aico-cli 0.4.0 → 0.4.2

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 (55) hide show
  1. package/dist/chunks/simple-config.mjs +41 -15
  2. package/dist/cli.mjs +35 -31
  3. package/package.json +4 -1
  4. package/templates/agents/aico/plan/function-point-analyzer.md +219 -0
  5. package/templates/agents/aico/requirement/test-crossplatform.ps1 +0 -0
  6. package/templates/agents/aico/requirement/test-crossplatform.sh +456 -0
  7. package/templates/commands/base//344/273/243/347/240/201/345/256/241/346/237/245/346/231/272/350/203/275/344/275/223.md +2 -5
  8. package/templates/commands/base//345/212/237/350/203/275/347/202/271/346/265/213/347/256/227.md +469 -19
  9. package/templates/skills/slack-gif-creator/LICENSE.txt +202 -0
  10. package/templates/skills/slack-gif-creator/SKILL.md +646 -0
  11. package/templates/skills/slack-gif-creator/core/color_palettes.py +302 -0
  12. package/templates/skills/slack-gif-creator/core/easing.py +230 -0
  13. package/templates/skills/slack-gif-creator/core/frame_composer.py +469 -0
  14. package/templates/skills/slack-gif-creator/core/gif_builder.py +246 -0
  15. package/templates/skills/slack-gif-creator/core/typography.py +357 -0
  16. package/templates/skills/slack-gif-creator/core/validators.py +264 -0
  17. package/templates/skills/slack-gif-creator/core/visual_effects.py +494 -0
  18. package/templates/skills/slack-gif-creator/requirements.txt +4 -0
  19. package/templates/skills/slack-gif-creator/templates/bounce.py +106 -0
  20. package/templates/skills/slack-gif-creator/templates/explode.py +331 -0
  21. package/templates/skills/slack-gif-creator/templates/fade.py +329 -0
  22. package/templates/skills/slack-gif-creator/templates/flip.py +291 -0
  23. package/templates/skills/slack-gif-creator/templates/kaleidoscope.py +211 -0
  24. package/templates/skills/slack-gif-creator/templates/morph.py +329 -0
  25. package/templates/skills/slack-gif-creator/templates/move.py +293 -0
  26. package/templates/skills/slack-gif-creator/templates/pulse.py +268 -0
  27. package/templates/skills/slack-gif-creator/templates/shake.py +127 -0
  28. package/templates/skills/slack-gif-creator/templates/slide.py +291 -0
  29. package/templates/skills/slack-gif-creator/templates/spin.py +269 -0
  30. package/templates/skills/slack-gif-creator/templates/wiggle.py +300 -0
  31. package/templates/skills/slack-gif-creator/templates/zoom.py +312 -0
  32. package/templates/skills/swimlane-diagram/README.md +373 -0
  33. package/templates/skills/swimlane-diagram/SKILL.md +242 -0
  34. package/templates/skills/swimlane-diagram/examples.md +405 -0
  35. package/templates/skills/swimlane-diagram/generators.mjs +258 -0
  36. package/templates/skills/swimlane-diagram/package.json +126 -0
  37. package/templates/skills/swimlane-diagram/reference.md +368 -0
  38. package/templates/skills/swimlane-diagram/swimlane-diagram.mjs +215 -0
  39. package/templates/skills/swimlane-diagram/swimlane-diagram.test.mjs +358 -0
  40. package/templates/skills/swimlane-diagram/validators.mjs +291 -0
  41. package/templates/skills/theme-factory/LICENSE.txt +202 -0
  42. package/templates/skills/theme-factory/SKILL.md +59 -0
  43. package/templates/skills/theme-factory/theme-showcase.pdf +0 -0
  44. package/templates/skills/theme-factory/themes/arctic-frost.md +19 -0
  45. package/templates/skills/theme-factory/themes/botanical-garden.md +19 -0
  46. package/templates/skills/theme-factory/themes/desert-rose.md +19 -0
  47. package/templates/skills/theme-factory/themes/forest-canopy.md +19 -0
  48. package/templates/skills/theme-factory/themes/golden-hour.md +19 -0
  49. package/templates/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  50. package/templates/skills/theme-factory/themes/modern-minimalist.md +19 -0
  51. package/templates/skills/theme-factory/themes/ocean-depths.md +19 -0
  52. package/templates/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  53. package/templates/skills/theme-factory/themes/tech-innovation.md +19 -0
  54. package/templates/code.md +0 -70
  55. package/templates/windows-bootstrap.ps1 +0 -390
@@ -13,7 +13,7 @@ import { join as join$1 } from 'node:path';
13
13
  import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.4.0";
16
+ const version = "0.4.2";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
@@ -4678,18 +4678,18 @@ const DEFAULT_FILE_COPY_CONFIGS = [
4678
4678
  }
4679
4679
  },
4680
4680
  {
4681
- source: "templates/personality.md",
4682
- destination: join(CLAUDE_DIR, "personality.md"),
4683
- type: "file",
4681
+ source: "templates/skills",
4682
+ destination: join(CLAUDE_DIR, "skills"),
4683
+ type: "directory",
4684
4684
  options: {
4685
- mergeStrategy: "merge",
4685
+ mergeStrategy: "copy",
4686
4686
  backupBeforeCopy: true,
4687
4687
  deleteBeforeCopy: true
4688
4688
  }
4689
4689
  },
4690
4690
  {
4691
- source: "templates/code.md",
4692
- destination: join(CLAUDE_DIR, "code.md"),
4691
+ source: "templates/personality.md",
4692
+ destination: join(CLAUDE_DIR, "personality.md"),
4693
4693
  type: "file",
4694
4694
  options: {
4695
4695
  mergeStrategy: "merge",
@@ -4941,7 +4941,10 @@ class ConfigInstaller extends AbstractInstaller {
4941
4941
  const settingsInstalled = existsSync(SETTINGS_FILE);
4942
4942
  const personalityInstalled = existsSync(join(CLAUDE_DIR, "personality.md"));
4943
4943
  const languageInstalled = existsSync(join(CLAUDE_DIR, "language.md"));
4944
- return { isInstalled: settingsInstalled && personalityInstalled && languageInstalled };
4944
+ const skillsInstalled = existsSync(join(CLAUDE_DIR, "skills"));
4945
+ return {
4946
+ isInstalled: settingsInstalled && personalityInstalled && languageInstalled && skillsInstalled
4947
+ };
4945
4948
  }
4946
4949
  async install(options = {}) {
4947
4950
  try {
@@ -5151,35 +5154,58 @@ class ConfigCheckerInstaller extends AbstractInstaller {
5151
5154
  name = "Config Checker";
5152
5155
  async checkStatus() {
5153
5156
  const configType = await this.detectConfigType();
5157
+ const skillsInstalled = exists(join(CLAUDE_DIR, "skills"));
5154
5158
  return {
5155
- isInstalled: configType !== "none",
5159
+ isInstalled: configType !== "none" && skillsInstalled,
5156
5160
  version: void 0
5157
5161
  };
5158
5162
  }
5159
5163
  async install(options = {}) {
5160
5164
  try {
5161
5165
  const configType = await this.detectConfigType();
5162
- if (configType !== "none" && !options.force) {
5163
- this.log(`\u68C0\u6D4B\u5230 ${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"} \u914D\u7F6E\uFF0C\u8DF3\u8FC7\u914D\u7F6E`, "success");
5166
+ const skillsInstalled = exists(join(CLAUDE_DIR, "skills"));
5167
+ if (configType !== "none" && skillsInstalled && !options.force) {
5168
+ this.log(`\u68C0\u6D4B\u5230 ${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"} \u914D\u7F6E\u4E14\u6280\u80FD\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u914D\u7F6E`, "success");
5164
5169
  return this.createSkipResult(
5165
- `${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"} \u914D\u7F6E\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u914D\u7F6E`,
5170
+ `${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"} \u914D\u7F6E\u548C\u6280\u80FD\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u914D\u7F6E`,
5166
5171
  "already_configured",
5167
- { configType }
5172
+ { configType, skillsInstalled }
5168
5173
  );
5169
5174
  }
5170
5175
  if (!options.silent) {
5171
5176
  if (configType !== "none" && options.force) {
5172
5177
  this.log(`\u5F3A\u5236\u8986\u76D6\u73B0\u6709${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"}\u914D\u7F6E...`, "info");
5178
+ } else if (!skillsInstalled) {
5179
+ this.log("\u68C0\u6D4B\u5230\u6280\u80FD\u76EE\u5F55\u672A\u5B89\u88C5\uFF0C\u5C06\u8FDB\u884C\u5B89\u88C5...", "info");
5173
5180
  } else {
5174
5181
  this.log("\u5F00\u59CB\u914D\u7F6E\u68C0\u67E5...", "info");
5175
5182
  }
5176
5183
  }
5177
5184
  const operation = configType !== "none" && options.force ? "\u8986\u76D6\u68C0\u67E5" : "\u914D\u7F6E\u68C0\u67E5";
5178
- return this.createSuccessResult(`\u914D\u7F6E\u68C0\u67E5\u5B8C\u6210\uFF0C${operation}\u6210\u529F`, void 0, { configType });
5185
+ const skillsMessage = skillsInstalled ? "\u6280\u80FD\u76EE\u5F55\u5DF2\u5B58\u5728" : "\u6280\u80FD\u76EE\u5F55\u672A\u5B89\u88C5";
5186
+ return this.createSuccessResult(
5187
+ `\u914D\u7F6E\u68C0\u67E5\u5B8C\u6210\uFF0C${operation}\u6210\u529F\uFF0C${skillsMessage}`,
5188
+ void 0,
5189
+ { configType, skillsInstalled }
5190
+ );
5179
5191
  } catch (error) {
5180
5192
  return this.handleError(error, "\u914D\u7F6E\u68C0\u67E5");
5181
5193
  }
5182
5194
  }
5195
+ /**
5196
+ * 检查版本一致性
5197
+ */
5198
+ async checkVersionConsistency() {
5199
+ try {
5200
+ const aicoConfig = readAicoConfig();
5201
+ if (!aicoConfig) {
5202
+ return false;
5203
+ }
5204
+ return aicoConfig.version === version;
5205
+ } catch (error) {
5206
+ return false;
5207
+ }
5208
+ }
5183
5209
  /**
5184
5210
  * 检测配置类型
5185
5211
  */
@@ -5544,4 +5570,4 @@ async function openSettingsJson() {
5544
5570
  }
5545
5571
  }
5546
5572
 
5547
- export { AICO_CONFIG_FILE as A, getMcpConfigPath as B, CLAUDE_DIR as C, DEFAULT_FILE_COPY_CONFIGS as D, readMcpConfig as E, writeMcpConfig as F, backupMcpConfig as G, mergeMcpServers as H, buildMcpServerConfig as I, fixWindowsMcpConfig as J, addCompletedOnboarding as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, createEscapablePrompt as N, displayBannerWithInfo as O, executeWithEscapeSupport as P, handleExitPromptError as Q, handleGeneralError as R, SETTINGS_FILE as S, EscapeKeyPressed as T, displayBanner as U, ConfigCheckerInstaller as V, InstallationComposer as W, version as X, readAicoConfig as Y, init$1 as Z, init as a, getPlatform as b, commandExists as c, importRecommendedEnv as d, importRecommendedPermissions as e, cleanupPermissions as f, getTermuxPrefix as g, mergeAndCleanPermissions as h, isTermux as i, CLAUDE_MD_FILE as j, ClAUDE_CONFIG_FILE as k, SUPPORTED_LANGS as l, messages as m, LANG_LABELS as n, openSettingsJson as o, AI_OUTPUT_LANGUAGES as p, ensureClaudeDir as q, backupExistingConfig as r, copyConfigFiles as s, copyConfigFilesWithConfig as t, configureApi as u, mergeConfigs as v, updateDefaultModel as w, mergeSettingsFile as x, getExistingApiConfig as y, applyAiLanguageDirective as z };
5573
+ export { AICO_CONFIG_FILE as A, getMcpConfigPath as B, CLAUDE_DIR as C, DEFAULT_FILE_COPY_CONFIGS as D, readMcpConfig as E, writeMcpConfig as F, backupMcpConfig as G, mergeMcpServers as H, buildMcpServerConfig as I, fixWindowsMcpConfig as J, addCompletedOnboarding as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, createEscapablePrompt as N, displayBannerWithInfo as O, executeWithEscapeSupport as P, handleExitPromptError as Q, handleGeneralError as R, SETTINGS_FILE as S, EscapeKeyPressed as T, displayBanner as U, ConfigCheckerInstaller as V, updateAicoConfig as W, version as X, InstallationComposer as Y, readAicoConfig as Z, init$1 as _, init as a, getPlatform as b, commandExists as c, importRecommendedEnv as d, importRecommendedPermissions as e, cleanupPermissions as f, getTermuxPrefix as g, mergeAndCleanPermissions as h, isTermux as i, CLAUDE_MD_FILE as j, ClAUDE_CONFIG_FILE as k, SUPPORTED_LANGS as l, messages as m, LANG_LABELS as n, openSettingsJson as o, AI_OUTPUT_LANGUAGES as p, ensureClaudeDir as q, backupExistingConfig as r, copyConfigFiles as s, copyConfigFilesWithConfig as t, configureApi as u, mergeConfigs as v, updateDefaultModel as w, mergeSettingsFile as x, getExistingApiConfig as y, applyAiLanguageDirective as z };
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { N as createEscapablePrompt, O as displayBannerWithInfo, a as init, P as executeWithEscapeSupport, Q as handleExitPromptError, R as handleGeneralError, T as EscapeKeyPressed, U as displayBanner, V as ConfigCheckerInstaller, W as InstallationComposer, X as version, Y as readAicoConfig } from './chunks/simple-config.mjs';
4
+ import { N as createEscapablePrompt, O as displayBannerWithInfo, a as init, P as executeWithEscapeSupport, Q as handleExitPromptError, R as handleGeneralError, T as EscapeKeyPressed, U as displayBanner, V as ConfigCheckerInstaller, W as updateAicoConfig, X as version, Y as InstallationComposer, Z as readAicoConfig } from './chunks/simple-config.mjs';
5
5
  import inquirer$1 from 'inquirer';
6
6
  import { spawn, exec as exec$1 } from 'node:child_process';
7
7
  import 'tinyexec';
@@ -356,9 +356,10 @@ async function update(options = {}) {
356
356
  const configType = await checker.detectConfigType();
357
357
  console.log(ansis.cyan(`\u{1F4CB} \u68C0\u6D4B\u5230\u914D\u7F6E\u7C7B\u578B: ${configType === "company" ? "\u516C\u53F8\u914D\u7F6E" : configType === "personal" ? "\u4E2A\u4EBA\u914D\u7F6E" : "\u65E0\u914D\u7F6E"}`));
358
358
  await updateAicoCli();
359
+ updateAicoConfig({ version });
359
360
  if (configType === "none") {
360
361
  console.log(ansis.yellow("\n\u26A0\uFE0F \u672A\u68C0\u6D4B\u5230\u914D\u7F6E\uFF0C\u5C06\u6267\u884C\u521D\u59CB\u5316..."));
361
- const { init } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
362
+ const { init } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
362
363
  await init({
363
364
  force: false,
364
365
  skipBanner: true,
@@ -404,7 +405,7 @@ function setupCommands(cli) {
404
405
  } else if (options.update) {
405
406
  await update({});
406
407
  } else if (options.company) {
407
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
408
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
408
409
  await init2({
409
410
  apiType: "auth_token",
410
411
  force: options.force,
@@ -412,7 +413,7 @@ function setupCommands(cli) {
412
413
  skipPrompt: true
413
414
  });
414
415
  } else if (options.personal) {
415
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
416
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
416
417
  await init2({
417
418
  apiType: "ccr_proxy",
418
419
  force: options.force,
@@ -434,7 +435,7 @@ function setupCommands(cli) {
434
435
  await update({});
435
436
  });
436
437
  cli.command("c", "\u5FEB\u901F\u914D\u7F6E\u516C\u53F8\u8BBE\u7F6E").action(async () => {
437
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
438
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
438
439
  await init2({
439
440
  apiType: "auth_token",
440
441
  force: false,
@@ -443,7 +444,7 @@ function setupCommands(cli) {
443
444
  });
444
445
  });
445
446
  cli.command("p", "\u5FEB\u901F\u914D\u7F6E\u4E2A\u4EBA\u8BBE\u7F6E").action(async () => {
446
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
447
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
447
448
  await init2({
448
449
  apiType: "ccr_proxy",
449
450
  force: false,
@@ -468,31 +469,34 @@ async function startCodeEditor() {
468
469
  const configType = await checker.detectConfigType();
469
470
  const aicoConfig = readAicoConfig();
470
471
  const needsReinstall = !aicoConfig || aicoConfig.version !== version;
471
- if (configType === "none" || needsReinstall) {
472
- if (configType === "none") {
473
- console.log(ansis.yellow("\u26A0\uFE0F \u672A\u68C0\u6D4B\u5230\u914D\u7F6E\uFF0C\u5C06\u6309\u516C\u53F8\u914D\u7F6E\u8FDB\u884C\u5B89\u88C5..."));
474
- } else {
475
- console.log(ansis.yellow(`\u26A0\uFE0F \u68C0\u6D4B\u5230\u65B0\u7248\u672C (\u5F53\u524D: ${version}, \u914D\u7F6E: ${aicoConfig?.version || "\u65E0"})\uFF0C\u5C06\u81EA\u52A8\u5347\u7EA7...`));
476
- }
477
- if (configType === "company") {
478
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
479
- await init2({
480
- apiType: "auth_token",
481
- skipBanner: true,
482
- skipPrompt: true,
483
- force: true
484
- });
485
- } else if (configType === "personal") {
486
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
487
- await init2({
488
- apiType: "ccr_proxy",
489
- skipBanner: true,
490
- skipPrompt: true,
491
- force: true
492
- });
493
- } else {
494
- const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.Z; });
495
- await init2({ skipBanner: true, skipPrompt: true });
472
+ if (configType === "none") {
473
+ console.log(ansis.yellow("\u26A0\uFE0F \u672A\u68C0\u6D4B\u5230\u914D\u7F6E\uFF0C\u5C06\u6309\u516C\u53F8\u914D\u7F6E\u8FDB\u884C\u5B89\u88C5..."));
474
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
475
+ await init2({ skipBanner: true, skipPrompt: true });
476
+ } else if (needsReinstall) {
477
+ console.log(ansis.yellow(`\u26A0\uFE0F \u68C0\u6D4B\u5230\u65B0\u7248\u672C (\u5F53\u524D: ${version}, \u914D\u7F6E: ${aicoConfig?.version || "\u65E0"})`));
478
+ try {
479
+ updateAicoConfig({ version });
480
+ console.log(ansis.green("\u2705 \u7248\u672C\u5DF2\u540C\u6B65\uFF0C\u8DF3\u8FC7\u91CD\u65B0\u5B89\u88C5"));
481
+ } catch (error) {
482
+ console.log(ansis.yellow("\u26A0\uFE0F \u7248\u672C\u540C\u6B65\u5931\u8D25\uFF0C\u5C06\u6267\u884C\u5B8C\u6574\u914D\u7F6E\u66F4\u65B0..."));
483
+ if (configType === "company") {
484
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
485
+ await init2({
486
+ apiType: "auth_token",
487
+ skipBanner: true,
488
+ skipPrompt: true,
489
+ force: true
490
+ });
491
+ } else if (configType === "personal") {
492
+ const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n._; });
493
+ await init2({
494
+ apiType: "ccr_proxy",
495
+ skipBanner: true,
496
+ skipPrompt: true,
497
+ force: true
498
+ });
499
+ }
496
500
  }
497
501
  } else {
498
502
  console.log(ansis.green(`\u2705 \u68C0\u6D4B\u5230${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"}\u914D\u7F6E\uFF0C\u7248\u672C\u5339\u914D\uFF0C\u8DF3\u8FC7\u914D\u7F6E\u68C0\u67E5...`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aico-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "packageManager": "pnpm@9.15.9",
5
5
  "description": "AI CLI",
6
6
  "repository": {
@@ -51,7 +51,10 @@
51
51
  "@types/semver": "^7.7.0",
52
52
  "@vitest/coverage-v8": "^3.2.4",
53
53
  "@vitest/ui": "^3.2.4",
54
+ "playwright": "^1.56.1",
55
+ "pptxgenjs": "^4.0.1",
54
56
  "semver": "^7.7.2",
57
+ "sharp": "^0.34.4",
55
58
  "tsx": "^4.20.3",
56
59
  "typescript": "^5.9.2",
57
60
  "unbuild": "^3.6.0",
@@ -0,0 +1,219 @@
1
+ ---
2
+ name: function-point-analyzer
3
+ description: 功能点测算智能体,自动识别工程模块并分析Git提交记录,按月份输出功能点统计CSV
4
+ tools: Read, Write, Bash, Read, Edit, Glob, Grep
5
+ color: green
6
+ ---
7
+
8
+ > 🎯 功能点测算智能体 - 专为软件开发项目设计
9
+ >
10
+ > 🔍 核心功能:
11
+ > - 自动识别工程类型和结构
12
+ > - 分析Git提交记录提取功能点
13
+ > - 按月份分组统计并输出CSV报告
14
+ > - 支持多层级模块识别
15
+
16
+ ## 💻 调用方式
17
+
18
+ ### 基本用法
19
+ ```markdown
20
+ 启动功能点测算智能体
21
+ ```
22
+
23
+ ### 带参数的用法
24
+ ```markdown
25
+ /功能点测算 --months 3
26
+ ```
27
+
28
+ ### 命令选项
29
+ - `--months <number>`: 指定分析最近几个月的提交记录(默认:3)
30
+
31
+ ## 🚀 工作流程
32
+
33
+ ### 1. 工程识别阶段
34
+ - 检测当前目录是否为Git仓库
35
+ - 识别项目名称和类型(Node.js、Java、Python等)
36
+ - 分析项目结构和模块划分
37
+
38
+ ### 2. Git提交分析阶段
39
+ - 获取指定时间范围内的Git提交记录
40
+ - 提取提交信息、作者、时间、修改文件
41
+ - 按月份对提交记录进行分组
42
+
43
+ ### 3. 功能点识别阶段
44
+ - 根据提交消息分析功能点类型
45
+ - 从文件路径提取模块层级信息
46
+ - 计算各功能点的权重和复杂度
47
+
48
+ ### 4. 结果输出阶段
49
+ - 按月份创建子文件夹(如:`7月`、`8月`、`9月`)
50
+ - 生成CSV格式的功能点统计报告
51
+ - 输出详细的统计分析摘要
52
+
53
+ ## 📊 CSV输出格式
54
+
55
+ ### 文件路径结构
56
+ ```
57
+ .aico/功能点/
58
+ ├── 7月/
59
+ │ └── <项目名>_功能点统计.csv
60
+ ├── 8月/
61
+ │ └── <项目名>_功能点统计.csv
62
+ └── 9月/
63
+ └── <项目名>_功能点统计.csv
64
+ ```
65
+
66
+ ### CSV字段规范
67
+ | 字段名 | 说明 | 必填 | 示例 |
68
+ |--------|------|------|------|
69
+ | 一级模块 | 功能所属的一级模块名称 | 是 | utils |
70
+ | 二级模块(选填) | 功能所属的二级模块名称 | 否 | commands |
71
+ | 三级模块(选填) | 功能所属的三级模块名称 | 否 | function-point |
72
+ | 四级模块(选填) | 功能所属的四级模块名称 | 否 | - |
73
+ | 功能项描述 | 功能的详细业务描述 | 是 | 新增功能点测算功能 |
74
+ | 功能点计数项名称 | 功能点的计数项名称 | 是 | 新增功能点测算功能_ILF |
75
+ | 类别 | 功能点类型分类 | 是 | 内部逻辑文件(ILF) |
76
+ | 未调整功能点数(UFP) | 根据类别计算的功能点数 | 是 | 10 |
77
+ | 复用程度 | 功能的复用程度 | 是 | 低 |
78
+ | 修改类型 | 功能的修改类型 | 是 | 新增 |
79
+ | 关联人 | 功能关联的责任人 | 是 | 50632783 |
80
+
81
+ ## 🎯 功能点分类规则
82
+
83
+ ### 内部逻辑文件(ILF)- 10点
84
+ - 新增界面或模块
85
+ - 创建核心业务对象
86
+ - 实现完整功能模块
87
+ - 添加新页面或视图
88
+
89
+ ### 外部查询(EQ)- 4点
90
+ - 数据查询操作
91
+ - 报表导出功能
92
+ - 条件筛选功能
93
+ - 搜索相关功能
94
+
95
+ ### 外部输入(EI)- 4点
96
+ - 数据修改操作
97
+ - 记录删除功能
98
+ - 信息更新功能
99
+ - 内容编辑功能
100
+
101
+ ### 外部输出(EO)- 5点
102
+ - 复杂数据处理和输出
103
+ - 带计算功能的结果输出
104
+ - 综合报告生成
105
+
106
+ ## 🔧 实现原理
107
+
108
+ ### 工程类型识别
109
+ 通过检查以下文件来识别项目类型:
110
+ - `package.json` → Node.js
111
+ - `pom.xml` → Java
112
+ - `requirements.txt` → Python
113
+ - `Cargo.toml` → Rust
114
+ - `go.mod` → Go
115
+ - `Gemfile` → Ruby
116
+
117
+ ### 模块层级提取
118
+ 从文件路径中提取模块层级信息:
119
+ ```
120
+ src/utils/commands/function-point.ts
121
+ ├── 一级模块: utils
122
+ ├── 二级模块: commands
123
+ └── 三级模块: function-point
124
+ ```
125
+
126
+ ### 功能点模式匹配
127
+ 通过正则表达式匹配提交消息中的关键词来识别功能点类型:
128
+ - ILF: `新增.*界面`、`创建.*模块`、`实现.*功能`
129
+ - EQ: `查询.*数据`、`导出.*报表`、`筛选.*条件`
130
+ - EI: `修改.*数据`、`删除.*记录`、`更新.*信息`
131
+
132
+ ## 📈 使用示例
133
+
134
+ ### 示例1:基本功能点测算
135
+ ```
136
+ 启动功能点测算智能体
137
+ ```
138
+
139
+ ### 示例2:分析最近6个月的数据
140
+ ```
141
+ /功能点测算 --months 6
142
+ ```
143
+
144
+ ### 示例3:输出示例结果
145
+ ```
146
+ 🔍 正在识别工程信息...
147
+ ✅ 工程识别完成:
148
+ 项目名称: aico-cli
149
+ 项目类型: Node.js
150
+
151
+ 📊 正在分析近3个月的Git提交记录...
152
+ 📈 正在分析功能点...
153
+ ✅ 2025-10: 分析 11 个提交,识别 3 个功能点
154
+ ✅ 2025-09: 分析 58 个提交,识别 31 个功能点
155
+ ✅ 2025-08: 分析 33 个提交,识别 28 个功能点
156
+
157
+ ✅ 功能点分析完成!
158
+ 总计识别: 62 个功能点
159
+ 输出目录: .aico/功能点
160
+
161
+ 📊 功能点统计摘要:
162
+ 总计功能点: 62
163
+ 按类型分布:
164
+ 内部逻辑文件(ILF): 62
165
+ 按月份分布:
166
+ 10月: 3
167
+ 9月: 31
168
+ 8月: 28
169
+ 按模块分布:
170
+ utils: 18
171
+ commands: 10
172
+ cli-setup: 17
173
+ ```
174
+
175
+ ## ⚡ 性能优化
176
+
177
+ ### 缓存机制
178
+ - Git提交记录缓存,避免重复查询
179
+ - 功能点分析结果缓存,提高效率
180
+
181
+ ### 并行处理
182
+ - 多线程处理月份分组
183
+ - 并行生成CSV文件
184
+
185
+ ### 内存优化
186
+ - 流式处理大量提交记录
187
+ - 分批处理功能点分析
188
+
189
+ ## 🛠️ 依赖要求
190
+
191
+ ### 系统要求
192
+ - Git (命令行工具)
193
+ - Node.js (用于运行环境)
194
+ - 足够的磁盘空间存储CSV文件
195
+
196
+ ### 项目要求
197
+ - 必须是Git仓库
198
+ - 有规范的提交消息格式
199
+ - 明确的模块目录结构
200
+
201
+ ## 🚨 注意事项
202
+
203
+ 1. **数据准确性**:功能点识别基于提交消息的关键词匹配,建议团队保持规范的提交消息格式
204
+ 2. **内存使用**:大型项目可能产生大量提交记录,建议适当调整分析的时间范围
205
+ 3. **权限要求**:确保有读取Git记录和写入`.aico`目录的权限
206
+ 4. **编码格式**:CSV文件使用UTF-8 with BOM格式,确保Excel正确打开
207
+
208
+ ## 🔄 更新日志
209
+
210
+ ### v1.0.0 (2025-10-17)
211
+ - ✅ 实现基础功能点测算功能
212
+ - ✅ 支持按月份文件夹输出CSV
213
+ - ✅ 添加多项目类型识别
214
+ - ✅ 实现智能模块层级提取
215
+ - ✅ 支持自定义时间范围分析
216
+
217
+ ---
218
+
219
+ 💡 **提示**: 使用前请确保当前目录是Git仓库,并且有规范的提交消息格式,这样可以得到更准确的功能点分析结果。