@xdevops/issue-auto-finish 1.0.2 → 1.0.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 (133) hide show
  1. package/dist/KnowledgeAnalyzer-EZSJT2MJ.js +13 -0
  2. package/dist/KnowledgeAnalyzer-EZSJT2MJ.js.map +1 -0
  3. package/dist/KnowledgeStore-4ROC6F56.js +10 -0
  4. package/dist/KnowledgeStore-4ROC6F56.js.map +1 -0
  5. package/dist/ai-runner/AIRunner.d.ts +2 -0
  6. package/dist/ai-runner/AIRunner.d.ts.map +1 -1
  7. package/dist/ai-runner/BaseAIRunner.d.ts +9 -0
  8. package/dist/ai-runner/BaseAIRunner.d.ts.map +1 -1
  9. package/dist/ai-runner-RGAJPOOW.js +16 -0
  10. package/dist/ai-runner-RGAJPOOW.js.map +1 -0
  11. package/dist/analyze-I7UOJB4F.js +72 -0
  12. package/dist/analyze-I7UOJB4F.js.map +1 -0
  13. package/dist/chunk-3JUHZGX5.js +171 -0
  14. package/dist/chunk-3JUHZGX5.js.map +1 -0
  15. package/dist/chunk-5JYCGAU3.js +318 -0
  16. package/dist/chunk-5JYCGAU3.js.map +1 -0
  17. package/dist/chunk-5VUB3UUK.js +643 -0
  18. package/dist/chunk-5VUB3UUK.js.map +1 -0
  19. package/dist/{chunk-IDUKWCC2.js → chunk-C6ZJVIPZ.js} +1151 -80
  20. package/dist/chunk-C6ZJVIPZ.js.map +1 -0
  21. package/dist/{chunk-OWVT3Z34.js → chunk-JFYAXNNS.js} +121 -31
  22. package/dist/chunk-JFYAXNNS.js.map +1 -0
  23. package/dist/chunk-KISVPNSV.js +188 -0
  24. package/dist/chunk-KISVPNSV.js.map +1 -0
  25. package/dist/{chunk-I3T573SU.js → chunk-LEQYGOMJ.js} +65 -2
  26. package/dist/chunk-LEQYGOMJ.js.map +1 -0
  27. package/dist/{chunk-TBIEB3JY.js → chunk-N5YK6YVI.js} +592 -767
  28. package/dist/chunk-N5YK6YVI.js.map +1 -0
  29. package/dist/{chunk-RIUI4ROA.js → chunk-PECYMYAK.js} +2 -2
  30. package/dist/chunk-SWG2Y7YX.js +410 -0
  31. package/dist/chunk-SWG2Y7YX.js.map +1 -0
  32. package/dist/chunk-TZ6C7HL5.js +59 -0
  33. package/dist/chunk-TZ6C7HL5.js.map +1 -0
  34. package/dist/cli/commands/analyze.d.ts +8 -0
  35. package/dist/cli/commands/analyze.d.ts.map +1 -0
  36. package/dist/cli.js +67 -3
  37. package/dist/cli.js.map +1 -1
  38. package/dist/clients/GongfengClient.d.ts +5 -0
  39. package/dist/clients/GongfengClient.d.ts.map +1 -1
  40. package/dist/config-RI7NLDXI.js +7 -0
  41. package/dist/config-RI7NLDXI.js.map +1 -0
  42. package/dist/config.d.ts +19 -0
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/{doctor-B26Q6JWI.js → doctor-ZPGIBA5N.js} +3 -3
  45. package/dist/events/EventBus.d.ts +1 -1
  46. package/dist/events/EventBus.d.ts.map +1 -1
  47. package/dist/git/GitOperations.d.ts +12 -0
  48. package/dist/git/GitOperations.d.ts.map +1 -1
  49. package/dist/i18n/locales/en.d.ts.map +1 -1
  50. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +11 -5
  53. package/dist/{init-L3VIWCOV.js → init-LZGCIHE7.js} +8 -4
  54. package/dist/{init-L3VIWCOV.js.map → init-LZGCIHE7.js.map} +1 -1
  55. package/dist/knowledge/KnowledgeAnalyzer.d.ts +31 -0
  56. package/dist/knowledge/KnowledgeAnalyzer.d.ts.map +1 -0
  57. package/dist/knowledge/KnowledgeDefaults.d.ts +7 -0
  58. package/dist/knowledge/KnowledgeDefaults.d.ts.map +1 -0
  59. package/dist/knowledge/KnowledgeEntry.d.ts +30 -0
  60. package/dist/knowledge/KnowledgeEntry.d.ts.map +1 -0
  61. package/dist/knowledge/KnowledgeLoader.d.ts +18 -0
  62. package/dist/knowledge/KnowledgeLoader.d.ts.map +1 -0
  63. package/dist/knowledge/KnowledgeStore.d.ts +35 -0
  64. package/dist/knowledge/KnowledgeStore.d.ts.map +1 -0
  65. package/dist/knowledge/ProjectKnowledge.d.ts +79 -0
  66. package/dist/knowledge/ProjectKnowledge.d.ts.map +1 -0
  67. package/dist/knowledge/analyze-prompt.d.ts +2 -0
  68. package/dist/knowledge/analyze-prompt.d.ts.map +1 -0
  69. package/dist/knowledge/importers/GongfengExtractor.d.ts +27 -0
  70. package/dist/knowledge/importers/GongfengExtractor.d.ts.map +1 -0
  71. package/dist/knowledge/importers/IwikiImporter.d.ts +21 -0
  72. package/dist/knowledge/importers/IwikiImporter.d.ts.map +1 -0
  73. package/dist/knowledge/index.d.ts +12 -0
  74. package/dist/knowledge/index.d.ts.map +1 -0
  75. package/dist/lib.js +19 -10
  76. package/dist/orchestrator/PipelineOrchestrator.d.ts +5 -1
  77. package/dist/orchestrator/PipelineOrchestrator.d.ts.map +1 -1
  78. package/dist/phases/BasePhase.d.ts.map +1 -1
  79. package/dist/poller/IssuePoller.d.ts +5 -0
  80. package/dist/poller/IssuePoller.d.ts.map +1 -1
  81. package/dist/prompts/chat-templates.d.ts +4 -0
  82. package/dist/prompts/chat-templates.d.ts.map +1 -0
  83. package/dist/prompts/templates.d.ts +11 -0
  84. package/dist/prompts/templates.d.ts.map +1 -1
  85. package/dist/rules/RuleResolver.d.ts +4 -0
  86. package/dist/rules/RuleResolver.d.ts.map +1 -1
  87. package/dist/run.js +11 -5
  88. package/dist/run.js.map +1 -1
  89. package/dist/services/ChatService.d.ts +39 -0
  90. package/dist/services/ChatService.d.ts.map +1 -0
  91. package/dist/shutdown/ShutdownSignal.d.ts +3 -0
  92. package/dist/shutdown/ShutdownSignal.d.ts.map +1 -0
  93. package/dist/{start-TVN4SS6E.js → start-NMQHUKGF.js} +1 -1
  94. package/dist/tracker/IssueState.d.ts +1 -0
  95. package/dist/tracker/IssueState.d.ts.map +1 -1
  96. package/dist/tracker/IssueTracker.d.ts +2 -0
  97. package/dist/tracker/IssueTracker.d.ts.map +1 -1
  98. package/dist/updater/AutoUpdater.d.ts +33 -0
  99. package/dist/updater/AutoUpdater.d.ts.map +1 -0
  100. package/dist/updater/UpdateExecutor.d.ts +7 -0
  101. package/dist/updater/UpdateExecutor.d.ts.map +1 -0
  102. package/dist/updater/VersionChecker.d.ts +22 -0
  103. package/dist/updater/VersionChecker.d.ts.map +1 -0
  104. package/dist/web/WebServer.d.ts +4 -0
  105. package/dist/web/WebServer.d.ts.map +1 -1
  106. package/dist/web/routes/api.d.ts +4 -0
  107. package/dist/web/routes/api.d.ts.map +1 -1
  108. package/dist/web/routes/chat.d.ts +7 -0
  109. package/dist/web/routes/chat.d.ts.map +1 -0
  110. package/dist/web/routes/knowledge.d.ts +13 -0
  111. package/dist/web/routes/knowledge.d.ts.map +1 -0
  112. package/dist/web/routes/setup.d.ts.map +1 -1
  113. package/dist/webhook/CommandExecutor.d.ts +4 -0
  114. package/dist/webhook/CommandExecutor.d.ts.map +1 -1
  115. package/dist/webhook/CommandParser.d.ts +2 -2
  116. package/dist/webhook/CommandParser.d.ts.map +1 -1
  117. package/dist/webhook/WebhookHandler.d.ts +8 -0
  118. package/dist/webhook/WebhookHandler.d.ts.map +1 -1
  119. package/dist/webhook/WebhookServer.d.ts +2 -0
  120. package/dist/webhook/WebhookServer.d.ts.map +1 -1
  121. package/package.json +4 -2
  122. package/src/web/frontend/dist/assets/index-AcJ0lPIv.js +67 -0
  123. package/src/web/frontend/dist/assets/index-BbRt5BAr.css +1 -0
  124. package/src/web/frontend/dist/index.html +2 -2
  125. package/dist/chunk-I3T573SU.js.map +0 -1
  126. package/dist/chunk-IDUKWCC2.js.map +0 -1
  127. package/dist/chunk-OWVT3Z34.js.map +0 -1
  128. package/dist/chunk-TBIEB3JY.js.map +0 -1
  129. package/src/web/frontend/dist/assets/index-CQdlU9PE.js +0 -65
  130. package/src/web/frontend/dist/assets/index-CgMEkyZJ.css +0 -1
  131. /package/dist/{chunk-RIUI4ROA.js.map → chunk-PECYMYAK.js.map} +0 -0
  132. /package/dist/{doctor-B26Q6JWI.js.map → doctor-ZPGIBA5N.js.map} +0 -0
  133. /package/dist/{start-TVN4SS6E.js.map → start-NMQHUKGF.js.map} +0 -0
@@ -0,0 +1,13 @@
1
+ import {
2
+ analyze,
3
+ analyzeIncremental,
4
+ collectStaticInfo
5
+ } from "./chunk-5VUB3UUK.js";
6
+ import "./chunk-5JYCGAU3.js";
7
+ import "./chunk-TZ6C7HL5.js";
8
+ export {
9
+ analyze,
10
+ analyzeIncremental,
11
+ collectStaticInfo
12
+ };
13
+ //# sourceMappingURL=KnowledgeAnalyzer-EZSJT2MJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ import {
2
+ KnowledgeStore,
3
+ projectKnowledgeToMarkdown
4
+ } from "./chunk-5JYCGAU3.js";
5
+ import "./chunk-TZ6C7HL5.js";
6
+ export {
7
+ KnowledgeStore,
8
+ projectKnowledgeToMarkdown
9
+ };
10
+ //# sourceMappingURL=KnowledgeStore-4ROC6F56.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -23,5 +23,7 @@ export interface RunResult {
23
23
  }
24
24
  export interface AIRunner {
25
25
  run(options: RunOptions): Promise<RunResult>;
26
+ killAll(): void;
27
+ killByWorkDir(targetWorkDir: string): number;
26
28
  }
27
29
  //# sourceMappingURL=AIRunner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AIRunner.d.ts","sourceRoot":"","sources":["../../src/ai-runner/AIRunner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CAC9C"}
1
+ {"version":3,"file":"AIRunner.d.ts","sourceRoot":"","sources":["../../src/ai-runner/AIRunner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC;IAChB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9C"}
@@ -4,7 +4,11 @@ export declare abstract class BaseAIRunner {
4
4
  protected abstract getBinary(): string;
5
5
  protected abstract buildArgs(options: RunOptions): string[];
6
6
  protected abstract getSpawnOptions(options: RunOptions): SpawnOptions;
7
+ private activeChildren;
7
8
  run(options: RunOptions): Promise<RunResult>;
9
+ killAll(): void;
10
+ killByWorkDir(targetWorkDir: string): number;
11
+ private forceKillChild;
8
12
  private emitStreamLine;
9
13
  /**
10
14
  * Handles both stream-json (one JSON object per line) and legacy single-JSON formats.
@@ -13,6 +17,11 @@ export declare abstract class BaseAIRunner {
13
17
  output: string;
14
18
  resolvedSessionId?: string;
15
19
  };
20
+ /**
21
+ * Extract plain text from assistant events as fallback when result.result is empty.
22
+ * Looks for message.content[].text in assistant-type events.
23
+ */
24
+ private extractAssistantText;
16
25
  private summarizeStreamEvents;
17
26
  private tryParseStreamJson;
18
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BaseAIRunner.d.ts","sourceRoot":"","sources":["../../src/ai-runner/BaseAIRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAe,MAAM,eAAe,CAAC;AAIxE,8BAAsB,YAAY;IAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,IAAI,MAAM;IACtC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE;IAC3D,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,YAAY;IAE/D,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAyGlD,OAAO,CAAC,cAAc;IAatB;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE;IA8CnG,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,kBAAkB;CAc3B"}
1
+ {"version":3,"file":"BaseAIRunner.d.ts","sourceRoot":"","sources":["../../src/ai-runner/BaseAIRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGjF,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAe,MAAM,eAAe,CAAC;AAWxE,8BAAsB,YAAY;IAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,IAAI,MAAM;IACtC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,EAAE;IAC3D,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,YAAY;IAErE,OAAO,CAAC,cAAc,CAAwC;IAExD,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IA2HlD,OAAO,IAAI,IAAI;IAOf,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAc5C,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,cAAc;IAatB;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE;IAoDnG;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,kBAAkB;CAc3B"}
@@ -0,0 +1,16 @@
1
+ import {
2
+ BaseAIRunner,
3
+ ClaudeInternalRunner,
4
+ CodebuddyRunner,
5
+ CursorAgentRunner,
6
+ createAIRunner
7
+ } from "./chunk-SWG2Y7YX.js";
8
+ import "./chunk-TZ6C7HL5.js";
9
+ export {
10
+ BaseAIRunner,
11
+ ClaudeInternalRunner,
12
+ CodebuddyRunner,
13
+ CursorAgentRunner,
14
+ createAIRunner
15
+ };
16
+ //# sourceMappingURL=ai-runner-RGAJPOOW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,72 @@
1
+ import {
2
+ analyze
3
+ } from "./chunk-5VUB3UUK.js";
4
+ import "./chunk-5JYCGAU3.js";
5
+ import {
6
+ loadConfig
7
+ } from "./chunk-KISVPNSV.js";
8
+ import {
9
+ createAIRunner
10
+ } from "./chunk-SWG2Y7YX.js";
11
+ import "./chunk-TZ6C7HL5.js";
12
+
13
+ // src/cli/commands/analyze.ts
14
+ import path from "path";
15
+ import fs from "fs";
16
+ import os from "os";
17
+ function resolveOutputPath(explicitOutput) {
18
+ if (explicitOutput) return path.resolve(explicitOutput);
19
+ const envConfigPath = process.env.IAF_CONFIG_PATH;
20
+ if (envConfigPath) {
21
+ return path.join(path.dirname(envConfigPath), "knowledge.json");
22
+ }
23
+ const cwdCandidate = path.resolve(process.cwd(), "knowledge.json");
24
+ const globalCandidate = path.join(os.homedir(), ".issue-auto-finish", "knowledge.json");
25
+ if (fs.existsSync(path.resolve(process.cwd(), ".env"))) {
26
+ return cwdCandidate;
27
+ }
28
+ return globalCandidate;
29
+ }
30
+ async function analyzeCommand(opts) {
31
+ const config = loadConfig();
32
+ const workDir = opts.dir ? path.resolve(opts.dir) : config.project.workDir;
33
+ const outputPath = resolveOutputPath(opts.output);
34
+ if (fs.existsSync(outputPath) && !opts.force) {
35
+ console.log(`
36
+ knowledge.json already exists at: ${outputPath}`);
37
+ console.log(" Use --force to overwrite.\n");
38
+ process.exitCode = 1;
39
+ return;
40
+ }
41
+ console.log(`
42
+ Analyzing project: ${workDir}`);
43
+ console.log(` Output: ${outputPath}
44
+ `);
45
+ const aiRunner = createAIRunner(config.ai);
46
+ try {
47
+ const knowledge = await analyze({
48
+ workDir,
49
+ aiRunner,
50
+ outputPath
51
+ });
52
+ console.log(" Analysis complete!\n");
53
+ console.log(` Language: ${knowledge.structure.primaryLanguage}`);
54
+ console.log(` Frameworks: ${knowledge.structure.frameworks.join(", ") || "none"}`);
55
+ console.log(` Monorepo: ${knowledge.structure.isMonorepo ? "yes" : "no"}`);
56
+ console.log(` Pkg Manager: ${knowledge.toolchain.packageManager}`);
57
+ console.log(` Triggers: ${knowledge.ruleTriggers.length} rule(s)`);
58
+ console.log(` Known Issues: ${knowledge.knownIssues.length}`);
59
+ console.log(`
60
+ Saved to: ${outputPath}
61
+ `);
62
+ } catch (err) {
63
+ console.error(`
64
+ Analysis failed: ${err.message}
65
+ `);
66
+ process.exitCode = 1;
67
+ }
68
+ }
69
+ export {
70
+ analyzeCommand
71
+ };
72
+ //# sourceMappingURL=analyze-I7UOJB4F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/analyze.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { loadConfig } from '../../config.js';\nimport { createAIRunner } from '../../ai-runner/index.js';\nimport { analyze } from '../../knowledge/KnowledgeAnalyzer.js';\n\ninterface AnalyzeCommandOptions {\n dir?: string;\n output?: string;\n force?: boolean;\n}\n\nfunction resolveOutputPath(explicitOutput?: string): string {\n if (explicitOutput) return path.resolve(explicitOutput);\n\n // Same search order as .env\n const envConfigPath = process.env.IAF_CONFIG_PATH;\n if (envConfigPath) {\n return path.join(path.dirname(envConfigPath), 'knowledge.json');\n }\n\n const cwdCandidate = path.resolve(process.cwd(), 'knowledge.json');\n const globalCandidate = path.join(os.homedir(), '.issue-auto-finish', 'knowledge.json');\n\n // Prefer cwd if .env exists there, otherwise global\n if (fs.existsSync(path.resolve(process.cwd(), '.env'))) {\n return cwdCandidate;\n }\n\n return globalCandidate;\n}\n\nexport async function analyzeCommand(opts: AnalyzeCommandOptions): Promise<void> {\n const config = loadConfig();\n const workDir = opts.dir ? path.resolve(opts.dir) : config.project.workDir;\n const outputPath = resolveOutputPath(opts.output);\n\n if (fs.existsSync(outputPath) && !opts.force) {\n console.log(`\\n knowledge.json already exists at: ${outputPath}`);\n console.log(' Use --force to overwrite.\\n');\n process.exitCode = 1;\n return;\n }\n\n console.log(`\\n Analyzing project: ${workDir}`);\n console.log(` Output: ${outputPath}\\n`);\n\n const aiRunner = createAIRunner(config.ai);\n\n try {\n const knowledge = await analyze({\n workDir,\n aiRunner,\n outputPath,\n });\n\n console.log(' Analysis complete!\\n');\n console.log(` Language: ${knowledge.structure.primaryLanguage}`);\n console.log(` Frameworks: ${knowledge.structure.frameworks.join(', ') || 'none'}`);\n console.log(` Monorepo: ${knowledge.structure.isMonorepo ? 'yes' : 'no'}`);\n console.log(` Pkg Manager: ${knowledge.toolchain.packageManager}`);\n console.log(` Triggers: ${knowledge.ruleTriggers.length} rule(s)`);\n console.log(` Known Issues: ${knowledge.knownIssues.length}`);\n console.log(`\\n Saved to: ${outputPath}\\n`);\n } catch (err) {\n console.error(`\\n Analysis failed: ${(err as Error).message}\\n`);\n process.exitCode = 1;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,QAAQ;AAWf,SAAS,kBAAkB,gBAAiC;AAC1D,MAAI,eAAgB,QAAO,KAAK,QAAQ,cAAc;AAGtD,QAAM,gBAAgB,QAAQ,IAAI;AAClC,MAAI,eAAe;AACjB,WAAO,KAAK,KAAK,KAAK,QAAQ,aAAa,GAAG,gBAAgB;AAAA,EAChE;AAEA,QAAM,eAAe,KAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB;AACjE,QAAM,kBAAkB,KAAK,KAAK,GAAG,QAAQ,GAAG,sBAAsB,gBAAgB;AAGtF,MAAI,GAAG,WAAW,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM,CAAC,GAAG;AACtD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,eAAsB,eAAe,MAA4C;AAC/E,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,KAAK,MAAM,KAAK,QAAQ,KAAK,GAAG,IAAI,OAAO,QAAQ;AACnE,QAAM,aAAa,kBAAkB,KAAK,MAAM;AAEhD,MAAI,GAAG,WAAW,UAAU,KAAK,CAAC,KAAK,OAAO;AAC5C,YAAQ,IAAI;AAAA,sCAAyC,UAAU,EAAE;AACjE,YAAQ,IAAI,+BAA+B;AAC3C,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,uBAA0B,OAAO,EAAE;AAC/C,UAAQ,IAAI,aAAa,UAAU;AAAA,CAAI;AAEvC,QAAM,WAAW,eAAe,OAAO,EAAE;AAEzC,MAAI;AACF,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,YAAQ,IAAI,wBAAwB;AACpC,YAAQ,IAAI,kBAAkB,UAAU,UAAU,eAAe,EAAE;AACnE,YAAQ,IAAI,kBAAkB,UAAU,UAAU,WAAW,KAAK,IAAI,KAAK,MAAM,EAAE;AACnF,YAAQ,IAAI,kBAAkB,UAAU,UAAU,aAAa,QAAQ,IAAI,EAAE;AAC7E,YAAQ,IAAI,kBAAkB,UAAU,UAAU,cAAc,EAAE;AAClE,YAAQ,IAAI,kBAAkB,UAAU,aAAa,MAAM,UAAU;AACrE,YAAQ,IAAI,mBAAmB,UAAU,YAAY,MAAM,EAAE;AAC7D,YAAQ,IAAI;AAAA,cAAiB,UAAU;AAAA,CAAI;AAAA,EAC7C,SAAS,KAAK;AACZ,YAAQ,MAAM;AAAA,qBAAyB,IAAc,OAAO;AAAA,CAAI;AAChE,YAAQ,WAAW;AAAA,EACrB;AACF;","names":[]}
@@ -0,0 +1,171 @@
1
+ import {
2
+ KNOWLEDGE_DEFAULTS
3
+ } from "./chunk-5VUB3UUK.js";
4
+ import {
5
+ logger
6
+ } from "./chunk-TZ6C7HL5.js";
7
+
8
+ // src/knowledge/KnowledgeLoader.ts
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import os from "os";
12
+ var logger2 = logger.child("KnowledgeLoader");
13
+ var _cachedKnowledge;
14
+ function resolveKnowledgePath(explicitPath) {
15
+ if (explicitPath) {
16
+ return fs.existsSync(explicitPath) ? explicitPath : null;
17
+ }
18
+ const envConfigPath = process.env.IAF_CONFIG_PATH;
19
+ if (envConfigPath) {
20
+ const candidate = path.join(path.dirname(envConfigPath), "knowledge.json");
21
+ if (fs.existsSync(candidate)) return candidate;
22
+ }
23
+ const projectDir = path.resolve(path.dirname(new URL(import.meta.url).pathname), "../..");
24
+ const projectCandidate = path.join(projectDir, "knowledge.json");
25
+ if (fs.existsSync(projectCandidate)) return projectCandidate;
26
+ const cwdCandidate = path.resolve(process.cwd(), "knowledge.json");
27
+ if (fs.existsSync(cwdCandidate)) return cwdCandidate;
28
+ const globalCandidate = path.join(os.homedir(), ".issue-auto-finish", "knowledge.json");
29
+ if (fs.existsSync(globalCandidate)) return globalCandidate;
30
+ return null;
31
+ }
32
+ function deepMerge(defaults, overrides) {
33
+ const result = { ...defaults };
34
+ for (const key of Object.keys(overrides)) {
35
+ const val = overrides[key];
36
+ if (val !== null && val !== void 0) {
37
+ if (typeof val === "object" && !Array.isArray(val) && typeof result[key] === "object" && !Array.isArray(result[key])) {
38
+ result[key] = deepMerge(result[key], val);
39
+ } else {
40
+ result[key] = val;
41
+ }
42
+ }
43
+ }
44
+ return result;
45
+ }
46
+ function loadKnowledge(explicitPath) {
47
+ const filePath = resolveKnowledgePath(explicitPath);
48
+ if (!filePath) {
49
+ logger2.info("No knowledge.json found, will use defaults");
50
+ _cachedKnowledge = null;
51
+ return null;
52
+ }
53
+ try {
54
+ const raw = fs.readFileSync(filePath, "utf-8");
55
+ const parsed = JSON.parse(raw);
56
+ const merged = deepMerge(
57
+ KNOWLEDGE_DEFAULTS,
58
+ parsed
59
+ );
60
+ _cachedKnowledge = merged;
61
+ logger2.info("Knowledge loaded", { path: filePath, version: merged.version });
62
+ return merged;
63
+ } catch (err) {
64
+ logger2.warn("Failed to load knowledge.json, will use defaults", {
65
+ path: filePath,
66
+ error: err.message
67
+ });
68
+ _cachedKnowledge = null;
69
+ return null;
70
+ }
71
+ }
72
+ function getProjectKnowledge() {
73
+ if (_cachedKnowledge === void 0) {
74
+ return loadKnowledge();
75
+ }
76
+ return _cachedKnowledge;
77
+ }
78
+
79
+ // src/knowledge/importers/IwikiImporter.ts
80
+ import TurndownService from "turndown";
81
+ var logger3 = logger.child("IwikiImporter");
82
+ var IwikiImporter = class {
83
+ store;
84
+ config;
85
+ turndown;
86
+ constructor(store, config = {}) {
87
+ this.store = store;
88
+ this.config = config;
89
+ this.turndown = new TurndownService({
90
+ headingStyle: "atx",
91
+ codeBlockStyle: "fenced"
92
+ });
93
+ }
94
+ async importFromUrl(url) {
95
+ logger3.info("Importing iwiki page", { url });
96
+ const html = await this.fetchPage(url);
97
+ const { title, markdown } = this.extractContent(html);
98
+ const entry = this.store.create({
99
+ type: "iwiki",
100
+ title: title || this.titleFromUrl(url),
101
+ content: markdown,
102
+ tags: ["iwiki"],
103
+ source: { url, kind: "iwiki-page", syncEnabled: true, lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() }
104
+ });
105
+ logger3.info("iwiki page imported", { id: entry.id, title: entry.title });
106
+ return entry;
107
+ }
108
+ async sync(entryId) {
109
+ const entry = this.store.get(entryId);
110
+ if (!entry) throw new Error("Knowledge entry not found: " + entryId);
111
+ if (!entry.source?.url) throw new Error("Entry has no source URL");
112
+ logger3.info("Syncing iwiki page", { id: entryId, url: entry.source.url });
113
+ const html = await this.fetchPage(entry.source.url);
114
+ const { title, markdown } = this.extractContent(html);
115
+ const updated = this.store.update(entryId, {
116
+ title: title || entry.title,
117
+ content: markdown,
118
+ source: { ...entry.source, lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() }
119
+ });
120
+ logger3.info("iwiki page synced", { id: entryId });
121
+ return updated;
122
+ }
123
+ extractContent(html) {
124
+ const titleRe = /<title[^>]*>([^<]+)<\/title>/i;
125
+ const titleMatch = html.match(titleRe);
126
+ const title = titleMatch ? titleMatch[1].trim() : "";
127
+ let bodyHtml = html;
128
+ const bodyRe = /<body[^>]*>([\s\S]*?)<\/body>/i;
129
+ const bodyMatch = html.match(bodyRe);
130
+ if (bodyMatch) bodyHtml = bodyMatch[1];
131
+ bodyHtml = bodyHtml.replace(/<script[\s\S]*?<\/script>/gi, "");
132
+ bodyHtml = bodyHtml.replace(/<style[\s\S]*?<\/style>/gi, "");
133
+ bodyHtml = bodyHtml.replace(/<nav[\s\S]*?<\/nav>/gi, "");
134
+ bodyHtml = bodyHtml.replace(/<header[\s\S]*?<\/header>/gi, "");
135
+ bodyHtml = bodyHtml.replace(/<footer[\s\S]*?<\/footer>/gi, "");
136
+ const mainRe = /<main[^>]*>([\s\S]*?)<\/main>/i;
137
+ const articleRe = /<article[^>]*>([\s\S]*?)<\/article>/i;
138
+ const contentRe = /class="[^"]*content[^"]*"[^>]*>([\s\S]*?)<\/div>/i;
139
+ const mainMatch = bodyHtml.match(mainRe) || bodyHtml.match(articleRe) || bodyHtml.match(contentRe);
140
+ if (mainMatch) bodyHtml = mainMatch[1];
141
+ const markdown = this.turndown.turndown(bodyHtml).trim();
142
+ return { title, markdown };
143
+ }
144
+ async fetchPage(url) {
145
+ const headers = {};
146
+ if (this.config.authCookie) headers["Cookie"] = this.config.authCookie;
147
+ if (this.config.authToken) headers["Authorization"] = "Bearer " + this.config.authToken;
148
+ const resp = await fetch(url, { headers, redirect: "follow" });
149
+ if (!resp.ok) throw new Error("Failed to fetch iwiki page: HTTP " + resp.status);
150
+ return resp.text();
151
+ }
152
+ titleFromUrl(url) {
153
+ try {
154
+ const u = new URL(url);
155
+ const segments = u.pathname.split("/").filter(Boolean);
156
+ return decodeURIComponent(segments[segments.length - 1] || u.hostname);
157
+ } catch {
158
+ return url;
159
+ }
160
+ }
161
+ };
162
+
163
+ // src/knowledge/importers/GongfengExtractor.ts
164
+ var logger4 = logger.child("GongfengExtractor");
165
+
166
+ export {
167
+ loadKnowledge,
168
+ getProjectKnowledge,
169
+ IwikiImporter
170
+ };
171
+ //# sourceMappingURL=chunk-3JUHZGX5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/knowledge/KnowledgeLoader.ts","../src/knowledge/importers/IwikiImporter.ts","../src/knowledge/importers/GongfengExtractor.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logger as rootLogger } from '../logger.js';\nimport type { ProjectKnowledge } from './ProjectKnowledge.js';\nimport { KNOWLEDGE_DEFAULTS } from './KnowledgeDefaults.js';\n\nconst logger = rootLogger.child('KnowledgeLoader');\n\nlet _cachedKnowledge: ProjectKnowledge | null | undefined;\n\nfunction resolveKnowledgePath(explicitPath?: string): string | null {\n if (explicitPath) {\n return fs.existsSync(explicitPath) ? explicitPath : null;\n }\n\n // Check IAF_CONFIG_PATH dir\n const envConfigPath = process.env.IAF_CONFIG_PATH;\n if (envConfigPath) {\n const candidate = path.join(path.dirname(envConfigPath), 'knowledge.json');\n if (fs.existsSync(candidate)) return candidate;\n }\n\n // Check project directory (relative to src/../)\n const projectDir = path.resolve(path.dirname(new URL(import.meta.url).pathname), '../..');\n const projectCandidate = path.join(projectDir, 'knowledge.json');\n if (fs.existsSync(projectCandidate)) return projectCandidate;\n\n // Check cwd\n const cwdCandidate = path.resolve(process.cwd(), 'knowledge.json');\n if (fs.existsSync(cwdCandidate)) return cwdCandidate;\n\n // Check global config dir\n const globalCandidate = path.join(os.homedir(), '.issue-auto-finish', 'knowledge.json');\n if (fs.existsSync(globalCandidate)) return globalCandidate;\n\n return null;\n}\n\nfunction deepMerge(defaults: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown> {\n const result = { ...defaults };\n for (const key of Object.keys(overrides)) {\n const val = overrides[key];\n if (val !== null && val !== undefined) {\n if (typeof val === 'object' && !Array.isArray(val) && typeof result[key] === 'object' && !Array.isArray(result[key])) {\n result[key] = deepMerge(result[key] as Record<string, unknown>, val as Record<string, unknown>);\n } else {\n result[key] = val;\n }\n }\n }\n return result;\n}\n\n/**\n * Load knowledge from knowledge.json, merging with defaults for any missing fields.\n */\nexport function loadKnowledge(explicitPath?: string): ProjectKnowledge | null {\n const filePath = resolveKnowledgePath(explicitPath);\n if (!filePath) {\n logger.info('No knowledge.json found, will use defaults');\n _cachedKnowledge = null;\n return null;\n }\n\n try {\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<ProjectKnowledge>;\n const merged = deepMerge(\n KNOWLEDGE_DEFAULTS as unknown as Record<string, unknown>,\n parsed as unknown as Record<string, unknown>,\n ) as unknown as ProjectKnowledge;\n _cachedKnowledge = merged;\n logger.info('Knowledge loaded', { path: filePath, version: merged.version });\n return merged;\n } catch (err) {\n logger.warn('Failed to load knowledge.json, will use defaults', {\n path: filePath,\n error: (err as Error).message,\n });\n _cachedKnowledge = null;\n return null;\n }\n}\n\n/**\n * Get cached knowledge (or null if not loaded or file not found).\n */\nexport function getProjectKnowledge(): ProjectKnowledge | null {\n if (_cachedKnowledge === undefined) {\n return loadKnowledge();\n }\n return _cachedKnowledge;\n}\n\n/**\n * Clear cache and reload.\n */\nexport function reloadKnowledge(explicitPath?: string): ProjectKnowledge | null {\n _cachedKnowledge = undefined;\n return loadKnowledge(explicitPath);\n}\n\n/**\n * Reset the cache (for testing).\n */\nexport function resetKnowledgeCache(): void {\n _cachedKnowledge = undefined;\n}\n","import TurndownService from 'turndown';\nimport { logger as rootLogger } from '../../logger.js';\nimport type { KnowledgeStore } from '../KnowledgeStore.js';\nimport type { KnowledgeEntry } from '../KnowledgeEntry.js';\n\nconst logger = rootLogger.child('IwikiImporter');\n\nexport interface IwikiImporterConfig {\n authCookie?: string;\n authToken?: string;\n}\n\nexport class IwikiImporter {\n private store: KnowledgeStore;\n private config: IwikiImporterConfig;\n private turndown: TurndownService;\n\n constructor(store: KnowledgeStore, config: IwikiImporterConfig = {}) {\n this.store = store;\n this.config = config;\n this.turndown = new TurndownService({\n headingStyle: 'atx',\n codeBlockStyle: 'fenced',\n });\n }\n\n async importFromUrl(url: string): Promise<KnowledgeEntry> {\n logger.info('Importing iwiki page', { url });\n const html = await this.fetchPage(url);\n const { title, markdown } = this.extractContent(html);\n const entry = this.store.create({\n type: 'iwiki',\n title: title || this.titleFromUrl(url),\n content: markdown,\n tags: ['iwiki'],\n source: { url, kind: 'iwiki-page', syncEnabled: true, lastSyncAt: new Date().toISOString() },\n });\n logger.info('iwiki page imported', { id: entry.id, title: entry.title });\n return entry;\n }\n\n async sync(entryId: string): Promise<KnowledgeEntry> {\n const entry = this.store.get(entryId);\n if (!entry) throw new Error('Knowledge entry not found: ' + entryId);\n if (!entry.source?.url) throw new Error('Entry has no source URL');\n logger.info('Syncing iwiki page', { id: entryId, url: entry.source.url });\n const html = await this.fetchPage(entry.source.url);\n const { title, markdown } = this.extractContent(html);\n const updated = this.store.update(entryId, {\n title: title || entry.title,\n content: markdown,\n source: { ...entry.source, lastSyncAt: new Date().toISOString() },\n });\n logger.info('iwiki page synced', { id: entryId });\n return updated!;\n }\n\n extractContent(html: string): { title: string; markdown: string } {\n const titleRe = /<title[^>]*>([^<]+)<\\/title>/i;\n const titleMatch = html.match(titleRe);\n const title = titleMatch ? titleMatch[1].trim() : '';\n\n let bodyHtml = html;\n const bodyRe = /<body[^>]*>([\\s\\S]*?)<\\/body>/i;\n const bodyMatch = html.match(bodyRe);\n if (bodyMatch) bodyHtml = bodyMatch[1];\n\n bodyHtml = bodyHtml.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\n bodyHtml = bodyHtml.replace(/<style[\\s\\S]*?<\\/style>/gi, '');\n bodyHtml = bodyHtml.replace(/<nav[\\s\\S]*?<\\/nav>/gi, '');\n bodyHtml = bodyHtml.replace(/<header[\\s\\S]*?<\\/header>/gi, '');\n bodyHtml = bodyHtml.replace(/<footer[\\s\\S]*?<\\/footer>/gi, '');\n\n const mainRe = /<main[^>]*>([\\s\\S]*?)<\\/main>/i;\n const articleRe = /<article[^>]*>([\\s\\S]*?)<\\/article>/i;\n const contentRe = /class=\"[^\"]*content[^\"]*\"[^>]*>([\\s\\S]*?)<\\/div>/i;\n const mainMatch = bodyHtml.match(mainRe) || bodyHtml.match(articleRe) || bodyHtml.match(contentRe);\n if (mainMatch) bodyHtml = mainMatch[1];\n\n const markdown = this.turndown.turndown(bodyHtml).trim();\n return { title, markdown };\n }\n\n private async fetchPage(url: string): Promise<string> {\n const headers: Record<string, string> = {};\n if (this.config.authCookie) headers['Cookie'] = this.config.authCookie;\n if (this.config.authToken) headers['Authorization'] = 'Bearer ' + this.config.authToken;\n const resp = await fetch(url, { headers, redirect: 'follow' });\n if (!resp.ok) throw new Error('Failed to fetch iwiki page: HTTP ' + resp.status);\n return resp.text();\n }\n\n private titleFromUrl(url: string): string {\n try {\n const u = new URL(url);\n const segments = u.pathname.split('/').filter(Boolean);\n return decodeURIComponent(segments[segments.length - 1] || u.hostname);\n } catch {\n return url;\n }\n }\n}\n","import { logger as rootLogger } from '../../logger.js';\nimport type { GongfengClient, GongfengNote } from '../../clients/GongfengClient.js';\nimport type { AIRunner } from '../../ai-runner/AIRunner.js';\nimport type { KnowledgeStore } from '../KnowledgeStore.js';\nimport type { KnowledgeEntry } from '../KnowledgeEntry.js';\n\nconst logger = rootLogger.child('GongfengExtractor');\n\nexport interface GongfengExtractorDeps {\n store: KnowledgeStore;\n gongfeng: GongfengClient;\n aiRunner: AIRunner;\n gongfengApiUrl: string;\n gongfengProjectPath: string;\n timeoutMs?: number;\n}\n\nexport class GongfengExtractor {\n private store: KnowledgeStore;\n private gongfeng: GongfengClient;\n private aiRunner: AIRunner;\n private gongfengApiUrl: string;\n private gongfengProjectPath: string;\n private timeoutMs: number;\n\n constructor(deps: GongfengExtractorDeps) {\n this.store = deps.store;\n this.gongfeng = deps.gongfeng;\n this.aiRunner = deps.aiRunner;\n this.gongfengApiUrl = deps.gongfengApiUrl;\n this.gongfengProjectPath = deps.gongfengProjectPath;\n this.timeoutMs = deps.timeoutMs ?? 120_000;\n }\n\n async extractFromIssue(issueIid: number, workDir: string): Promise<KnowledgeEntry> {\n logger.info('Extracting knowledge from issue', { issueIid });\n\n const issue = await this.gongfeng.getIssueDetail(issueIid);\n const notes = await this.gongfeng.listIssueNotes(issueIid);\n\n const prompt = this.buildExtractionPrompt(\n 'Issue #' + issueIid + ': ' + issue.title,\n issue.description || '',\n notes,\n );\n\n const result = await this.aiRunner.run({ prompt, workDir, timeoutMs: this.timeoutMs });\n if (!result.success) {\n throw new Error('AI extraction failed: ' + result.output.slice(0, 500));\n }\n\n const issueUrl = this.buildIssueUrl(issueIid);\n const entry = this.store.create({\n type: 'gongfeng',\n title: 'Issue #' + issueIid + ' - ' + issue.title,\n content: result.output,\n tags: ['gongfeng', 'issue-' + issueIid],\n source: { url: issueUrl, kind: 'gongfeng-issue', lastSyncAt: new Date().toISOString() },\n });\n\n logger.info('Knowledge extracted from issue', { id: entry.id, issueIid });\n return entry;\n }\n\n async extractFromMR(mrIid: number, workDir: string): Promise<KnowledgeEntry> {\n logger.info('Extracting knowledge from MR', { mrIid });\n\n const mr = await this.gongfeng.getMergeRequestDetail(mrIid);\n\n const prompt = this.buildExtractionPrompt(\n 'MR !' + mrIid + ': ' + mr.title,\n '',\n [],\n );\n\n const result = await this.aiRunner.run({ prompt, workDir, timeoutMs: this.timeoutMs });\n if (!result.success) {\n throw new Error('AI extraction failed: ' + result.output.slice(0, 500));\n }\n\n const mrUrl = this.buildMRUrl(mrIid);\n const entry = this.store.create({\n type: 'gongfeng',\n title: 'MR !' + mrIid + ' - ' + mr.title,\n content: result.output,\n tags: ['gongfeng', 'mr-' + mrIid],\n source: { url: mrUrl, kind: 'gongfeng-mr', lastSyncAt: new Date().toISOString() },\n });\n\n logger.info('Knowledge extracted from MR', { id: entry.id, mrIid });\n return entry;\n }\n\n private buildExtractionPrompt(title: string, description: string, notes: GongfengNote[]): string {\n const filteredNotes = notes\n .filter(n => !n.body.includes('<!-- issue-auto-finish-agent -->'))\n .map(n => '**' + n.author.name + '** (' + n.created_at + '):\\n' + n.body)\n .join('\\n\\n---\\n\\n');\n\n return [\n '你是一个技术知识提取专家。请从以下工蜂 Issue/MR 的讨论中提取有价值的技术知识。',\n '',\n '## 标题',\n title,\n '',\n description ? '## 描述\\n' + description + '\\n' : '',\n '## 讨论内容',\n filteredNotes || '(无讨论)',\n '',\n '## 输出要求',\n '请用 Markdown 格式输出提取到的技术知识,包括但不限于:',\n '1. 关键技术决策和原因',\n '2. 发现的问题和解决方案',\n '3. 值得记录的最佳实践或注意事项',\n '4. 架构或设计相关的讨论结论',\n '',\n '如果讨论中没有有价值的技术知识,输出\"无有价值的技术知识可提取\"。',\n '请直接输出 Markdown 内容,不要添加额外的包裹或说明。',\n ].join('\\n');\n }\n\n private buildIssueUrl(iid: number): string {\n const base = this.gongfengApiUrl.replace('/api/v3', '').replace('/api/v4', '');\n return base + '/' + this.gongfengProjectPath + '/issues/' + iid;\n }\n\n private buildMRUrl(iid: number): string {\n const base = this.gongfengApiUrl.replace('/api/v3', '').replace('/api/v4', '');\n return base + '/' + this.gongfengProjectPath + '/merge_requests/' + iid;\n }\n}\n"],"mappings":"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","names":["logger","logger","logger"]}