@cloudbase/cli 2.10.0 → 2.11.0-beta.0

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 (205) hide show
  1. package/lib/auth/login.js +51 -65
  2. package/lib/auth/logout.js +3 -14
  3. package/lib/commands/account/login.js +136 -149
  4. package/lib/commands/account/logout.js +3 -14
  5. package/lib/commands/ag/base.js +203 -0
  6. package/lib/commands/ag/create.js +301 -0
  7. package/lib/commands/ag/debug/index.html +699 -0
  8. package/lib/commands/ag/delete.js +200 -0
  9. package/lib/commands/ag/deploy.js +185 -0
  10. package/lib/commands/ag/detail.js +113 -0
  11. package/lib/commands/ag/index.js +22 -0
  12. package/lib/commands/ag/list.js +155 -0
  13. package/lib/commands/ag/run.js +644 -0
  14. package/lib/commands/ai/index.js +76 -95
  15. package/lib/commands/cloudfunction/base.js +182 -203
  16. package/lib/commands/cloudrun/base.js +578 -603
  17. package/lib/commands/common.js +48 -63
  18. package/lib/commands/config/delete.js +16 -27
  19. package/lib/commands/config/get.js +13 -24
  20. package/lib/commands/config/list.js +16 -27
  21. package/lib/commands/config/set.js +33 -44
  22. package/lib/commands/db/base.js +221 -240
  23. package/lib/commands/env/base.js +36 -49
  24. package/lib/commands/env/domain.js +79 -94
  25. package/lib/commands/env/login.js +120 -135
  26. package/lib/commands/framework/index.js +32 -49
  27. package/lib/commands/fun/base.js +223 -244
  28. package/lib/commands/functions/alias/getRoute.js +33 -44
  29. package/lib/commands/functions/alias/setRoute.js +36 -47
  30. package/lib/commands/functions/code-download.js +43 -54
  31. package/lib/commands/functions/code-update.js +23 -34
  32. package/lib/commands/functions/concurrency/delete.js +11 -22
  33. package/lib/commands/functions/concurrency/list.js +20 -31
  34. package/lib/commands/functions/concurrency/set.js +13 -24
  35. package/lib/commands/functions/config-update.js +30 -41
  36. package/lib/commands/functions/copy.js +12 -23
  37. package/lib/commands/functions/delete.js +30 -41
  38. package/lib/commands/functions/deploy.js +184 -202
  39. package/lib/commands/functions/detail.js +23 -34
  40. package/lib/commands/functions/invoke.js +69 -75
  41. package/lib/commands/functions/layer/bind.js +102 -105
  42. package/lib/commands/functions/layer/create.js +29 -35
  43. package/lib/commands/functions/layer/delete.js +42 -48
  44. package/lib/commands/functions/layer/download.js +52 -58
  45. package/lib/commands/functions/layer/list.js +44 -50
  46. package/lib/commands/functions/layer/sort.js +39 -45
  47. package/lib/commands/functions/list.js +25 -36
  48. package/lib/commands/functions/log.js +65 -73
  49. package/lib/commands/functions/run.js +118 -116
  50. package/lib/commands/functions/trigger-create.js +32 -43
  51. package/lib/commands/functions/trigger-delete.js +50 -61
  52. package/lib/commands/functions/version/list.js +29 -40
  53. package/lib/commands/functions/version/publish.js +11 -22
  54. package/lib/commands/gateway/create.js +50 -61
  55. package/lib/commands/gateway/delete.js +38 -49
  56. package/lib/commands/gateway/domain.js +65 -80
  57. package/lib/commands/gateway/list.js +31 -42
  58. package/lib/commands/gateway/switch.js +48 -61
  59. package/lib/commands/helpers/init.js +226 -249
  60. package/lib/commands/helpers/new.js +35 -46
  61. package/lib/commands/helpers/open.js +22 -33
  62. package/lib/commands/hosting/hosting.js +157 -178
  63. package/lib/commands/index.js +1 -0
  64. package/lib/commands/lowcode/app.js +114 -144
  65. package/lib/commands/lowcode/comps.js +136 -127
  66. package/lib/commands/lowcode/utils.js +11 -22
  67. package/lib/commands/pull/pull.js +33 -46
  68. package/lib/commands/run/delete.js +35 -46
  69. package/lib/commands/run/image/delete.js +32 -39
  70. package/lib/commands/run/image/download.js +26 -33
  71. package/lib/commands/run/image/list.js +41 -48
  72. package/lib/commands/run/image/upload.js +26 -33
  73. package/lib/commands/run/list.js +32 -43
  74. package/lib/commands/run/service/config.js +17 -28
  75. package/lib/commands/run/service/deploy.js +15 -26
  76. package/lib/commands/run/service/list.js +48 -59
  77. package/lib/commands/run/service/update.js +7 -18
  78. package/lib/commands/run/standalonegateway/create.js +35 -42
  79. package/lib/commands/run/standalonegateway/destroy.js +23 -30
  80. package/lib/commands/run/standalonegateway/list.js +19 -26
  81. package/lib/commands/run/standalonegateway/package.js +31 -38
  82. package/lib/commands/run/standalonegateway/turn.js +27 -34
  83. package/lib/commands/run/version/create.js +198 -205
  84. package/lib/commands/run/version/delete.js +31 -38
  85. package/lib/commands/run/version/list.js +42 -49
  86. package/lib/commands/run/version/modify.js +27 -34
  87. package/lib/commands/run/version/update.js +201 -208
  88. package/lib/commands/runf/base.js +216 -237
  89. package/lib/commands/self-update.js +59 -72
  90. package/lib/commands/smart.js +66 -79
  91. package/lib/commands/storage/storage.js +192 -219
  92. package/lib/commands/third/thirdAttach.js +16 -27
  93. package/lib/commands/utils.js +119 -149
  94. package/lib/db/index.js +48 -67
  95. package/lib/decorators/captureError.js +10 -21
  96. package/lib/decorators/guard.js +11 -22
  97. package/lib/decorators/injectParams.js +29 -40
  98. package/lib/decorators/params/common.js +5 -2
  99. package/lib/decorators/params/index.js +3 -12
  100. package/lib/env/domain.js +13 -28
  101. package/lib/env/index.js +25 -44
  102. package/lib/env/login.js +30 -45
  103. package/lib/function/alias.js +31 -44
  104. package/lib/function/base.js +187 -215
  105. package/lib/function/code.js +8 -19
  106. package/lib/function/concurrency.js +43 -58
  107. package/lib/function/create.js +43 -53
  108. package/lib/function/delete.js +22 -35
  109. package/lib/function/layer/attach.js +33 -46
  110. package/lib/function/layer/create.js +34 -45
  111. package/lib/function/layer/delete.js +5 -16
  112. package/lib/function/layer/download.js +11 -22
  113. package/lib/function/layer/list.js +12 -25
  114. package/lib/function/layer/sort.js +6 -17
  115. package/lib/function/trigger.js +65 -82
  116. package/lib/function/update.js +24 -32
  117. package/lib/function/version.js +29 -42
  118. package/lib/function/vpc.js +12 -25
  119. package/lib/gateway/index.js +77 -104
  120. package/lib/hosting.js +157 -188
  121. package/lib/run/delete.js +3 -12
  122. package/lib/run/image/build.js +6 -15
  123. package/lib/run/image/delete.js +3 -12
  124. package/lib/run/image/info.js +3 -12
  125. package/lib/run/image/list.js +6 -15
  126. package/lib/run/list.js +19 -30
  127. package/lib/run/repo.js +6 -15
  128. package/lib/run/service/common.js +160 -173
  129. package/lib/run/service/config.js +44 -57
  130. package/lib/run/service/deployPackage.js +33 -44
  131. package/lib/run/service/list.js +8 -14
  132. package/lib/run/service/showLogs.js +69 -90
  133. package/lib/run/service/update.js +50 -63
  134. package/lib/run/standalonegateway/create.js +3 -12
  135. package/lib/run/standalonegateway/destroy.js +3 -12
  136. package/lib/run/standalonegateway/list.js +3 -12
  137. package/lib/run/standalonegateway/package/list.js +3 -12
  138. package/lib/run/standalonegateway/turn/off.js +3 -12
  139. package/lib/run/standalonegateway/turn/on.js +3 -12
  140. package/lib/run/version/create.js +41 -31
  141. package/lib/run/version/delete.js +3 -12
  142. package/lib/run/version/list.js +3 -12
  143. package/lib/run/version/modify.js +3 -12
  144. package/lib/run/version/repo.js +6 -15
  145. package/lib/run/version/update.js +37 -26
  146. package/lib/storage.js +62 -93
  147. package/lib/third/index.js +6 -17
  148. package/lib/utils/ai/banner.js +49 -60
  149. package/lib/utils/ai/claudeWindows.js +2 -2
  150. package/lib/utils/ai/config.js +169 -206
  151. package/lib/utils/ai/ensureFiles.js +6 -17
  152. package/lib/utils/ai/env.js +16 -27
  153. package/lib/utils/ai/envLocalManager.js +35 -52
  154. package/lib/utils/ai/router.js +927 -1005
  155. package/lib/utils/ai/setup.js +527 -563
  156. package/lib/utils/auth.js +3 -14
  157. package/lib/utils/checkTcbrEnv.js +20 -31
  158. package/lib/utils/cli-table.js +6 -1
  159. package/lib/utils/config.js +4 -13
  160. package/lib/utils/dts.js +98 -113
  161. package/lib/utils/env.js +154 -175
  162. package/lib/utils/function-packer.js +29 -42
  163. package/lib/utils/log.js +10 -21
  164. package/lib/utils/mcp-config-modifier.js +105 -120
  165. package/lib/utils/net/cloud-api-request.js +15 -23
  166. package/lib/utils/net/credential.js +26 -39
  167. package/lib/utils/net/http-request.js +63 -80
  168. package/lib/utils/net/manager-service.js +22 -35
  169. package/lib/utils/notice.js +16 -27
  170. package/lib/utils/output/loading.js +3 -12
  171. package/lib/utils/parallel.js +32 -43
  172. package/lib/utils/platform/mac.js +4 -15
  173. package/lib/utils/platform/port.js +4 -15
  174. package/lib/utils/prompt/select.js +6 -15
  175. package/lib/utils/report.js +28 -33
  176. package/lib/utils/reporter/agree.js +11 -22
  177. package/lib/utils/reporter/download.js +17 -28
  178. package/lib/utils/reporter/usage.js +12 -23
  179. package/lib/utils/store/auth.js +17 -30
  180. package/lib/utils/store/config.js +11 -25
  181. package/lib/utils/store/db.js +17 -36
  182. package/lib/utils/tcbrApi/callTcbrApi.js +19 -28
  183. package/lib/utils/template-manager.js +215 -242
  184. package/lib/utils/template.js +81 -96
  185. package/lib/utils/tools/common.js +45 -56
  186. package/lib/utils/tools/time.js +5 -16
  187. package/lib/utils/url.js +10 -4
  188. package/package.json +2 -2
  189. package/specs/ag-command/design.md +421 -0
  190. package/specs/ag-command/doc.md +204 -0
  191. package/specs/ag-command/requirements.md +173 -0
  192. package/specs/ag-command/summary.md +174 -0
  193. package/specs/ag-command/tasks.md +197 -0
  194. package/specs/ag-command/usage-guide.md +420 -0
  195. package/tsconfig.json +1 -1
  196. package/types/commands/ag/base.d.ts +44 -0
  197. package/types/commands/ag/create.d.ts +25 -0
  198. package/types/commands/ag/delete.d.ts +32 -0
  199. package/types/commands/ag/deploy.d.ts +31 -0
  200. package/types/commands/ag/detail.d.ts +28 -0
  201. package/types/commands/ag/index.d.ts +6 -0
  202. package/types/commands/ag/list.d.ts +35 -0
  203. package/types/commands/ag/run.d.ts +52 -0
  204. package/types/commands/cloudrun/base.d.ts +10 -0
  205. package/types/commands/index.d.ts +1 -0
@@ -0,0 +1,699 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Agent 调试面板</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ background: #f5f7fa;
17
+ height: 100vh;
18
+ display: flex;
19
+ flex-direction: column;
20
+ }
21
+
22
+ .header {
23
+ background: #fff;
24
+ padding: 1rem 2rem;
25
+ border-bottom: 1px solid #e1e8ed;
26
+ box-shadow: 0 2px 4px rgba(79, 65, 65, 0.1);
27
+ }
28
+
29
+ .header h1 {
30
+ color: #1a202c;
31
+ font-size: 1.5rem;
32
+ font-weight: 600;
33
+ }
34
+
35
+ .header .info {
36
+ color: #718096;
37
+ font-size: 0.875rem;
38
+ margin-top: 0.25rem;
39
+ }
40
+
41
+ .main {
42
+ flex: 1;
43
+ display: flex;
44
+ overflow: hidden;
45
+ }
46
+
47
+ .sidebar {
48
+ width: 600px;
49
+ background: #fff;
50
+ border-right: 1px solid #e1e8ed;
51
+ display: flex;
52
+ flex-direction: column;
53
+ }
54
+
55
+ .tabs {
56
+ display: flex;
57
+ border-bottom: 1px solid #e1e8ed;
58
+ }
59
+
60
+ .tab {
61
+ flex: 1;
62
+ padding: 0.75rem;
63
+ text-align: center;
64
+ background: #f7fafc;
65
+ border: none;
66
+ cursor: pointer;
67
+ font-size: 0.875rem;
68
+ font-weight: 500;
69
+ color: #4a5568;
70
+ transition: all 0.2s;
71
+ }
72
+
73
+ .tab.active {
74
+ background: #fff;
75
+ color: #3182ce;
76
+ border-bottom: 2px solid #3182ce;
77
+ }
78
+
79
+ .tab:hover {
80
+ background: #edf2f7;
81
+ }
82
+
83
+ .request-form {
84
+ padding: 1rem;
85
+ flex: 1;
86
+ overflow-y: auto;
87
+ }
88
+
89
+ .form-group {
90
+ margin-bottom: 1rem;
91
+ }
92
+
93
+ .form-group label {
94
+ display: block;
95
+ margin-bottom: 0.5rem;
96
+ font-weight: 500;
97
+ color: #2d3748;
98
+ font-size: 0.875rem;
99
+ }
100
+
101
+ .form-group input, .form-group select, .form-group textarea {
102
+ width: 100%;
103
+ padding: 0.5rem;
104
+ border: 1px solid #cbd5e0;
105
+ border-radius: 0.375rem;
106
+ font-size: 0.875rem;
107
+ transition: border-color 0.2s;
108
+ }
109
+
110
+ .form-group input:focus, .form-group select:focus, .form-group textarea:focus {
111
+ outline: none;
112
+ border-color: #3182ce;
113
+ box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1);
114
+ }
115
+
116
+ .url-input {
117
+ display: flex;
118
+ gap: 0.5rem;
119
+ }
120
+
121
+ .form-group .method-select {
122
+ width: 100px;
123
+ flex-shrink: 0;
124
+ }
125
+
126
+ .url-field {
127
+ flex: 1;
128
+ }
129
+
130
+ .send-btn {
131
+ width: 100%;
132
+ padding: 0.75rem;
133
+ background: #3182ce;
134
+ color: white;
135
+ border: none;
136
+ border-radius: 0.375rem;
137
+ font-weight: 500;
138
+ cursor: pointer;
139
+ transition: background-color 0.2s;
140
+ }
141
+
142
+ .send-btn:hover {
143
+ background: #2c5282;
144
+ }
145
+
146
+ .send-btn:disabled {
147
+ background: #a0aec0;
148
+ cursor: not-allowed;
149
+ }
150
+
151
+ .content {
152
+ flex: 1;
153
+ background: #fff;
154
+ display: flex;
155
+ flex-direction: column;
156
+ }
157
+
158
+ .response-header {
159
+ padding: 1rem;
160
+ border-bottom: 1px solid #e1e8ed;
161
+ background: #f7fafc;
162
+ }
163
+
164
+ .response-status {
165
+ font-weight: 600;
166
+ font-size: 1.125rem;
167
+ }
168
+
169
+ .response-status.success { color: #38a169; }
170
+ .response-status.error { color: #e53e3e; }
171
+
172
+ .response-body {
173
+ flex: 1;
174
+ padding: 1rem;
175
+ overflow-y: auto;
176
+ }
177
+
178
+ .response-content {
179
+ background: #f7fafc;
180
+ border: 1px solid #e1e8ed;
181
+ border-radius: 0.375rem;
182
+ padding: 1rem;
183
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
184
+ font-size: 0.875rem;
185
+ line-height: 1.5;
186
+ white-space: pre-wrap;
187
+ word-break: break-all;
188
+ }
189
+
190
+ .sse-messages {
191
+ max-height: 400px;
192
+ overflow-y: auto;
193
+ border: 1px solid #e1e8ed;
194
+ border-radius: 0.375rem;
195
+ }
196
+
197
+ .sse-message {
198
+ padding: 0.75rem;
199
+ border-bottom: 1px solid #e1e8ed;
200
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
201
+ font-size: 0.875rem;
202
+ }
203
+
204
+ .sse-message:last-child {
205
+ border-bottom: none;
206
+ }
207
+
208
+ .sse-message .timestamp {
209
+ color: #718096;
210
+ font-size: 0.75rem;
211
+ }
212
+
213
+ .sse-controls {
214
+ display: flex;
215
+ gap: 0.5rem;
216
+ margin-bottom: 1rem;
217
+ }
218
+
219
+ .sse-btn {
220
+ padding: 0.5rem 1rem;
221
+ border: 1px solid #cbd5e0;
222
+ border-radius: 0.375rem;
223
+ background: #fff;
224
+ cursor: pointer;
225
+ font-size: 0.875rem;
226
+ transition: all 0.2s;
227
+ }
228
+
229
+ .sse-btn:hover {
230
+ background: #f7fafc;
231
+ }
232
+
233
+ .sse-btn.active {
234
+ background: #3182ce;
235
+ color: white;
236
+ border-color: #3182ce;
237
+ }
238
+
239
+ .headers-section {
240
+ margin-bottom: 1rem;
241
+ }
242
+
243
+ .header-row {
244
+ display: flex;
245
+ gap: 0.5rem;
246
+ margin-bottom: 0.5rem;
247
+ }
248
+
249
+ .header-row input {
250
+ flex: 1;
251
+ }
252
+
253
+ .add-header-btn {
254
+ padding: 0.25rem 0.5rem;
255
+ background: #e2e8f0;
256
+ border: 1px solid #cbd5e0;
257
+ border-radius: 0.25rem;
258
+ cursor: pointer;
259
+ font-size: 0.75rem;
260
+ }
261
+
262
+ .loading {
263
+ display: inline-block;
264
+ width: 16px;
265
+ height: 16px;
266
+ border: 2px solid #e2e8f0;
267
+ border-top: 2px solid #3182ce;
268
+ border-radius: 50%;
269
+ animation: spin 1s linear infinite;
270
+ margin-right: 0.5rem;
271
+ }
272
+
273
+ @keyframes spin {
274
+ 0% { transform: rotate(0deg); }
275
+ 100% { transform: rotate(360deg); }
276
+ }
277
+ </style>
278
+ </head>
279
+ <body>
280
+ <div class="header">
281
+ <h1>Agent 调试面板</h1>
282
+ <div class="info">Agent ID: <span id="agentId">-</span> | 服务端口: <span id="agentPort">-</span></div>
283
+ </div>
284
+
285
+ <div class="main">
286
+ <div class="sidebar">
287
+ <div class="tabs">
288
+ <button class="tab active" data-tab="http">HTTP</button>
289
+ <button class="tab" data-tab="sse">SSE</button>
290
+ </div>
291
+
292
+ <!-- HTTP Tab -->
293
+ <div class="request-form" id="http-tab">
294
+ <div class="form-group">
295
+ <label>请求地址</label>
296
+ <div class="url-input">
297
+ <select class="method-select" id="http-method">
298
+ <option value="GET">GET</option>
299
+ <option value="POST" selected>POST</option>
300
+ <option value="PUT">PUT</option>
301
+ <option value="DELETE">DELETE</option>
302
+ <option value="PATCH">PATCH</option>
303
+ </select>
304
+ <input type="text" class="url-field" id="http-url" placeholder="http://127.0.0.1:3000/api/endpoint">
305
+ </div>
306
+ </div>
307
+
308
+ <div class="form-group">
309
+ <label>请求头</label>
310
+ <div class="headers-section" id="http-headers">
311
+ <div class="header-row">
312
+ <input type="text" placeholder="Content-Type" value="Content-Type">
313
+ <input type="text" placeholder="application/json" value="application/json">
314
+ </div>
315
+ </div>
316
+ <button class="add-header-btn" onclick="addHeader('http')">+ 添加请求头</button>
317
+ </div>
318
+
319
+ <div class="form-group">
320
+ <label>请求体</label>
321
+ <textarea id="http-body" rows="8" placeholder='{"message": "Hello Agent"}'>{
322
+ "stream": false,
323
+ "message": "Hello"
324
+ }</textarea>
325
+ </div>
326
+
327
+ <button class="send-btn" onclick="sendHttpRequest()">
328
+ <span id="http-loading" class="loading" style="display: none;"></span>
329
+ 发送请求
330
+ </button>
331
+ </div>
332
+
333
+ <!-- SSE Tab -->
334
+ <div class="request-form" id="sse-tab" style="display: none;">
335
+ <div class="form-group">
336
+ <label>请求地址</label>
337
+ <div class="url-input">
338
+ <select class="method-select" id="sse-method">
339
+ <option value="GET">GET</option>
340
+ <option value="POST" selected>POST</option>
341
+ <option value="PUT">PUT</option>
342
+ <option value="DELETE">DELETE</option>
343
+ <option value="PATCH">PATCH</option>
344
+ </select>
345
+ <input type="text" class="url-field" id="sse-url" placeholder="http://127.0.0.1:3000/api/stream">
346
+ </div>
347
+ </div>
348
+
349
+ <div class="form-group">
350
+ <label>请求头</label>
351
+ <div class="headers-section" id="sse-headers">
352
+ <div class="header-row">
353
+ <input type="text" placeholder="Accept" value="Accept">
354
+ <input type="text" placeholder="text/event-stream" value="text/event-stream">
355
+ </div>
356
+ <div class="header-row">
357
+ <input type="text" placeholder="Content-Type" value="Content-Type">
358
+ <input type="text" placeholder="application/json" value="application/json">
359
+ </div>
360
+ </div>
361
+ <button class="add-header-btn" onclick="addHeader('sse')">+ 添加请求头</button>
362
+ </div>
363
+
364
+ <div class="form-group">
365
+ <label>请求体</label>
366
+ <textarea id="sse-body" rows="6" placeholder='{"message": "Hello Agent"}'>{
367
+ "stream": true,
368
+ "message": "Hello"
369
+ }</textarea>
370
+ </div>
371
+
372
+ <div class="sse-controls">
373
+ <button class="sse-btn" id="sse-connect-btn" onclick="connectSSE()">连接</button>
374
+ <button class="sse-btn" id="sse-disconnect-btn" onclick="disconnectSSE()" disabled>断开</button>
375
+ <button class="sse-btn" onclick="clearSSEMessages()">清空消息</button>
376
+ </div>
377
+ </div>
378
+ </div>
379
+
380
+ <div class="content">
381
+ <!-- HTTP Response -->
382
+ <div id="http-response" class="response-content-wrapper">
383
+ <div class="response-header">
384
+ <div class="response-status" id="http-status">准备发送请求</div>
385
+ </div>
386
+ <div class="response-body">
387
+ <div class="response-content" id="http-response-body">在左侧配置请求参数,然后点击"发送请求"按钮</div>
388
+ </div>
389
+ </div>
390
+
391
+ <!-- SSE Response -->
392
+ <div id="sse-response" class="response-content-wrapper" style="display: none;">
393
+ <div class="response-header">
394
+ <div class="response-status" id="sse-status">准备连接 SSE</div>
395
+ </div>
396
+ <div class="response-body">
397
+ <div class="sse-messages" id="sse-messages"></div>
398
+ </div>
399
+ </div>
400
+ </div>
401
+ </div>
402
+
403
+ <script>
404
+ let currentTab = 'http';
405
+ let sseConnection = null;
406
+
407
+ // 获取 URL 参数
408
+ const urlParams = new URLSearchParams(window.location.search);
409
+ const agentId = urlParams.get('agentId') || 'unknown';
410
+ const agentPort = urlParams.get('agentPort') || '3000';
411
+
412
+ document.getElementById('agentId').textContent = agentId;
413
+ document.getElementById('agentPort').textContent = agentPort;
414
+
415
+ // 设置默认 URL
416
+ document.getElementById('http-url').value = `http://127.0.0.1:${agentPort}/send-message`;
417
+ document.getElementById('sse-url').value = `http://127.0.0.1:${agentPort}/send-message`;
418
+
419
+ // Tab 切换
420
+ document.querySelectorAll('.tab').forEach(tab => {
421
+ tab.addEventListener('click', () => {
422
+ const tabName = tab.dataset.tab;
423
+ switchTab(tabName);
424
+ });
425
+ });
426
+
427
+ function switchTab(tabName) {
428
+ currentTab = tabName;
429
+
430
+ // 更新 tab 样式
431
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
432
+ document.querySelector(`[data-tab="${tabName}"]`).classList.add('active');
433
+
434
+ // 显示对应内容
435
+ document.getElementById('http-tab').style.display = tabName === 'http' ? 'block' : 'none';
436
+ document.getElementById('sse-tab').style.display = tabName === 'sse' ? 'block' : 'none';
437
+ document.getElementById('http-response').style.display = tabName === 'http' ? 'block' : 'none';
438
+ document.getElementById('sse-response').style.display = tabName === 'sse' ? 'block' : 'none';
439
+ }
440
+
441
+ // 添加请求头
442
+ function addHeader(type) {
443
+ const container = document.getElementById(`${type}-headers`);
444
+ const row = document.createElement('div');
445
+ row.className = 'header-row';
446
+ row.innerHTML = `
447
+ <input type="text" placeholder="Header Name">
448
+ <input type="text" placeholder="Header Value">
449
+ `;
450
+ container.appendChild(row);
451
+ }
452
+
453
+ // 获取请求头
454
+ function getHeaders(type) {
455
+ const headers = {};
456
+ const rows = document.querySelectorAll(`#${type}-headers .header-row`);
457
+ rows.forEach(row => {
458
+ const inputs = row.querySelectorAll('input');
459
+ const key = inputs[0].value.trim();
460
+ const value = inputs[1].value.trim();
461
+ if (key && value) {
462
+ headers[key] = value;
463
+ }
464
+ });
465
+ return headers;
466
+ }
467
+
468
+ // 发送 HTTP 请求
469
+ async function sendHttpRequest() {
470
+ const method = document.getElementById('http-method').value;
471
+ const url = document.getElementById('http-url').value;
472
+ const body = document.getElementById('http-body').value;
473
+ const headers = getHeaders('http');
474
+
475
+ if (!url) {
476
+ alert('请输入请求地址');
477
+ return;
478
+ }
479
+
480
+ const loadingEl = document.getElementById('http-loading');
481
+ const statusEl = document.getElementById('http-status');
482
+ const responseEl = document.getElementById('http-response-body');
483
+
484
+ loadingEl.style.display = 'inline-block';
485
+ statusEl.textContent = '发送中...';
486
+ statusEl.className = 'response-status';
487
+
488
+ try {
489
+ const requestOptions = {
490
+ method,
491
+ headers
492
+ };
493
+
494
+ if (method !== 'GET' && body) {
495
+ requestOptions.body = body;
496
+ }
497
+
498
+ const response = await fetch(url, requestOptions);
499
+ const responseText = await response.text();
500
+
501
+ // 更新状态
502
+ statusEl.textContent = `${response.status} ${response.statusText}`;
503
+ statusEl.className = `response-status ${response.ok ? 'success' : 'error'}`;
504
+
505
+ // 格式化响应
506
+ let formattedResponse = responseText;
507
+ try {
508
+ const jsonData = JSON.parse(responseText);
509
+ formattedResponse = JSON.stringify(jsonData, null, 2);
510
+ } catch (e) {
511
+ // 不是 JSON,保持原样
512
+ }
513
+
514
+ responseEl.textContent = formattedResponse;
515
+
516
+ } catch (error) {
517
+ statusEl.textContent = `请求失败: ${error.message}`;
518
+ statusEl.className = 'response-status error';
519
+ responseEl.textContent = error.message;
520
+ } finally {
521
+ loadingEl.style.display = 'none';
522
+ }
523
+ }
524
+
525
+ // SSE 连接
526
+ function connectSSE() {
527
+ const method = document.getElementById('sse-method').value;
528
+ const url = document.getElementById('sse-url').value;
529
+ const body = document.getElementById('sse-body').value;
530
+ const headers = getHeaders('sse');
531
+
532
+ if (!url) {
533
+ alert('请输入 SSE 地址');
534
+ return;
535
+ }
536
+
537
+ const statusEl = document.getElementById('sse-status');
538
+ const messagesEl = document.getElementById('sse-messages');
539
+ const connectBtn = document.getElementById('sse-connect-btn');
540
+ const disconnectBtn = document.getElementById('sse-disconnect-btn');
541
+
542
+ try {
543
+ // 对于 POST 等需要请求体的方法,使用 fetch + ReadableStream
544
+ if (method !== 'GET') {
545
+ connectSSEWithFetch(method, url, headers, body, statusEl, connectBtn, disconnectBtn);
546
+ } else {
547
+ // GET 方法使用传统的 EventSource
548
+ sseConnection = new EventSource(url);
549
+ setupSSEEventHandlers(sseConnection, statusEl, connectBtn, disconnectBtn);
550
+ }
551
+
552
+ } catch (error) {
553
+ statusEl.textContent = `连接失败: ${error.message}`;
554
+ statusEl.className = 'response-status error';
555
+ }
556
+ }
557
+
558
+ // 使用 fetch 实现 POST SSE 连接
559
+ async function connectSSEWithFetch(method, url, headers, body, statusEl, connectBtn, disconnectBtn) {
560
+ try {
561
+ const requestOptions = {
562
+ method,
563
+ headers: {
564
+ ...headers,
565
+ 'Accept': 'text/event-stream',
566
+ 'Cache-Control': 'no-cache'
567
+ }
568
+ };
569
+
570
+ if (method !== 'GET' && body) {
571
+ requestOptions.body = body;
572
+ }
573
+
574
+ const response = await fetch(url, requestOptions);
575
+
576
+ if (!response.ok) {
577
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
578
+ }
579
+
580
+ statusEl.textContent = '已连接';
581
+ statusEl.className = 'response-status success';
582
+ connectBtn.disabled = true;
583
+ disconnectBtn.disabled = false;
584
+ addSSEMessage('系统', `连接已建立 (${method})`);
585
+
586
+ // 创建一个可以手动控制的连接对象
587
+ sseConnection = {
588
+ close: () => {
589
+ if (response.body) {
590
+ response.body.cancel();
591
+ }
592
+ }
593
+ };
594
+
595
+ // 读取流式响应
596
+ const reader = response.body.getReader();
597
+ const decoder = new TextDecoder();
598
+ let buffer = '';
599
+
600
+ while (true) {
601
+ const { done, value } = await reader.read();
602
+ if (done) break;
603
+
604
+ buffer += decoder.decode(value, { stream: true });
605
+ const lines = buffer.split('\n');
606
+ buffer = lines.pop(); // 保留最后一个可能不完整的行
607
+
608
+ for (const line of lines) {
609
+ if (line.startsWith('data: ')) {
610
+ const data = line.slice(6); // 移除 'data: ' 前缀
611
+ if (data.trim()) {
612
+ addSSEMessage('数据', data);
613
+ }
614
+ } else if (line.trim() === '') {
615
+ // 空行表示事件结束
616
+ }
617
+ }
618
+ }
619
+
620
+ } catch (error) {
621
+ statusEl.textContent = `连接失败: ${error.message}`;
622
+ statusEl.className = 'response-status error';
623
+ addSSEMessage('错误', error.message);
624
+ connectBtn.disabled = false;
625
+ disconnectBtn.disabled = true;
626
+ }
627
+ }
628
+
629
+ // 设置 EventSource 事件处理器
630
+ function setupSSEEventHandlers(eventSource, statusEl, connectBtn, disconnectBtn) {
631
+ eventSource.onopen = () => {
632
+ statusEl.textContent = '已连接';
633
+ statusEl.className = 'response-status success';
634
+ connectBtn.disabled = true;
635
+ disconnectBtn.disabled = false;
636
+ addSSEMessage('系统', '连接已建立 (GET)');
637
+ };
638
+
639
+ eventSource.onmessage = (event) => {
640
+ addSSEMessage('数据', event.data);
641
+ };
642
+
643
+ eventSource.onerror = (error) => {
644
+ statusEl.textContent = '连接错误';
645
+ statusEl.className = 'response-status error';
646
+ addSSEMessage('错误', '连接发生错误');
647
+ };
648
+ }
649
+
650
+ // 断开 SSE
651
+ function disconnectSSE() {
652
+ if (sseConnection) {
653
+ sseConnection.close();
654
+ sseConnection = null;
655
+
656
+ const statusEl = document.getElementById('sse-status');
657
+ const connectBtn = document.getElementById('sse-connect-btn');
658
+ const disconnectBtn = document.getElementById('sse-disconnect-btn');
659
+
660
+ statusEl.textContent = '已断开';
661
+ statusEl.className = 'response-status';
662
+ connectBtn.disabled = false;
663
+ disconnectBtn.disabled = true;
664
+ addSSEMessage('系统', '连接已断开');
665
+ }
666
+ }
667
+
668
+ // 添加 SSE 消息
669
+ function addSSEMessage(type, data) {
670
+ const messagesEl = document.getElementById('sse-messages');
671
+ const messageEl = document.createElement('div');
672
+ messageEl.className = 'sse-message';
673
+
674
+ const timestamp = new Date().toLocaleTimeString();
675
+ messageEl.innerHTML = `
676
+ <div class="timestamp">[${timestamp}] ${type}</div>
677
+ <div>${data}</div>
678
+ `;
679
+
680
+ messagesEl.appendChild(messageEl);
681
+ messagesEl.scrollTop = messagesEl.scrollHeight;
682
+ }
683
+
684
+ // 清空 SSE 消息
685
+ function clearSSEMessages() {
686
+ document.getElementById('sse-messages').innerHTML = '';
687
+ }
688
+
689
+ // 快捷键支持
690
+ document.addEventListener('keydown', (e) => {
691
+ if (e.ctrlKey && e.key === 'Enter') {
692
+ if (currentTab === 'http') {
693
+ sendHttpRequest();
694
+ }
695
+ }
696
+ });
697
+ </script>
698
+ </body>
699
+ </html>