@comate/zulu 0.7.1 → 0.7.3

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 (155) hide show
  1. package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.d.ts +1 -0
  2. package/comate-engine/server.js +3 -3
  3. package/dist/bundle/index.js +2 -2
  4. package/package.json +1 -1
  5. package/comate-engine/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
  6. package/comate-engine/plugins/aiscan/assets/icon.svg +0 -12
  7. package/comate-engine/plugins/aiscan/dist/index.js +0 -54426
  8. package/comate-engine/plugins/aiscan/package.json +0 -67
  9. package/comate-engine/plugins/appdev/assets/icon.png +0 -0
  10. package/comate-engine/plugins/appdev/dist/help.md +0 -12
  11. package/comate-engine/plugins/appdev/dist/index.d.ts +0 -2
  12. package/comate-engine/plugins/appdev/dist/index.js +0 -194
  13. package/comate-engine/plugins/appdev/dist/providers/err.d.ts +0 -8
  14. package/comate-engine/plugins/appdev/dist/providers/err.js +0 -37
  15. package/comate-engine/plugins/appdev/dist/providers/fallback.d.ts +0 -5
  16. package/comate-engine/plugins/appdev/dist/providers/fallback.js +0 -28
  17. package/comate-engine/plugins/appdev/dist/providers/help.d.ts +0 -8
  18. package/comate-engine/plugins/appdev/dist/providers/help.js +0 -19
  19. package/comate-engine/plugins/appdev/dist/providers/medusa.d.ts +0 -8
  20. package/comate-engine/plugins/appdev/dist/providers/medusa.js +0 -39
  21. package/comate-engine/plugins/appdev/dist/providers/qa.d.ts +0 -8
  22. package/comate-engine/plugins/appdev/dist/providers/qa.js +0 -33
  23. package/comate-engine/plugins/appdev/package.json +0 -67
  24. package/comate-engine/plugins/bfc/assets/bfc-icon.png +0 -0
  25. package/comate-engine/plugins/bfc/dist/config/config.d.ts +0 -4
  26. package/comate-engine/plugins/bfc/dist/config/config.js +0 -4
  27. package/comate-engine/plugins/bfc/dist/help.md +0 -11
  28. package/comate-engine/plugins/bfc/dist/index.d.ts +0 -2
  29. package/comate-engine/plugins/bfc/dist/index.js +0 -452
  30. package/comate-engine/plugins/bfc/dist/providers/bfcInstructMode.d.ts +0 -8
  31. package/comate-engine/plugins/bfc/dist/providers/bfcInstructMode.js +0 -77
  32. package/comate-engine/plugins/bfc/dist/providers/genAbnormalCode.d.ts +0 -8
  33. package/comate-engine/plugins/bfc/dist/providers/genAbnormalCode.js +0 -71
  34. package/comate-engine/plugins/bfc/dist/providers/genBfcCode.d.ts +0 -8
  35. package/comate-engine/plugins/bfc/dist/providers/genBfcCode.js +0 -74
  36. package/comate-engine/plugins/bfc/dist/providers/getBatchCases.d.ts +0 -10
  37. package/comate-engine/plugins/bfc/dist/providers/getBatchCases.js +0 -71
  38. package/comate-engine/plugins/bfc/dist/providers/help.d.ts +0 -8
  39. package/comate-engine/plugins/bfc/dist/providers/help.js +0 -19
  40. package/comate-engine/plugins/bfc/dist/service/generateService.d.ts +0 -14
  41. package/comate-engine/plugins/bfc/dist/service/generateService.js +0 -27
  42. package/comate-engine/plugins/bfc/package.json +0 -85
  43. package/comate-engine/plugins/bpm/assets/bpm.png +0 -0
  44. package/comate-engine/plugins/bpm/dist/index.js +0 -313
  45. package/comate-engine/plugins/bpm/package.json +0 -65
  46. package/comate-engine/plugins/casebuilder/assets/icon.svg +0 -1
  47. package/comate-engine/plugins/casebuilder/dist/help.md +0 -33
  48. package/comate-engine/plugins/casebuilder/dist/index.js +0 -837
  49. package/comate-engine/plugins/casebuilder/package.json +0 -80
  50. package/comate-engine/plugins/centrino/assets/icon.png +0 -0
  51. package/comate-engine/plugins/centrino/dist/help.md +0 -30
  52. package/comate-engine/plugins/centrino/dist/index.js +0 -1046
  53. package/comate-engine/plugins/centrino/package.json +0 -68
  54. package/comate-engine/plugins/cnap/assets/cnap.png +0 -0
  55. package/comate-engine/plugins/cnap/dist/help.md +0 -11
  56. package/comate-engine/plugins/cnap/dist/index.js +0 -171
  57. package/comate-engine/plugins/cnap/package.json +0 -65
  58. package/comate-engine/plugins/demo-timer/assets/icon.svg +0 -2
  59. package/comate-engine/plugins/demo-timer/dist/index.js +0 -463
  60. package/comate-engine/plugins/demo-timer/package.json +0 -73
  61. package/comate-engine/plugins/dev-tools/assets/icon.png +0 -0
  62. package/comate-engine/plugins/dev-tools/dist/help.md +0 -18
  63. package/comate-engine/plugins/dev-tools/dist/index.js +0 -166160
  64. package/comate-engine/plugins/dev-tools/package.json +0 -95
  65. package/comate-engine/plugins/devaux/assets/icon.svg +0 -1
  66. package/comate-engine/plugins/devaux/dist/help.md +0 -41
  67. package/comate-engine/plugins/devaux/dist/index.js +0 -75551
  68. package/comate-engine/plugins/devaux/dist/static/tree-sitter-cpp.wasm +0 -0
  69. package/comate-engine/plugins/devaux/dist/static/tree-sitter-go.wasm +0 -0
  70. package/comate-engine/plugins/devaux/dist/static/tree-sitter.wasm +0 -0
  71. package/comate-engine/plugins/devaux/dist/tree-sitter.wasm +0 -0
  72. package/comate-engine/plugins/devaux/package.json +0 -82
  73. package/comate-engine/plugins/f2c/assets/icon.svg +0 -11
  74. package/comate-engine/plugins/f2c/dist/help.md +0 -13
  75. package/comate-engine/plugins/f2c/dist/index.js +0 -101649
  76. package/comate-engine/plugins/f2c/package.json +0 -56
  77. package/comate-engine/plugins/fcnap/assets/icon.png +0 -0
  78. package/comate-engine/plugins/fcnap/dist/help.md +0 -9
  79. package/comate-engine/plugins/fcnap/dist/index.js +0 -105
  80. package/comate-engine/plugins/fcnap/package.json +0 -50
  81. package/comate-engine/plugins/front-end-skills/assets/icon.svg +0 -1
  82. package/comate-engine/plugins/front-end-skills/dist/help.md +0 -17
  83. package/comate-engine/plugins/front-end-skills/dist/index.js +0 -8172
  84. package/comate-engine/plugins/front-end-skills/package.json +0 -79
  85. package/comate-engine/plugins/gdp/assets/icon.png +0 -0
  86. package/comate-engine/plugins/gdp/dist/help.md +0 -11
  87. package/comate-engine/plugins/gdp/dist/index.js +0 -70806
  88. package/comate-engine/plugins/gdp/package.json +0 -80
  89. package/comate-engine/plugins/git/assets/git.svg +0 -1
  90. package/comate-engine/plugins/git/assets/icon.svg +0 -1
  91. package/comate-engine/plugins/git/dist/help.md +0 -7
  92. package/comate-engine/plugins/git/dist/index.js +0 -32765
  93. package/comate-engine/plugins/git/package.json +0 -91
  94. package/comate-engine/plugins/harmonyos/assets/harmonyos.png +0 -0
  95. package/comate-engine/plugins/harmonyos/dist/index.js +0 -78
  96. package/comate-engine/plugins/harmonyos/package.json +0 -37
  97. package/comate-engine/plugins/iapi/assets/icon.png +0 -0
  98. package/comate-engine/plugins/iapi/dist/help.md +0 -13
  99. package/comate-engine/plugins/iapi/dist/index.js +0 -458
  100. package/comate-engine/plugins/iapi/dist/static/lang/tree-sitter-go.wasm +0 -0
  101. package/comate-engine/plugins/iapi/dist/static/lang/tree-sitter-java.wasm +0 -0
  102. package/comate-engine/plugins/iapi/dist/static/tree-sitter-go.wasm +0 -0
  103. package/comate-engine/plugins/iapi/dist/static/tree-sitter-java.wasm +0 -0
  104. package/comate-engine/plugins/iapi/dist/tree-sitter.wasm +0 -0
  105. package/comate-engine/plugins/iapi/package.json +0 -102
  106. package/comate-engine/plugins/icafe/assets/icafe.svg +0 -1
  107. package/comate-engine/plugins/icafe/dist/help.md +0 -5
  108. package/comate-engine/plugins/icafe/dist/index.js +0 -885
  109. package/comate-engine/plugins/icafe/package.json +0 -74
  110. package/comate-engine/plugins/ievalue/assets/iEValue.svg +0 -10
  111. package/comate-engine/plugins/ievalue/dist/index.js +0 -2920
  112. package/comate-engine/plugins/ievalue/package.json +0 -88
  113. package/comate-engine/plugins/ipipe/assets/iPipePlugin.png +0 -0
  114. package/comate-engine/plugins/ipipe/dist/help.md +0 -15
  115. package/comate-engine/plugins/ipipe/dist/index.js +0 -7268
  116. package/comate-engine/plugins/ipipe/package.json +0 -62
  117. package/comate-engine/plugins/jarvis/assets/icon.svg +0 -1
  118. package/comate-engine/plugins/jarvis/dist/help.md +0 -17
  119. package/comate-engine/plugins/jarvis/dist/index.js +0 -140473
  120. package/comate-engine/plugins/jarvis/package.json +0 -93
  121. package/comate-engine/plugins/mapsearch/assets/mapsearchicon.png +0 -0
  122. package/comate-engine/plugins/mapsearch/dist/help.md +0 -4
  123. package/comate-engine/plugins/mapsearch/dist/index.js +0 -145
  124. package/comate-engine/plugins/mapsearch/package.json +0 -53
  125. package/comate-engine/plugins/paddle/assets/icon.png +0 -0
  126. package/comate-engine/plugins/paddle/assets/paconvert-3.0.1-py3-none-any.whl +0 -0
  127. package/comate-engine/plugins/paddle/dist/help.md +0 -31
  128. package/comate-engine/plugins/paddle/dist/index.js +0 -1011
  129. package/comate-engine/plugins/paddle/package.json +0 -129
  130. package/comate-engine/plugins/robot/assets/Robot.png +0 -0
  131. package/comate-engine/plugins/robot/dist/index.js +0 -476
  132. package/comate-engine/plugins/robot/package.json +0 -91
  133. package/comate-engine/plugins/security/assets/comate.png +0 -0
  134. package/comate-engine/plugins/security/dist/index.js +0 -18434
  135. package/comate-engine/plugins/security/package.json +0 -82
  136. package/comate-engine/plugins/smartapp/assets/icon.png +0 -0
  137. package/comate-engine/plugins/smartapp/dist/help.md +0 -4
  138. package/comate-engine/plugins/smartapp/dist/index.js +0 -113
  139. package/comate-engine/plugins/smartapp/package.json +0 -54
  140. package/comate-engine/plugins/testmate/assets/icon.svg +0 -1
  141. package/comate-engine/plugins/testmate/dist/help.md +0 -62
  142. package/comate-engine/plugins/testmate/dist/index.js +0 -21483
  143. package/comate-engine/plugins/testmate/package.json +0 -85
  144. package/comate-engine/plugins/tor/assets/TorPlugin.png +0 -0
  145. package/comate-engine/plugins/tor/dist/help.md +0 -22
  146. package/comate-engine/plugins/tor/dist/index.js +0 -807
  147. package/comate-engine/plugins/tor/package.json +0 -99
  148. package/comate-engine/plugins/weiyun/assets/icon.png +0 -0
  149. package/comate-engine/plugins/weiyun/dist/help.md +0 -11
  150. package/comate-engine/plugins/weiyun/dist/index.js +0 -100495
  151. package/comate-engine/plugins/weiyun/package.json +0 -55
  152. package/comate-engine/plugins/workcard/assets/favicon.png +0 -0
  153. package/comate-engine/plugins/workcard/dist/help.md +0 -30
  154. package/comate-engine/plugins/workcard/dist/index.js +0 -547
  155. package/comate-engine/plugins/workcard/package.json +0 -102
@@ -1,837 +0,0 @@
1
- import { SkillProvider, StringChunkStream } from '@comate/plugin-host';
2
- import { readFileSync } from 'fs';
3
- import { fileURLToPath } from 'node:url';
4
- import path, { dirname } from 'path';
5
-
6
- class HelpSkillProvider extends SkillProvider {
7
- static{
8
- this.skillName = 'help';
9
- }
10
- static{
11
- this.description = '插件介绍';
12
- }
13
- static{
14
- this.parameters = {
15
- type: 'object',
16
- properties: {}
17
- };
18
- }
19
- async *execute() {
20
- const stream = new StringChunkStream();
21
- try {
22
- const filename = fileURLToPath(import.meta.url);
23
- const content = readFileSync(`${dirname(filename)}/help.md`, 'utf8');
24
- yield stream.flush(content);
25
- } catch (error) {
26
- this.logger.error(`Plugin Error: ${error}`);
27
- yield stream.flushReplaceLast(`抱歉\n\n插件发生出错,${error}。`);
28
- }
29
- }
30
- }
31
-
32
- const API_SERVER_HOST = 'http://10.169.27.242:8089/comate';
33
- // export const API_SERVER_HOST = 'http://localhost:8080/comate';
34
- const WEB_LINK = 'https://casebuilder.n.baidu-int.com';
35
- const MAX_DEMO_CONTENT_LENGTH = 5000;
36
-
37
- function createParser(onParse) {
38
- let isFirstChunk, buffer, startingPosition, startingFieldLength, eventId, eventName, data;
39
- return reset(), { feed, reset };
40
- function reset() {
41
- isFirstChunk = !0, buffer = "", startingPosition = 0, startingFieldLength = -1, eventId = void 0, eventName = void 0, data = "";
42
- }
43
- function feed(chunk) {
44
- buffer = buffer ? buffer + chunk : chunk, isFirstChunk && hasBom(buffer) && (buffer = buffer.slice(BOM.length)), isFirstChunk = !1;
45
- const length = buffer.length;
46
- let position = 0, discardTrailingNewline = !1;
47
- for (; position < length; ) {
48
- discardTrailingNewline && (buffer[position] === `
49
- ` && ++position, discardTrailingNewline = !1);
50
- let lineLength = -1, fieldLength = startingFieldLength, character;
51
- for (let index = startingPosition; lineLength < 0 && index < length; ++index)
52
- character = buffer[index], character === ":" && fieldLength < 0 ? fieldLength = index - position : character === "\r" ? (discardTrailingNewline = !0, lineLength = index - position) : character === `
53
- ` && (lineLength = index - position);
54
- if (lineLength < 0) {
55
- startingPosition = length - position, startingFieldLength = fieldLength;
56
- break;
57
- } else
58
- startingPosition = 0, startingFieldLength = -1;
59
- parseEventStreamLine(buffer, position, fieldLength, lineLength), position += lineLength + 1;
60
- }
61
- position === length ? buffer = "" : position > 0 && (buffer = buffer.slice(position));
62
- }
63
- function parseEventStreamLine(lineBuffer, index, fieldLength, lineLength) {
64
- if (lineLength === 0) {
65
- data.length > 0 && (onParse({
66
- type: "event",
67
- id: eventId,
68
- event: eventName || void 0,
69
- data: data.slice(0, -1)
70
- // remove trailing newline
71
- }), data = "", eventId = void 0), eventName = void 0;
72
- return;
73
- }
74
- const noValue = fieldLength < 0, field = lineBuffer.slice(index, index + (noValue ? lineLength : fieldLength));
75
- let step = 0;
76
- noValue ? step = lineLength : lineBuffer[index + fieldLength + 1] === " " ? step = fieldLength + 2 : step = fieldLength + 1;
77
- const position = index + step, valueLength = lineLength - step, value = lineBuffer.slice(position, position + valueLength).toString();
78
- if (field === "data")
79
- data += value ? `${value}
80
- ` : `
81
- `;
82
- else if (field === "event")
83
- eventName = value;
84
- else if (field === "id" && !value.includes("\0"))
85
- eventId = value;
86
- else if (field === "retry") {
87
- const retry = parseInt(value, 10);
88
- Number.isNaN(retry) || onParse({ type: "reconnect-interval", value: retry });
89
- }
90
- }
91
- }
92
- const BOM = [239, 187, 191];
93
- function hasBom(buffer) {
94
- return BOM.every((charCode, index) => buffer.charCodeAt(index) === charCode);
95
- }
96
-
97
- class EventSourceParserStream extends TransformStream {
98
- constructor() {
99
- let parser;
100
- super({
101
- start(controller) {
102
- parser = createParser((event) => {
103
- event.type === "event" && controller.enqueue(event);
104
- });
105
- },
106
- transform(chunk) {
107
- parser.feed(chunk);
108
- }
109
- });
110
- }
111
- }
112
-
113
- const apiRequest = async (method, path, options = {}, timeout = 5000)=>{
114
- try {
115
- const response = await fetch(`${API_SERVER_HOST}${path}`, {
116
- method,
117
- ...options,
118
- signal: AbortSignal.timeout(timeout)
119
- });
120
- if (!response.ok) {
121
- throw new Error(`[${response.status}] 请求错误。请求参数:${JSON.stringify({
122
- method,
123
- path,
124
- ...options
125
- })}`);
126
- }
127
- const jsonRes = response.json();
128
- return jsonRes.then((res)=>{
129
- if (res.code !== 'OK') {
130
- throw new Error(`[${res.code}] ${res.message}`);
131
- } else {
132
- return res.data;
133
- }
134
- });
135
- } catch (err) {
136
- throw err;
137
- }
138
- };
139
- async function* sseRequest(method, path, options = {}) {
140
- try {
141
- const response = await fetch(`${API_SERVER_HOST}${path}`, {
142
- method,
143
- headers: {
144
- 'Content-Type': 'application/json'
145
- },
146
- ...options
147
- });
148
- if (!response.ok) {
149
- throw new Error(`[${response.status}] 请求错误。请求参数:${JSON.stringify({
150
- method,
151
- path,
152
- ...options
153
- })}`);
154
- }
155
- if (!response.body) {
156
- throw new Error(`[${response.status}] 响应体错误。请求参数:${JSON.stringify({
157
- method,
158
- path,
159
- ...options
160
- })}`);
161
- }
162
- // 兼容非流式返回的处理逻辑
163
- const contentType = response.headers.get('Content-Type');
164
- if (contentType?.indexOf('application/json') !== -1) {
165
- const jsonRes = response.json();
166
- yield jsonRes.then((res)=>{
167
- if (res.code !== 'OK') {
168
- throw new Error(`[${res.code}] ${res.message}`);
169
- } else {
170
- return res.data;
171
- }
172
- });
173
- }
174
- const resBody = await response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream());
175
- const reader = resBody.getReader();
176
- try {
177
- while(true){
178
- const { value, done } = await reader.read();
179
- if (done) {
180
- break;
181
- }
182
- const { event, data } = value;
183
- if (event && [
184
- 'FatalError',
185
- 'BadRequest'
186
- ].includes(event)) {
187
- throw new Error(data);
188
- }
189
- if (event !== 'Msg' || !data.length) {
190
- continue;
191
- }
192
- yield data.replaceAll('\\x0A', '\n');
193
- }
194
- } catch (e) {
195
- throw e;
196
- } finally{
197
- reader.releaseLock();
198
- }
199
- } catch (err) {
200
- throw err;
201
- }
202
- }
203
- const queryRepo = (username, repo)=>{
204
- return apiRequest('GET', `/query/repo?repo=${repo}`, {
205
- headers: {
206
- 'X-COMATE-USER': username
207
- }
208
- });
209
- };
210
- const setRepoProject = (username, repo, projectId)=>{
211
- return apiRequest('POST', `/set/repo/project?repo=${repo}`, {
212
- headers: {
213
- 'X-COMATE-USER': username,
214
- 'Content-Type': 'application/json'
215
- },
216
- body: JSON.stringify({
217
- projectId
218
- })
219
- });
220
- };
221
- const setProjectCaseDemoContent = (username, repo, content)=>{
222
- return apiRequest('POST', `/set/project/case-demo-content?repo=${repo}`, {
223
- headers: {
224
- 'X-COMATE-USER': username,
225
- 'Content-Type': 'application/json'
226
- },
227
- body: JSON.stringify({
228
- caseDemoContent: content
229
- })
230
- });
231
- };
232
- const analyzeRepo = (username, repo, fileRelPath, content)=>{
233
- return apiRequest('POST', `/analyze/repo?repo=${repo}`, {
234
- headers: {
235
- 'X-COMATE-USER': username,
236
- 'Content-Type': 'application/json'
237
- },
238
- body: JSON.stringify({
239
- fileRelPath,
240
- fileContent: content
241
- })
242
- }, 10000);
243
- };
244
- // 创建AppBuilder会话id
245
- const newChat = (username, repo, sessionId, ide)=>{
246
- return apiRequest('POST', `/chat/new?repo=${repo}`, {
247
- headers: {
248
- 'X-COMATE-USER': username,
249
- 'Content-Type': 'application/json'
250
- },
251
- body: JSON.stringify({
252
- sessionId,
253
- ide
254
- })
255
- });
256
- };
257
- // 函数检索测试
258
- const ragRepoFunc = (username, repo, query)=>{
259
- return apiRequest('POST', `/rag/repo-func?repo=${repo}`, {
260
- headers: {
261
- 'X-COMATE-USER': username,
262
- 'Content-Type': 'application/json'
263
- },
264
- body: JSON.stringify({
265
- query
266
- })
267
- }, 20000);
268
- };
269
- // AppBuilder多轮对话生成代码
270
- async function genCaseCodeByAB(username, repo, cid, query, caseDemoContent, isFirstRound) {
271
- const res = await sseRequest('POST', `/gen/case-code-by-ab?repo=${repo}`, {
272
- body: JSON.stringify({
273
- cid,
274
- query,
275
- caseDemoContent,
276
- isFirstRound
277
- }),
278
- headers: {
279
- 'X-COMATE-USER': username,
280
- 'Content-Type': 'application/json'
281
- }
282
- });
283
- return res;
284
- }
285
-
286
- const pickICodeNameRepository = (repository)=>{
287
- if (repository.versionControl === 'git') {
288
- const repositoryUrl = repository.repositoryUrl;
289
- const matched = repositoryUrl?.match(/ssh:\/\/[^/]+\/(.+)/);
290
- if (matched && matched.length > 1) {
291
- return matched[1];
292
- }
293
- }
294
- return null;
295
- };
296
-
297
- class InfoSkillProvider extends SkillProvider {
298
- static{
299
- this.skillName = 'info';
300
- }
301
- static{
302
- this.displayName = '查看当前代码库信息';
303
- }
304
- static{
305
- this.description = '查看当前代码库在平台的信息和iAPI绑定关系';
306
- }
307
- static{
308
- this.parameters = {
309
- type: 'object',
310
- properties: {}
311
- };
312
- }
313
- async *execute() {
314
- const stream = new StringChunkStream();
315
- try {
316
- const userDetail = await this.currentUser.requestDetail();
317
- if (!userDetail) {
318
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
319
- return;
320
- }
321
- const repository = await this.retriever.repositoryInfo();
322
- let repositoryUrl = pickICodeNameRepository(repository);
323
- if (!repositoryUrl) {
324
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
325
- return;
326
- }
327
- yield stream.flush('-> 正在获取当前仓库在平台的配置...\n\n');
328
- const teamRepo = await queryRepo(userDetail.name, repositoryUrl);
329
- yield stream.flush('-> 获取仓库配置成功,信息如下:\n\n');
330
- const activeProject = teamRepo?.repoProjects.find((item)=>item.projectId === teamRepo.activeProjectId);
331
- stream.append(`仓库名称:${teamRepo.name}\n\n`);
332
- stream.append(`默认iAPI项目:${activeProject ? activeProject.name : '未设置'}\n\n`);
333
- stream.append(`描述:${teamRepo.description}\n\n`);
334
- stream.append('关联的iAPI项目:\n\n');
335
- const projectTable = this.render.table(teamRepo?.repoProjects || [], {
336
- columns: [
337
- {
338
- field: 'projectId',
339
- title: '项目ID'
340
- },
341
- {
342
- field: 'name',
343
- title: '名称'
344
- }
345
- ]
346
- });
347
- yield stream.flush(projectTable);
348
- yield stream.flush('\n\n');
349
- } catch (error) {
350
- this.logger.error(`Plugin Error: ${error}`);
351
- yield stream.flushReplaceLast(`${error}`);
352
- }
353
- }
354
- }
355
-
356
- class SetRepoProjectSkillProvider extends SkillProvider {
357
- static{
358
- this.skillName = 'setRepoProject';
359
- }
360
- static{
361
- this.displayName = '设置默认IAPI项目';
362
- }
363
- static{
364
- this.description = '代码库必须要和IAPI项目做绑定,同时只能使用一个IAPI项目做接口生成';
365
- }
366
- static{
367
- this.parameters = {
368
- type: 'object',
369
- properties: {}
370
- };
371
- }
372
- async *execute() {
373
- const stream = new StringChunkStream();
374
- try {
375
- const { query } = this.currentContext;
376
- const projectId = query.trim();
377
- const userDetail = await this.currentUser.requestDetail();
378
- if (!userDetail) {
379
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
380
- return;
381
- }
382
- const fs = await this.requestWorkspaceFileSystem();
383
- if (!fs) {
384
- yield stream.flush('请先完成授权,CaseBuilder 插件需在用户授权工作区的文件读取权限后才能使用。');
385
- return;
386
- }
387
- const repository = await this.retriever.repositoryInfo();
388
- let repositoryUrl = pickICodeNameRepository(repository);
389
- if (!repositoryUrl) {
390
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
391
- return;
392
- }
393
- if (projectId == '') {
394
- yield stream.flushReplaceLast('请输入需要设置的默认iAPI项目ID。');
395
- return;
396
- }
397
- const repoProject = await setRepoProject(userDetail.name, repositoryUrl, projectId);
398
- if (repoProject.name == '') {
399
- yield stream.flushReplaceLast('设置默认iAPI项目失败,iAPI项目不存在,请检查输入的iAPI项目ID是否正确。');
400
- return;
401
- }
402
- yield stream.flush('-> 设置默认iAPI项目成功。\n\n');
403
- yield stream.flush('-> 当前默认iAPI项目:\n\n');
404
- const projectTable = this.render.table([
405
- repoProject
406
- ], {
407
- columns: [
408
- {
409
- field: 'projectId',
410
- title: '项目ID'
411
- },
412
- {
413
- field: 'name',
414
- title: '名称'
415
- }
416
- ]
417
- });
418
- yield stream.flush(projectTable);
419
- yield stream.flush('\n\n');
420
- } catch (error) {
421
- this.logger.error(`Plugin Error: ${error}`);
422
- yield stream.flushReplaceLast(`${error}`);
423
- }
424
- }
425
- }
426
-
427
- class SetCaseDemoContentSkillProvider extends SkillProvider {
428
- static{
429
- this.skillName = 'setCaseDemoContent';
430
- }
431
- static{
432
- this.displayName = '设置【用例样例】代码';
433
- }
434
- static{
435
- this.description = '用例样例代码可用于用例生成的参考代码';
436
- }
437
- static{
438
- this.parameters = {
439
- type: 'object',
440
- properties: {}
441
- };
442
- }
443
- async *execute() {
444
- const stream = new StringChunkStream();
445
- try {
446
- const { activeFilePath, activeFileContent, selectedCode } = this.currentContext;
447
- const userDetail = await this.currentUser.requestDetail();
448
- if (!userDetail) {
449
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
450
- return;
451
- }
452
- const fs = await this.requestWorkspaceFileSystem();
453
- if (!fs) {
454
- yield stream.flush('请先完成授权,CaseBuilder 插件需在用户授权工作区的文件读取权限后才能使用。');
455
- return;
456
- }
457
- const repository = await this.retriever.repositoryInfo();
458
- let repositoryUrl = pickICodeNameRepository(repository);
459
- if (!repositoryUrl) {
460
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
461
- return;
462
- }
463
- if (activeFilePath == '') {
464
- yield stream.flushReplaceLast('未打开任何文件,请先打开需要设置的用例样例文件。');
465
- return;
466
- }
467
- if (activeFileContent == '') {
468
- yield stream.flushReplaceLast('当前文件内容为空,请先编辑需要设置的用例样例文件。');
469
- return;
470
- }
471
- let fileContent = activeFileContent;
472
- yield stream.flush('-> 使用当前编辑器中打开的文件作为用例样例文件。\n\n');
473
- yield stream.flush(`-> 用例样例文件为:${activeFilePath}\n\n`);
474
- if (selectedCode.length) {
475
- fileContent = selectedCode;
476
- yield stream.flush('-> 使用当前编辑器中选中的代码作为用例样例文件。\n\n');
477
- }
478
- const fileContentLength = fileContent.length;
479
- yield stream.flush(`-> 当前样例文件长度: ${fileContentLength}。\n\n`);
480
- if (fileContentLength > MAX_DEMO_CONTENT_LENGTH) {
481
- yield stream.flush(`-> 样例文件超过 ${MAX_DEMO_CONTENT_LENGTH} 字符限制,请编辑更短的样例文件。\n\n`);
482
- return;
483
- }
484
- await setProjectCaseDemoContent(userDetail.name, repositoryUrl, fileContent);
485
- yield stream.flush('-> 设置用例样例文件成功。\n\n');
486
- } catch (error) {
487
- this.logger.error(`Plugin Error: ${error}`);
488
- yield stream.flushReplaceLast(`${error}`);
489
- }
490
- }
491
- }
492
-
493
- const blackFileList = [
494
- '__init__.py',
495
- '.DS_Store'
496
- ];
497
- const getFilesFromDirectory = async (files, rootDir, fs)=>{
498
- rootDir = rootDir.replace(/\/$/, '');
499
- const dirs = await fs.readDirectory(rootDir);
500
- for (const item of dirs){
501
- if (item.type === 'directory') {
502
- await getFilesFromDirectory(files, path.join(rootDir, item.name), fs);
503
- }
504
- if (item.type === 'file') {
505
- if (blackFileList.includes(item.name)) {
506
- continue;
507
- }
508
- files.push({
509
- name: item.name,
510
- path: path.normalize(rootDir),
511
- status: 'pending'
512
- });
513
- }
514
- }
515
- return files;
516
- };
517
-
518
- class RepoAnalyzeSkillProvider extends SkillProvider {
519
- static{
520
- this.skillName = 'repoAnalyze';
521
- }
522
- static{
523
- this.displayName = '分析代码库';
524
- }
525
- static{
526
- this.description = '指定目录或文件进行分析代码。';
527
- }
528
- static{
529
- this.parameters = {
530
- type: 'object',
531
- properties: {}
532
- };
533
- }
534
- renderFileTableString(files) {
535
- return this.render.table(files, {
536
- columns: [
537
- {
538
- field: 'path',
539
- title: '目录'
540
- },
541
- {
542
- field: 'name',
543
- title: '文件名'
544
- },
545
- {
546
- field: 'status',
547
- title: '状态',
548
- format: (v)=>{
549
- switch(v){
550
- case 'pending':
551
- return '待提交';
552
- case 'processing':
553
- return '提交中';
554
- case 'success':
555
- return '已提交';
556
- case 'failed':
557
- return '提交失败';
558
- case 'ignore':
559
- return '忽略';
560
- case 'empty':
561
- return '空文件';
562
- case 'exists':
563
- return '任务已存在';
564
- default:
565
- return v;
566
- }
567
- }
568
- },
569
- {
570
- field: 'err',
571
- title: '失败原因',
572
- format: (v)=>v || ''
573
- }
574
- ]
575
- });
576
- }
577
- async *execute() {
578
- const stream = new StringChunkStream();
579
- try {
580
- const { query, selectedCode, activeFilePath } = this.currentContext;
581
- let keyword = path.normalize(query.trim());
582
- const userDetail = await this.currentUser.requestDetail();
583
- if (!userDetail) {
584
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
585
- return;
586
- }
587
- const fs = await this.requestWorkspaceFileSystem();
588
- if (!fs) {
589
- yield stream.flush('请先完成授权,CaseBuilder 插件需在用户授权工作区的文件读取权限后才能使用。');
590
- return;
591
- }
592
- const repository = await this.retriever.repositoryInfo();
593
- let repositoryUrl = pickICodeNameRepository(repository);
594
- if (!repositoryUrl) {
595
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
596
- return;
597
- }
598
- const isSelectedCode = activeFilePath.length && selectedCode.length;
599
- let fileMode = 'openFile';
600
- if ([
601
- '',
602
- '.',
603
- './'
604
- ].includes(keyword)) {
605
- if ((keyword === '.' || keyword === '') && isSelectedCode) {
606
- keyword = activeFilePath;
607
- fileMode = 'selectedCode';
608
- } else {
609
- yield stream.flushReplaceLast('请输入需要分析的目录、文件或者选中代码段,不允许输入根目录。');
610
- return;
611
- }
612
- }
613
- let files = [];
614
- let fileOrDir;
615
- try {
616
- fileOrDir = await fs.stat(keyword);
617
- } catch (error) {
618
- yield stream.flushReplaceLast('目录或文件不存在。');
619
- return;
620
- }
621
- if (fileOrDir.type === 'file') {
622
- files.push({
623
- name: path.basename(keyword),
624
- path: path.dirname(keyword),
625
- status: 'pending'
626
- });
627
- } else if (fileOrDir.type === 'directory') {
628
- // 遍历目录
629
- files = await getFilesFromDirectory([], keyword, fs);
630
- if (files.length === 0) {
631
- yield stream.flushReplaceLast('目录下没有文件,请选择其他目录');
632
- return;
633
- }
634
- files.sort((a, b)=>a.path.length - b.path.length);
635
- } else {
636
- yield stream.flushReplaceLast('请输入正确的目录或文件');
637
- return;
638
- }
639
- yield stream.flushReplaceLast(this.renderFileTableString(files));
640
- for(const fileIdx in files){
641
- const file = files[fileIdx];
642
- const fileRelPath = file.path + '/' + file.name;
643
- let fileContent;
644
- if (fileMode === 'openFile') {
645
- const buf = await fs.readFile(fileRelPath);
646
- fileContent = buf.toString();
647
- }
648
- if (fileMode === 'selectedCode') {
649
- fileContent = selectedCode;
650
- }
651
- if (!fileContent) {
652
- files[fileIdx].status = 'ignore';
653
- yield stream.flushReplaceLast(this.renderFileTableString(files));
654
- continue;
655
- }
656
- files[fileIdx].status = 'processing';
657
- yield stream.flushReplaceLast(this.renderFileTableString(files));
658
- try {
659
- const status = await analyzeRepo(userDetail.name, repositoryUrl, fileRelPath, fileContent);
660
- if (status) {
661
- files[fileIdx].status = status;
662
- }
663
- } catch (error) {
664
- files[fileIdx].status = 'failed';
665
- files[fileIdx].err = error;
666
- }
667
- yield stream.flushReplaceLast(this.renderFileTableString(files));
668
- }
669
- yield stream.flushReplaceLast(this.renderFileTableString(files) + `\n\n分析任务是异步操作,前往 [CaseBuilder-团队-管理函数](${WEB_LINK}/team/repo) 查看任务进度。`);
670
- } catch (error) {
671
- this.logger.error(`Plugin Error: ${error}`);
672
- yield stream.flushReplaceLast(`${error}`);
673
- }
674
- }
675
- }
676
-
677
- class GenCaseV2SkillProvider extends SkillProvider {
678
- static{
679
- this.skillName = 'genCaseV2';
680
- }
681
- static{
682
- this.displayName = '用例用例生成V2';
683
- }
684
- static{
685
- this.description = '基于代码库现有函数进行用例生成';
686
- }
687
- static{
688
- this.parameters = {
689
- type: 'object',
690
- properties: {}
691
- };
692
- }
693
- async *execute() {
694
- const stream = new StringChunkStream();
695
- try {
696
- const { query, selectedCode } = this.currentContext;
697
- const trimQuery = query.trim();
698
- const userDetail = await this.currentUser.requestDetail();
699
- if (!userDetail) {
700
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
701
- return;
702
- }
703
- const fs = await this.requestWorkspaceFileSystem();
704
- if (!fs) {
705
- yield stream.flush('请先完成授权,CaseBuilder 插件需在用户授权工作区的文件读取权限后才能使用。');
706
- return;
707
- }
708
- const repository = await this.retriever.repositoryInfo();
709
- let repositoryUrl = pickICodeNameRepository(repository);
710
- if (!repositoryUrl) {
711
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
712
- return;
713
- }
714
- if (trimQuery.length == 0) {
715
- yield stream.flushReplaceLast('请以自然语言输入用例描述或用例实现步骤。');
716
- return;
717
- }
718
- // 获取当前IDE的sessionId
719
- const sessionId = this.sessionUuid;
720
- if (!sessionId) {
721
- yield stream.flushReplaceLast('IDE sessionId获取失败,请稍后重试。');
722
- return;
723
- }
724
- // 获取当前IDE的名称
725
- const host = await this.retriever.hostInfo();
726
- const ideName = host.appName.replaceAll(" ", "_").toLowerCase();
727
- yield stream.flush('-> 正在获取当前仓库在平台的配置...\n\n');
728
- const teamRepo = await queryRepo(userDetail.name, repositoryUrl);
729
- if (teamRepo.activeProjectId == '') {
730
- yield stream.flush('团队仓库没有激活默认iAPI项目,你可以通过功能【设置默认iAPI项目】快速设置。\n\n');
731
- return;
732
- }
733
- const activeProject = teamRepo?.repoProjects.find((item)=>item.projectId === teamRepo.activeProjectId);
734
- if (!activeProject) {
735
- yield stream.flush('团队仓库默认iAPI项目不存在。\n\n');
736
- return;
737
- }
738
- yield stream.flush('-> 获取仓库配置成功,信息如下:\n\n');
739
- stream.append(`仓库名称:${teamRepo.name}\n\n`);
740
- stream.append(`默认iAPI项目:${activeProject.name}\n\n`);
741
- stream.append(`描述:${teamRepo.description}\n\n`);
742
- stream.append('关联的iAPI项目:\n\n');
743
- const projectTable = this.render.table(teamRepo?.repoProjects || [], {
744
- columns: [
745
- {
746
- field: 'projectId',
747
- title: '项目ID'
748
- },
749
- {
750
- field: 'name',
751
- title: '名称'
752
- }
753
- ]
754
- });
755
- yield stream.flush(projectTable);
756
- yield stream.flush('\n\n');
757
- const newChatRes = await newChat(userDetail.name, repositoryUrl, sessionId, ideName);
758
- if (!newChatRes || !newChatRes.cid) {
759
- yield stream.flush('生成会话失败,请稍后重试。\n\n');
760
- return;
761
- }
762
- const cid = newChatRes.cid;
763
- const isFirstRound = newChatRes.isFirstRound;
764
- yield stream.flush('-> 根据您的需求,开始为您生成接口用例代码...\n\n');
765
- const codeChunks = await genCaseCodeByAB(userDetail.name, repositoryUrl, cid, trimQuery, selectedCode, isFirstRound);
766
- for await (const chunk of codeChunks){
767
- yield stream.flush(chunk);
768
- }
769
- yield stream.flush('\n\n');
770
- } catch (error) {
771
- this.logger.error(`Plugin Error: ${error}`);
772
- yield stream.flush(`${error}。`);
773
- }
774
- }
775
- }
776
-
777
- class RagRepoFuncSkillProvider extends SkillProvider {
778
- static{
779
- this.skillName = 'ragRepoFunc';
780
- }
781
- static{
782
- this.displayName = '代码库函数命中测试';
783
- }
784
- static{
785
- this.description = '根据关键字检索已经上传AB知识库的函数知识。';
786
- }
787
- static{
788
- this.parameters = {
789
- type: 'object',
790
- properties: {}
791
- };
792
- }
793
- async *execute() {
794
- const stream = new StringChunkStream();
795
- try {
796
- const { query } = this.currentContext;
797
- const keyword = query.trim();
798
- const userDetail = await this.currentUser.requestDetail();
799
- if (!userDetail) {
800
- yield stream.flushReplaceLast('请先完成授权,CaseBuilder 插件需在用户授权后才能使用。');
801
- return;
802
- }
803
- const repository = await this.retriever.repositoryInfo();
804
- let repositoryUrl = pickICodeNameRepository(repository);
805
- if (!repositoryUrl) {
806
- yield stream.flushReplaceLast('无法获取当前项目的仓库地址,可能不是一个icode仓库或者缺少.git配置目录。');
807
- return;
808
- }
809
- if (keyword.length == 0) {
810
- yield stream.flushReplaceLast('请输入检索关键字,可以是用例描述的某一个步骤。');
811
- return;
812
- }
813
- yield stream.flush('-> 正在为你进行函数命中测试...\n\n');
814
- const res = await ragRepoFunc(userDetail.name, repositoryUrl, keyword);
815
- if (res?.length) {
816
- yield stream.flushReplaceLast(res);
817
- } else {
818
- yield stream.flushReplaceLast('没有找到匹配的函数,请调整输入的关键字重新尝试。');
819
- }
820
- } catch (error) {
821
- this.logger.error(`Plugin Error: ${error}`);
822
- yield stream.flushReplaceLast(`${error}`);
823
- }
824
- }
825
- }
826
-
827
- function setup({ registry }) {
828
- registry.registerSkillProvider('help', HelpSkillProvider);
829
- registry.registerSkillProvider('info', InfoSkillProvider);
830
- registry.registerSkillProvider('setRepoProject', SetRepoProjectSkillProvider);
831
- registry.registerSkillProvider('setCaseDemoContent', SetCaseDemoContentSkillProvider);
832
- registry.registerSkillProvider('repoAnalyze', RepoAnalyzeSkillProvider);
833
- registry.registerSkillProvider('genCaseV2', GenCaseV2SkillProvider);
834
- registry.registerSkillProvider('ragRepoFunc', RagRepoFuncSkillProvider);
835
- }
836
-
837
- export { setup };