agent-ide 0.1.6 → 0.1.8

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 (98) hide show
  1. package/dist/core/analysis/complexity-analyzer.d.ts.map +1 -1
  2. package/dist/core/analysis/complexity-analyzer.js +3 -2
  3. package/dist/core/analysis/complexity-analyzer.js.map +1 -1
  4. package/dist/core/analysis/dead-code-detector.d.ts +34 -10
  5. package/dist/core/analysis/dead-code-detector.d.ts.map +1 -1
  6. package/dist/core/analysis/dead-code-detector.js +121 -82
  7. package/dist/core/analysis/dead-code-detector.js.map +1 -1
  8. package/dist/core/analysis/index.d.ts +1 -1
  9. package/dist/core/analysis/index.d.ts.map +1 -1
  10. package/dist/core/dependency/dependency-analyzer.d.ts.map +1 -1
  11. package/dist/core/dependency/dependency-analyzer.js +11 -4
  12. package/dist/core/dependency/dependency-analyzer.js.map +1 -1
  13. package/dist/core/indexing/index-engine.d.ts +9 -0
  14. package/dist/core/indexing/index-engine.d.ts.map +1 -1
  15. package/dist/core/indexing/index-engine.js +60 -1
  16. package/dist/core/indexing/index-engine.js.map +1 -1
  17. package/dist/core/move/import-resolver.d.ts +8 -0
  18. package/dist/core/move/import-resolver.d.ts.map +1 -1
  19. package/dist/core/move/import-resolver.js +62 -1
  20. package/dist/core/move/import-resolver.js.map +1 -1
  21. package/dist/core/move/move-service.d.ts +9 -0
  22. package/dist/core/move/move-service.d.ts.map +1 -1
  23. package/dist/core/move/move-service.js +105 -8
  24. package/dist/core/move/move-service.js.map +1 -1
  25. package/dist/core/move/types.d.ts +1 -1
  26. package/dist/core/move/types.d.ts.map +1 -1
  27. package/dist/core/refactor/extract-function.d.ts +26 -4
  28. package/dist/core/refactor/extract-function.d.ts.map +1 -1
  29. package/dist/core/refactor/extract-function.js +300 -48
  30. package/dist/core/refactor/extract-function.js.map +1 -1
  31. package/dist/core/rename/reference-updater.d.ts +10 -10
  32. package/dist/core/rename/reference-updater.d.ts.map +1 -1
  33. package/dist/core/rename/reference-updater.js +84 -79
  34. package/dist/core/rename/reference-updater.js.map +1 -1
  35. package/dist/core/rename/rename-engine.d.ts.map +1 -1
  36. package/dist/core/rename/rename-engine.js +68 -17
  37. package/dist/core/rename/rename-engine.js.map +1 -1
  38. package/dist/infrastructure/parser/base.d.ts +10 -0
  39. package/dist/infrastructure/parser/base.d.ts.map +1 -1
  40. package/dist/infrastructure/parser/base.js +39 -0
  41. package/dist/infrastructure/parser/base.js.map +1 -1
  42. package/dist/infrastructure/parser/interface.d.ts +12 -0
  43. package/dist/infrastructure/parser/interface.d.ts.map +1 -1
  44. package/dist/infrastructure/parser/interface.js +2 -0
  45. package/dist/infrastructure/parser/interface.js.map +1 -1
  46. package/dist/interfaces/cli/cli.d.ts +17 -1
  47. package/dist/interfaces/cli/cli.d.ts.map +1 -1
  48. package/dist/interfaces/cli/cli.js +220 -43
  49. package/dist/interfaces/cli/cli.js.map +1 -1
  50. package/dist/interfaces/cli/output-formatter.d.ts +55 -0
  51. package/dist/interfaces/cli/output-formatter.d.ts.map +1 -0
  52. package/dist/interfaces/cli/output-formatter.js +195 -0
  53. package/dist/interfaces/cli/output-formatter.js.map +1 -0
  54. package/dist/plugins/javascript/parser.d.ts +10 -0
  55. package/dist/plugins/javascript/parser.d.ts.map +1 -1
  56. package/dist/plugins/javascript/parser.js +62 -0
  57. package/dist/plugins/javascript/parser.js.map +1 -1
  58. package/dist/plugins/typescript/parser.d.ts +10 -0
  59. package/dist/plugins/typescript/parser.d.ts.map +1 -1
  60. package/dist/plugins/typescript/parser.js +59 -0
  61. package/dist/plugins/typescript/parser.js.map +1 -1
  62. package/package.json +8 -14
  63. package/dist/core/performance/analyzer.d.ts +0 -62
  64. package/dist/core/performance/analyzer.d.ts.map +0 -1
  65. package/dist/core/performance/analyzer.js +0 -378
  66. package/dist/core/performance/analyzer.js.map +0 -1
  67. package/dist/core/performance/cache-manager.d.ts +0 -161
  68. package/dist/core/performance/cache-manager.d.ts.map +0 -1
  69. package/dist/core/performance/cache-manager.js +0 -375
  70. package/dist/core/performance/cache-manager.js.map +0 -1
  71. package/dist/core/performance/index.d.ts +0 -14
  72. package/dist/core/performance/index.d.ts.map +0 -1
  73. package/dist/core/performance/index.js +0 -17
  74. package/dist/core/performance/index.js.map +0 -1
  75. package/dist/core/performance/interfaces.d.ts +0 -188
  76. package/dist/core/performance/interfaces.d.ts.map +0 -1
  77. package/dist/core/performance/interfaces.js +0 -17
  78. package/dist/core/performance/interfaces.js.map +0 -1
  79. package/dist/core/performance/memory-manager.d.ts +0 -176
  80. package/dist/core/performance/memory-manager.d.ts.map +0 -1
  81. package/dist/core/performance/memory-manager.js +0 -364
  82. package/dist/core/performance/memory-manager.js.map +0 -1
  83. package/dist/core/performance/monitor.d.ts +0 -92
  84. package/dist/core/performance/monitor.d.ts.map +0 -1
  85. package/dist/core/performance/monitor.js +0 -228
  86. package/dist/core/performance/monitor.js.map +0 -1
  87. package/dist/plugins/swift/index.d.ts +0 -11
  88. package/dist/plugins/swift/index.d.ts.map +0 -1
  89. package/dist/plugins/swift/index.js +0 -15
  90. package/dist/plugins/swift/index.js.map +0 -1
  91. package/dist/plugins/swift/parser.d.ts +0 -98
  92. package/dist/plugins/swift/parser.d.ts.map +0 -1
  93. package/dist/plugins/swift/parser.js +0 -612
  94. package/dist/plugins/swift/parser.js.map +0 -1
  95. package/dist/plugins/swift/types.d.ts +0 -196
  96. package/dist/plugins/swift/types.d.ts.map +0 -1
  97. package/dist/plugins/swift/types.js +0 -268
  98. package/dist/plugins/swift/types.js.map +0 -1
@@ -36,6 +36,8 @@ export function isParserPlugin(value) {
36
36
  return false;
37
37
  }
38
38
  }
39
+ // 可選方法不檢查(用於向後相容)
40
+ // getDefaultExcludePatterns 和 shouldIgnoreFile 是可選的
39
41
  return true;
40
42
  }
41
43
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/infrastructure/parser/interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6GH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,SAAS;IACT,IACE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACvC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EACtC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,eAAe;IACf,MAAM,eAAe,GAAG;QACtB,OAAO;QACP,gBAAgB;QAChB,gBAAgB;QAChB,qBAAqB;QACrB,QAAQ;QACR,iBAAiB;QACjB,gBAAgB;QAChB,YAAY;QACZ,UAAU;QACV,SAAS;KACV,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoB,EAAE,SAAiB;IACvE,OAAQ,MAAM,CAAC,mBAAgC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,QAAgB;IACrE,OAAQ,MAAM,CAAC,kBAA+B,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAuB,EACvB,QAAgB;IAEhB,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../../src/infrastructure/parser/interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6HH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,SAAS;IACT,IACE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACvC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EACtC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,eAAe;IACf,MAAM,eAAe,GAAG;QACtB,OAAO;QACP,gBAAgB;QAChB,gBAAgB;QAChB,qBAAqB;QACrB,QAAQ;QACR,iBAAiB;QACjB,gBAAgB;QAChB,YAAY;QACZ,UAAU;QACV,SAAS;KACV,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,oDAAoD;IAEpD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAoB,EAAE,SAAiB;IACvE,OAAQ,MAAM,CAAC,mBAAgC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,QAAgB;IACrE,OAAQ,MAAM,CAAC,kBAA+B,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAuB,EACvB,QAAgB;IAEhB,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -59,12 +59,28 @@ export declare class AgentIdeCLI {
59
59
  */
60
60
  private fileExists;
61
61
  /**
62
- * 套用程式碼編輯
62
+ * 正確套用程式碼編輯
63
+ */
64
+ private applyEditCorrectly;
65
+ /**
66
+ * 將行列位置轉換為字元偏移量
67
+ */
68
+ private positionToOffset;
69
+ /**
70
+ * @deprecated 使用 applyEditCorrectly 代替
63
71
  */
64
72
  private applyCodeEdit;
65
73
  /**
66
74
  * 獲取專案中的所有檔案
67
75
  */
68
76
  private getAllProjectFiles;
77
+ /**
78
+ * 讀取 tsconfig.json 的路徑別名設定
79
+ */
80
+ private loadPathAliases;
81
+ /**
82
+ * 建立輸出格式化器
83
+ */
84
+ private createFormatter;
69
85
  }
70
86
  //# sourceMappingURL=cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/interfaces/cli/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkBH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,kBAAkB,CAAC,CAAqB;IAChD,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,aAAa,CAAC,CAAgB;;IAQtC;;OAEG;IACG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,OAAO,CAAC,iBAAiB;IAiDzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,mBAAmB;YAuBb,kBAAkB;YA4BlB,mBAAmB;YAoInB,qBAAqB;YAmFrB,iBAAiB;YAwEjB,mBAAmB;IAoEjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAgD3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAMtB;;OAEG;IACH,OAAO,CAAC,cAAc;YAYR,oBAAoB;YAiLpB,iBAAiB;IAsG/B;;OAEG;YACW,yBAAyB;YAgBzB,wBAAwB;YA2BxB,uBAAuB;IAqBrC;;OAEG;YACW,UAAU;IASxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;YACW,kBAAkB;CAiCjC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/interfaces/cli/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiCH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,kBAAkB,CAAC,CAAqB;IAChD,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,aAAa,CAAC,CAAgB;;IAQtC;;OAEG;IACG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,OAAO,CAAC,iBAAiB;IAiDzB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,oBAAoB;IAiB5B,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,mBAAmB;YAuBb,kBAAkB;YA2DlB,mBAAmB;YAuHnB,qBAAqB;YAuHrB,iBAAiB;YA2EjB,mBAAmB;IAoEjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAgD3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAMtB;;OAEG;IACH,OAAO,CAAC,cAAc;YAYR,oBAAoB;YAiLpB,iBAAiB;IAsG/B;;OAEG;YACW,yBAAyB;YAgBzB,wBAAwB;YA2BxB,uBAAuB;IAqBrC;;OAEG;YACW,UAAU;IASxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;YACW,kBAAkB;IAkDhC;;OAEG;YACW,eAAe;IAgC7B;;OAEG;IACH,OAAO,CAAC,eAAe;CAqBxB"}
@@ -6,7 +6,6 @@ import { Command } from 'commander';
6
6
  import { IndexEngine } from '../../core/indexing/index-engine.js';
7
7
  import { DependencyAnalyzer } from '../../core/dependency/dependency-analyzer.js';
8
8
  import { RenameEngine } from '../../core/rename/rename-engine.js';
9
- import { ReferenceUpdater } from '../../core/rename/reference-updater.js';
10
9
  import { MoveService } from '../../core/move/index.js';
11
10
  import { SearchService } from '../../core/search/service.js';
12
11
  import { createIndexConfig } from '../../core/indexing/types.js';
@@ -15,8 +14,23 @@ import { TypeScriptParser } from '../../plugins/typescript/parser.js';
15
14
  import { JavaScriptParser } from '../../plugins/javascript/parser.js';
16
15
  import { ComplexityAnalyzer } from '../../core/analysis/complexity-analyzer.js';
17
16
  import { DeadCodeDetector } from '../../core/analysis/dead-code-detector.js';
17
+ import { OutputFormatter, OutputFormat } from './output-formatter.js';
18
18
  import * as fs from 'fs/promises';
19
+ import { readFileSync } from 'fs';
19
20
  import * as path from 'path';
21
+ import { fileURLToPath } from 'url';
22
+ // 讀取 package.json 版本
23
+ const __filename = fileURLToPath(import.meta.url);
24
+ const __dirname = path.dirname(__filename);
25
+ const packageJsonPath = path.resolve(__dirname, '../../../package.json');
26
+ let packageVersion = '0.1.0'; // fallback
27
+ try {
28
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
29
+ packageVersion = packageJson.version;
30
+ }
31
+ catch {
32
+ // 使用 fallback 版本
33
+ }
20
34
  export class AgentIdeCLI {
21
35
  program;
22
36
  indexEngine;
@@ -87,7 +101,7 @@ export class AgentIdeCLI {
87
101
  this.program
88
102
  .name('agent-ide')
89
103
  .description('程式碼智能工具集 for AI Agents')
90
- .version('0.1.0');
104
+ .version(packageVersion);
91
105
  this.setupIndexCommand();
92
106
  this.setupRenameCommand();
93
107
  this.setupRefactorCommand();
@@ -105,6 +119,7 @@ export class AgentIdeCLI {
105
119
  .option('-u, --update', '增量更新索引')
106
120
  .option('-e, --extensions <exts>', '包含的檔案副檔名', '.ts,.js,.tsx,.jsx')
107
121
  .option('-x, --exclude <patterns>', '排除模式', 'node_modules/**,*.test.*')
122
+ .option('--format <format>', '輸出格式 (markdown|plain|json|minimal)', 'plain')
108
123
  .action(async (options) => {
109
124
  await this.handleIndexCommand(options);
110
125
  });
@@ -120,6 +135,7 @@ export class AgentIdeCLI {
120
135
  .option('-o, --to <name>', '新名稱(--new-name 的別名)')
121
136
  .option('-p, --path <path>', '檔案或目錄路徑', '.')
122
137
  .option('--preview', '預覽變更而不執行')
138
+ .option('--format <format>', '輸出格式 (markdown|plain|json|minimal)', 'plain')
123
139
  .action(async (options) => {
124
140
  await this.handleRenameCommand(options);
125
141
  });
@@ -132,8 +148,10 @@ export class AgentIdeCLI {
132
148
  .option('-s, --start-line <line>', '起始行號')
133
149
  .option('-e, --end-line <line>', '結束行號')
134
150
  .option('-n, --function-name <name>', '函式名稱')
151
+ .option('-t, --target-file <file>', '目標檔案路徑(跨檔案提取)')
135
152
  .option('-p, --path <path>', '專案路徑', '.')
136
153
  .option('--preview', '預覽變更而不執行')
154
+ .option('--format <format>', '輸出格式 (markdown|plain|json|minimal)', 'plain')
137
155
  .action(async (action, options) => {
138
156
  await this.handleRefactorCommand(action, options);
139
157
  });
@@ -146,6 +164,7 @@ export class AgentIdeCLI {
146
164
  .argument('<target>', '目標路徑')
147
165
  .option('--update-imports', '自動更新 import 路徑', true)
148
166
  .option('--preview', '預覽變更而不執行')
167
+ .option('--format <format>', '輸出格式 (markdown|plain|json|minimal)', 'plain')
149
168
  .action(async (source, target, options) => {
150
169
  await this.handleMoveCommand(source, target, options);
151
170
  });
@@ -214,7 +233,12 @@ export class AgentIdeCLI {
214
233
  }
215
234
  // Command handlers
216
235
  async handleIndexCommand(options) {
217
- console.log('🔍 開始建立程式碼索引...');
236
+ const formatter = this.createFormatter(options.format);
237
+ const startTime = Date.now();
238
+ if (options.format !== 'json' && options.format !== 'minimal') {
239
+ console.log(formatter.formatTitle('程式碼索引', 1));
240
+ console.log('\n🔍 開始建立程式碼索引...\n');
241
+ }
218
242
  try {
219
243
  const config = createIndexConfig(options.path, {
220
244
  includeExtensions: options.extensions.split(','),
@@ -222,18 +246,43 @@ export class AgentIdeCLI {
222
246
  });
223
247
  this.indexEngine = new IndexEngine(config);
224
248
  if (options.update) {
225
- // TODO: 實作增量更新
226
- console.log('📝 執行增量索引更新...');
249
+ if (options.format !== 'json' && options.format !== 'minimal') {
250
+ console.log('📝 執行增量索引更新...');
251
+ }
227
252
  }
228
253
  else {
229
254
  await this.indexEngine.indexProject(options.path);
230
255
  }
231
256
  const stats = await this.indexEngine.getStats();
232
- console.log('✅ 索引完成!');
233
- console.log(`📊 統計: ${stats.totalFiles} 檔案, ${stats.totalSymbols} 符號`);
257
+ const duration = Date.now() - startTime;
258
+ const statsData = {
259
+ 檔案數: stats.totalFiles,
260
+ 符號數: stats.totalSymbols,
261
+ '執行時間(ms)': duration
262
+ };
263
+ if (options.format === 'json') {
264
+ console.log(formatter.formatSuccess('索引完成', statsData));
265
+ }
266
+ else if (options.format === 'minimal') {
267
+ console.log(`index:success files=${stats.totalFiles} symbols=${stats.totalSymbols} time=${duration}ms`);
268
+ }
269
+ else {
270
+ console.log('\n' + formatter.formatSuccess('索引完成'));
271
+ console.log('\n' + formatter.formatTitle('統計資訊', 2));
272
+ console.log(formatter.formatStats(statsData));
273
+ }
234
274
  }
235
275
  catch (error) {
236
- console.error('❌ 索引失敗:', error instanceof Error ? error.message : error);
276
+ const errorMessage = error instanceof Error ? error.message : String(error);
277
+ if (options.format === 'json') {
278
+ console.error(formatter.formatError(errorMessage));
279
+ }
280
+ else if (options.format === 'minimal') {
281
+ console.error(`index:error ${errorMessage}`);
282
+ }
283
+ else {
284
+ console.error('\n' + formatter.formatError(`索引失敗: ${errorMessage}`));
285
+ }
237
286
  if (process.env.NODE_ENV !== 'test') {
238
287
  process.exit(1);
239
288
  }
@@ -286,23 +335,12 @@ export class AgentIdeCLI {
286
335
  if (options.preview) {
287
336
  console.log('🔍 預覽變更...');
288
337
  try {
289
- // 確保有有效的檔案路徑
290
- let filePaths;
291
- if (targetSymbol.location && targetSymbol.location.filePath) {
292
- filePaths = [targetSymbol.location.filePath];
293
- }
294
- else {
295
- // 如果沒有 location,使用所有已索引的檔案
296
- const allFiles = this.indexEngine.getAllIndexedFiles();
297
- filePaths = allFiles.map(f => f.filePath);
298
- if (filePaths.length === 0) {
299
- filePaths = [options.path || process.cwd()];
300
- }
301
- }
338
+ // 取得所有專案檔案以進行跨檔案引用查找
339
+ const allProjectFiles = await this.getAllProjectFiles(options.path || workspacePath);
302
340
  const preview = await this.renameEngine.previewRename({
303
341
  symbol: targetSymbol,
304
342
  newName: to,
305
- filePaths
343
+ filePaths: allProjectFiles
306
344
  });
307
345
  console.log('📝 預計變更:');
308
346
  console.log(` 檔案數: ${preview.affectedFiles.length}`);
@@ -328,22 +366,24 @@ export class AgentIdeCLI {
328
366
  }
329
367
  // 3. 執行重新命名(處理跨檔案引用)
330
368
  console.log('✏️ 執行重新命名...');
331
- // 使用 ReferenceUpdater 來處理跨檔案引用
332
- const referenceUpdater = new ReferenceUpdater();
333
- const allProjectFiles = await this.getAllProjectFiles(options.path);
334
- const updateResult = await referenceUpdater.updateCrossFileReferences(targetSymbol, to, allProjectFiles);
335
- if (updateResult.success) {
369
+ // 取得所有專案檔案(使用與 preview 相同的邏輯)
370
+ const allProjectFiles = await this.getAllProjectFiles(options.path || workspacePath);
371
+ // 使用 renameEngine 執行重新命名(與 preview 使用相同的引擎)
372
+ const renameResult = await this.renameEngine.rename({
373
+ symbol: targetSymbol,
374
+ newName: to,
375
+ filePaths: allProjectFiles
376
+ });
377
+ if (renameResult.success) {
336
378
  console.log('✅ 重新命名成功!');
337
- console.log(`📊 統計: ${updateResult.updatedFiles.length} 檔案, ${updateResult.updatedFiles.reduce((sum, f) => sum + f.changes.length, 0)} 變更`);
338
- updateResult.updatedFiles.forEach(file => {
339
- file.changes.forEach(change => {
340
- console.log(` ✓ ${file.filePath}: "${change.oldText}" → "${change.newText}"`);
341
- });
379
+ console.log(`📊 統計: ${renameResult.affectedFiles.length} 檔案, ${renameResult.operations.length} 變更`);
380
+ renameResult.operations.forEach(operation => {
381
+ console.log(` ✓ ${operation.filePath}: "${operation.oldText}" → "${operation.newText}"`);
342
382
  });
343
383
  }
344
384
  else {
345
385
  console.error('❌ 重新命名失敗:');
346
- updateResult.errors?.forEach(error => {
386
+ renameResult.errors?.forEach(error => {
347
387
  console.error(` - ${error}`);
348
388
  });
349
389
  if (process.env.NODE_ENV !== 'test') {
@@ -389,18 +429,31 @@ export class AgentIdeCLI {
389
429
  const { FunctionExtractor } = await import('../../core/refactor/extract-function.js');
390
430
  const extractor = new FunctionExtractor();
391
431
  // 執行提取
392
- const result = await extractor.extract(code, range, {
432
+ const extractConfig = {
393
433
  functionName: options.functionName,
394
434
  generateComments: true,
395
435
  preserveFormatting: true,
396
- validateExtraction: true
397
- });
436
+ validateExtraction: true,
437
+ ...(options.targetFile ? {
438
+ targetFile: path.resolve(options.targetFile),
439
+ sourceFile: filePath
440
+ } : {})
441
+ };
442
+ const result = await extractor.extract(code, range, extractConfig);
398
443
  if (result.success) {
399
- // 套用編輯
444
+ // 套用編輯(按正確順序)
400
445
  let modifiedCode = code;
401
- result.edits.forEach(edit => {
402
- modifiedCode = this.applyCodeEdit(modifiedCode, edit);
403
- });
446
+ // 先處理所有 insert 類型(在檔案開頭插入函式定義)
447
+ const insertEdits = result.edits.filter(e => e.type === 'insert');
448
+ const replaceEdits = result.edits.filter(e => e.type === 'replace');
449
+ // 先應用 replace(替換選取範圍為函式呼叫)
450
+ for (const edit of replaceEdits) {
451
+ modifiedCode = this.applyEditCorrectly(modifiedCode, edit);
452
+ }
453
+ // 再應用 insert(插入函式定義)
454
+ for (const edit of insertEdits) {
455
+ modifiedCode = this.applyEditCorrectly(modifiedCode, edit);
456
+ }
404
457
  // 提取函式簽名(從修改後的程式碼中)
405
458
  const functionSignatureMatch = modifiedCode.match(new RegExp(`(async\\s+)?function\\s+${result.functionName}\\s*\\([^)]*\\)`));
406
459
  const functionSignature = functionSignatureMatch ? functionSignatureMatch[0] : `function ${result.functionName}`;
@@ -408,17 +461,35 @@ export class AgentIdeCLI {
408
461
  console.log(`📝 提取的函式: ${functionSignature}`);
409
462
  console.log(functionSignature);
410
463
  if (!options.preview) {
411
- // 寫入檔案
464
+ // 寫入原始檔案
412
465
  await fs.writeFile(filePath, modifiedCode, 'utf-8');
413
466
  console.log(`✓ 已更新 ${filePath}`);
467
+ // 如果是跨檔案提取,寫入目標檔案
468
+ if (result.targetFileContent && options.targetFile) {
469
+ const targetPath = path.resolve(options.targetFile);
470
+ // 確保目標目錄存在
471
+ const targetDir = path.dirname(targetPath);
472
+ await fs.mkdir(targetDir, { recursive: true });
473
+ // 寫入目標檔案
474
+ await fs.writeFile(targetPath, result.targetFileContent, 'utf-8');
475
+ console.log(`✓ 已建立/更新目標檔案 ${targetPath}`);
476
+ if (result.importStatement) {
477
+ console.log(`✓ 已加入 import: ${result.importStatement}`);
478
+ }
479
+ }
414
480
  }
415
481
  else {
416
482
  console.log('\n🔍 預覽模式 - 未寫入檔案');
417
483
  console.log(`📊 參數: ${result.parameters.map(p => p.name).join(', ')}`);
484
+ if (result.targetFileContent && options.targetFile) {
485
+ console.log(`📁 目標檔案: ${options.targetFile}`);
486
+ console.log(`📥 Import: ${result.importStatement || '(無)'}`);
487
+ }
418
488
  }
419
489
  }
420
490
  else {
421
491
  console.error('❌ 重構失敗:', result.errors.join(', '));
492
+ process.exitCode = 1;
422
493
  if (process.env.NODE_ENV !== 'test') {
423
494
  process.exit(1);
424
495
  }
@@ -457,8 +528,10 @@ export class AgentIdeCLI {
457
528
  }
458
529
  // 初始化移動服務
459
530
  if (!this.moveService) {
531
+ // 讀取 tsconfig.json 路徑別名
532
+ const pathAliases = await this.loadPathAliases(process.cwd());
460
533
  this.moveService = new MoveService({
461
- pathAliases: {},
534
+ pathAliases,
462
535
  supportedExtensions: ['.ts', '.tsx', '.js', '.jsx', '.vue'],
463
536
  includeNodeModules: false
464
537
  });
@@ -1004,7 +1077,43 @@ export class AgentIdeCLI {
1004
1077
  }
1005
1078
  }
1006
1079
  /**
1007
- * 套用程式碼編輯
1080
+ * 正確套用程式碼編輯
1081
+ */
1082
+ applyEditCorrectly(code, edit) {
1083
+ const lines = code.split('\n');
1084
+ switch (edit.type) {
1085
+ case 'replace': {
1086
+ // 計算起始和結束位置的偏移量
1087
+ const startOffset = this.positionToOffset(lines, edit.range.start);
1088
+ const endOffset = this.positionToOffset(lines, edit.range.end);
1089
+ return code.substring(0, startOffset) + edit.newText + code.substring(endOffset);
1090
+ }
1091
+ case 'insert': {
1092
+ const offset = this.positionToOffset(lines, edit.range.start);
1093
+ return code.substring(0, offset) + edit.newText + code.substring(offset);
1094
+ }
1095
+ case 'delete': {
1096
+ const startOffset = this.positionToOffset(lines, edit.range.start);
1097
+ const endOffset = this.positionToOffset(lines, edit.range.end);
1098
+ return code.substring(0, startOffset) + code.substring(endOffset);
1099
+ }
1100
+ default:
1101
+ return code;
1102
+ }
1103
+ }
1104
+ /**
1105
+ * 將行列位置轉換為字元偏移量
1106
+ */
1107
+ positionToOffset(lines, position) {
1108
+ let offset = 0;
1109
+ for (let i = 0; i < position.line - 1 && i < lines.length; i++) {
1110
+ offset += lines[i].length + 1; // +1 for newline
1111
+ }
1112
+ offset += position.column;
1113
+ return Math.min(offset, lines.join('\n').length);
1114
+ }
1115
+ /**
1116
+ * @deprecated 使用 applyEditCorrectly 代替
1008
1117
  */
1009
1118
  applyCodeEdit(code, edit) {
1010
1119
  const lines = code.split('\n');
@@ -1023,6 +1132,21 @@ export class AgentIdeCLI {
1023
1132
  const files = [];
1024
1133
  const allowedExtensions = ['.ts', '.tsx', '.js', '.jsx'];
1025
1134
  const excludePatterns = ['node_modules', 'dist', '.git', 'coverage'];
1135
+ // 檢查路徑是檔案還是目錄
1136
+ try {
1137
+ const stats = await fs.stat(projectPath);
1138
+ if (stats.isFile()) {
1139
+ // 如果是單一檔案,直接返回
1140
+ if (allowedExtensions.some(ext => projectPath.endsWith(ext))) {
1141
+ return [projectPath];
1142
+ }
1143
+ return [];
1144
+ }
1145
+ }
1146
+ catch (error) {
1147
+ // 路徑不存在
1148
+ return [];
1149
+ }
1026
1150
  async function walkDir(dir) {
1027
1151
  try {
1028
1152
  const entries = await fs.readdir(dir, { withFileTypes: true });
@@ -1050,5 +1174,58 @@ export class AgentIdeCLI {
1050
1174
  await walkDir(projectPath);
1051
1175
  return files;
1052
1176
  }
1177
+ /**
1178
+ * 讀取 tsconfig.json 的路徑別名設定
1179
+ */
1180
+ async loadPathAliases(projectRoot) {
1181
+ const pathAliases = {};
1182
+ try {
1183
+ const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
1184
+ const tsconfigContent = await fs.readFile(tsconfigPath, 'utf-8');
1185
+ const tsconfig = JSON.parse(tsconfigContent);
1186
+ if (tsconfig.compilerOptions?.paths) {
1187
+ const baseUrl = tsconfig.compilerOptions.baseUrl || '.';
1188
+ const basePath = path.resolve(projectRoot, baseUrl);
1189
+ for (const [alias, paths] of Object.entries(tsconfig.compilerOptions.paths)) {
1190
+ if (Array.isArray(paths) && paths.length > 0) {
1191
+ // 移除 /* 後綴
1192
+ const cleanAlias = alias.replace(/\/\*$/, '');
1193
+ const cleanPath = paths[0].replace(/\/\*$/, '');
1194
+ // 轉換為絕對路徑
1195
+ pathAliases[cleanAlias] = path.resolve(basePath, cleanPath);
1196
+ }
1197
+ }
1198
+ }
1199
+ }
1200
+ catch (error) {
1201
+ // tsconfig.json 不存在或解析失敗,使用空的路徑別名
1202
+ if (process.env.NODE_ENV !== 'test') {
1203
+ console.warn('⚠️ 無法讀取 tsconfig.json 路徑別名設定');
1204
+ }
1205
+ }
1206
+ return pathAliases;
1207
+ }
1208
+ /**
1209
+ * 建立輸出格式化器
1210
+ */
1211
+ createFormatter(format) {
1212
+ let outputFormat;
1213
+ switch (format?.toLowerCase()) {
1214
+ case 'markdown':
1215
+ outputFormat = OutputFormat.Markdown;
1216
+ break;
1217
+ case 'json':
1218
+ outputFormat = OutputFormat.Json;
1219
+ break;
1220
+ case 'minimal':
1221
+ outputFormat = OutputFormat.Minimal;
1222
+ break;
1223
+ case 'plain':
1224
+ default:
1225
+ outputFormat = OutputFormat.Plain;
1226
+ break;
1227
+ }
1228
+ return new OutputFormatter(outputFormat);
1229
+ }
1053
1230
  }
1054
1231
  //# sourceMappingURL=cli.js.map