ai-worktool 1.0.69 → 1.0.70

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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ## 1.0.69 (2025-08-18)
1
+ ## 1.0.70 (2025-08-19)
2
2
 
3
3
 
4
4
  ### Bug Fixes
@@ -37,7 +37,10 @@ async function addUncoveredLinePrompt(srcPath, report) {
37
37
  源文件内容如下:
38
38
  \`\`\`
39
39
  ${await (0, tools_1.readFile)(srcPath, 'utf8', true)}
40
- \`\`\``;
40
+ \`\`\`` + (report.coverage.branches.pct > 0 ? `
41
+
42
+ 查找已有测试文件增加单测代码。
43
+ ` : '');
41
44
  }
42
45
  async function addUncoveredFilePrompt(total, files) {
43
46
  const testFileNames = files.map((it) => it.filePath);
@@ -103,7 +103,7 @@ function inferCodeTypeFromExtension(filePath) {
103
103
  * @param argsObj 包含参数的对象
104
104
  * @returns 函数执行结果
105
105
  */
106
- async function callWithObject(name, argsObj, cwd) {
106
+ async function callWithObject(name, argsObj, projectDir) {
107
107
  const fn = tools[name];
108
108
  if (!fn) {
109
109
  throw new Error(`Tool ${name} not found`);
@@ -113,8 +113,10 @@ async function callWithObject(name, argsObj, cwd) {
113
113
  // 从对象中提取参数值
114
114
  const args = paramNames.map((name) => {
115
115
  // 转成决定路径
116
- if (name === 'filePath' && cwd && !path_1.default.isAbsolute(argsObj[name])) {
117
- return path_1.default.resolve(cwd, argsObj[name]);
116
+ if ((name === 'filePath' || name === 'oldPath' || name === 'newPath' || name === 'directory') &&
117
+ projectDir &&
118
+ !path_1.default.isAbsolute(argsObj[name])) {
119
+ return path_1.default.resolve(projectDir, argsObj[name]);
118
120
  }
119
121
  return argsObj[name];
120
122
  });
@@ -172,7 +174,7 @@ toolCall, root, result) {
172
174
  root = root || '/';
173
175
  const params = toolCall.params || {};
174
176
  if (toolCall.function_name === 'readFile') {
175
- const outputResult = result ? (result?.success ? ` ✅` : result?.message || '❌') : '';
177
+ const outputResult = result ? (result?.success ? ` ✅` : ` ❌${result?.message}`) : '';
176
178
  const filePath = params[0] || params.filePath;
177
179
  return `读取文件:${formatDisplayText(filePath ? (path_1.default.isAbsolute(filePath) ? path_1.default.relative(root, filePath) : filePath) : '')}${outputResult}`;
178
180
  }
@@ -181,21 +183,24 @@ toolCall, root, result) {
181
183
  toolCall.function_name === 'modifyLine' ||
182
184
  toolCall.function_name === 'deleteLine' ||
183
185
  toolCall.function_name === 'batchModifyLines') {
184
- const outputResult = result ? (result?.success ? ` ✅` : result?.message || '❌') : '';
186
+ const outputResult = result ? (result?.success ? ` ✅` : ` ❌${result?.message}`) : '';
185
187
  const filePath = params[0] || params.filePath;
186
188
  return `修改文件:${formatDisplayText(filePath ? (path_1.default.isAbsolute(filePath) ? path_1.default.relative(root, filePath) : filePath) : '')}${outputResult}`;
187
189
  }
188
190
  if (toolCall.function_name === 'searchFilesByExtension') {
189
191
  const outputResult = result
190
192
  ? result?.success
191
- ? ` => ${formatDisplayText(result.data.replaceAll(root + path_1.default.sep, '').replaceAll('- ', '').replaceAll('\n', ' '))} ✅`
192
- : result?.message || ''
193
+ ? ` => ${formatDisplayText(result.data
194
+ .replaceAll(root + path_1.default.sep, '')
195
+ .replaceAll('- ', '')
196
+ .replaceAll('\n', ' '))} ✅`
197
+ : ` ❌${result?.message}`
193
198
  : '';
194
199
  const searchPath = params[0] || params.directory;
195
200
  const exts = params[1] || params.extensions || '';
196
201
  return `检索文件:${searchPath ? (path_1.default.isAbsolute(searchPath) ? path_1.default.relative(root, searchPath) : searchPath) : ''}${exts ? '/*' : ''}${exts}${outputResult}`;
197
202
  }
198
- const outputResult = result ? (result?.success ? ` ✅` : result?.message || '❌') : '';
203
+ const outputResult = result ? (result?.success ? ` ✅` : ` ❌${result?.message}`) : '';
199
204
  return toolCall.function_name + outputResult;
200
205
  }
201
206
  //# sourceMappingURL=toolCall.js.map
@@ -231,7 +231,7 @@ async function getFailedTests(projectRoot, coverageDir = 'coverage') {
231
231
  function parseLcovForUncoveredLines(lcovContent, measureType = 'branches') {
232
232
  const uncoveredLines = {};
233
233
  let currentFile = null;
234
- const DAKey = measureType === 'branches' ? 'BRDA' : measureType === 'functions' ? 'FNDA' : 'DA';
234
+ const DAKey = measureType === 'branches' ? 'BRDA' : 'DA';
235
235
  lcovContent.split('\n').forEach((line) => {
236
236
  if (line.startsWith('SF:')) {
237
237
  // 记录当前文件路径
@@ -243,7 +243,7 @@ function parseLcovForUncoveredLines(lcovContent, measureType = 'branches') {
243
243
  // BRDA:53,0,0,8 最后是执行次数
244
244
  const [lineNumberStr, ...executionCountStr] = line.substring(DAKey.length + 1).split(',');
245
245
  const lineNumber = parseInt(lineNumberStr, 10);
246
- const executionCount = parseInt(executionCountStr[executionCountStr.length - 1], 10);
246
+ const executionCount = parseInt(executionCountStr[DAKey === 'BRDA' ? 2 : 0], 10);
247
247
  // 如果执行次数为0,表示该行未被覆盖
248
248
  if (executionCount === 0) {
249
249
  uncoveredLines[currentFile].push(lineNumber);
@@ -56,10 +56,10 @@ async function detectProjectConfig(projectRoot, defaultConfig) {
56
56
  await detectLanguages(projectRoot, config);
57
57
  // 检测源代码目录
58
58
  await detectSrcDir(projectRoot, config);
59
- // 检测测试相关配置
60
- await detectTestConfig(projectRoot, config);
61
59
  // 检测项目类型(前端/后端/全栈)
62
60
  await detectProjectType(projectRoot, config);
61
+ // 检测测试相关配置
62
+ await detectTestConfig(projectRoot, config);
63
63
  // 检测框架信息
64
64
  await detectFramework(projectRoot, config);
65
65
  // 检测Git配置
@@ -170,6 +170,10 @@ async function detectTestConfig(projectRoot, config) {
170
170
  }
171
171
  // 检测测试目录
172
172
  const possibleTestDirs = ['test', 'tests', '__tests__', 'spec', 'specs'];
173
+ if (config.srcDir) {
174
+ // __tests__:这是前端项目(尤其是使用 Jest 作为测试框架的 React 项目)中比较有特色的放置方式。
175
+ possibleTestDirs.push(path_1.default.join(config.srcDir, '__tests__'));
176
+ }
173
177
  for (const dir of possibleTestDirs) {
174
178
  const dirPath = path_1.default.join(projectRoot, dir);
175
179
  if (await directoryExists(dirPath)) {
@@ -238,16 +242,28 @@ async function detectTestConfig(projectRoot, config) {
238
242
  const extensions = new Set();
239
243
  if (config.languages?.includes('javascript')) {
240
244
  extensions.add('js');
245
+ if (config.projectType === 'frontend') {
246
+ extensions.add('jsx');
247
+ }
241
248
  }
242
249
  if (config.languages?.includes('typescript')) {
243
250
  extensions.add('ts');
251
+ if (config.projectType === 'frontend') {
252
+ extensions.add('tsx');
253
+ }
244
254
  }
245
255
  if (config.languages?.includes('coffeescript')) {
246
256
  extensions.add('coffee');
257
+ if (config.projectType === 'frontend') {
258
+ extensions.add('cjsx');
259
+ }
247
260
  }
248
261
  // 默认为js(如果没有检测到语言)
249
262
  if (extensions.size === 0) {
250
263
  extensions.add('js');
264
+ if (config.projectType === 'frontend') {
265
+ extensions.add('jsx');
266
+ }
251
267
  }
252
268
  // 生成基础模式集合
253
269
  const basePatterns = new Set();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-worktool",
3
3
  "displayName": "吃豆豆:单测智能体",
4
- "version": "1.0.69",
4
+ "version": "1.0.70",
5
5
  "description": "单元测试智能体,帮你开发单元测试用例代码直到100%单测覆盖通过。",
6
6
  "author": "jianguoke.cn",
7
7
  "license": "MIT",
@@ -28,11 +28,11 @@
28
28
  "createup": "node ./uposs.js create-local-folder",
29
29
  "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
30
30
  "puball": "yarn ver && yarn exepack && yarn vspack && yarn pubvs && yarn pubovsx && yarn puboss && yarn pubnpm",
31
- "exepack": "yarn createup && cross-env PKG_CACHE_PATH=./binaries pkg -o packages/aicoder-1.0.69 . && yarn upicon",
31
+ "exepack": "yarn createup && cross-env PKG_CACHE_PATH=./binaries pkg -o packages/aicoder-1.0.70 . && yarn upicon",
32
32
  "pubvs": "yarn remove-deps && yarn changelog && vsce publish --yarn --baseContentUrl https://aicoder.jianguoke.cn/assets && yarn restore-deps",
33
33
  "pubovsx": "yarn remove-deps && ovsx publish -p 47621ff6-be56-4814-865e-d2a8e8a76f86 --yarn --baseContentUrl https://aicoder.jianguoke.cn/assets && yarn restore-deps",
34
34
  "patch": "yarn remove-deps && vsce publish patch --yarn && yarn restore-deps",
35
- "vspack": "yarn createup && yarn remove-deps && vsce package -o packages/aicoder-1.0.69.vsix --yarn --baseContentUrl https://aicoder.jianguoke.cn/assets && yarn restore-deps",
35
+ "vspack": "yarn createup && yarn remove-deps && vsce package -o packages/aicoder-1.0.70.vsix --yarn --baseContentUrl https://aicoder.jianguoke.cn/assets && yarn restore-deps",
36
36
  "puboss": "node ./uposs.js upload",
37
37
  "pubnpm": "npm publish --registry=https://registry.npmjs.org",
38
38
  "prepare": "husky"