@xdevops/issue-auto-finish 1.0.2 → 1.0.4
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/dist/KnowledgeAnalyzer-EZSJT2MJ.js +13 -0
- package/dist/KnowledgeAnalyzer-EZSJT2MJ.js.map +1 -0
- package/dist/KnowledgeStore-4ROC6F56.js +10 -0
- package/dist/KnowledgeStore-4ROC6F56.js.map +1 -0
- package/dist/ai-runner/AIRunner.d.ts +2 -0
- package/dist/ai-runner/AIRunner.d.ts.map +1 -1
- package/dist/ai-runner/BaseAIRunner.d.ts +9 -0
- package/dist/ai-runner/BaseAIRunner.d.ts.map +1 -1
- package/dist/ai-runner-RGAJPOOW.js +16 -0
- package/dist/ai-runner-RGAJPOOW.js.map +1 -0
- package/dist/analyze-ONQDTYCN.js +72 -0
- package/dist/analyze-ONQDTYCN.js.map +1 -0
- package/dist/chunk-3JUHZGX5.js +171 -0
- package/dist/chunk-3JUHZGX5.js.map +1 -0
- package/dist/chunk-5JYCGAU3.js +318 -0
- package/dist/chunk-5JYCGAU3.js.map +1 -0
- package/dist/chunk-5VUB3UUK.js +643 -0
- package/dist/chunk-5VUB3UUK.js.map +1 -0
- package/dist/{chunk-OWVT3Z34.js → chunk-JFYAXNNS.js} +121 -31
- package/dist/chunk-JFYAXNNS.js.map +1 -0
- package/dist/chunk-MH6LHFPB.js +188 -0
- package/dist/chunk-MH6LHFPB.js.map +1 -0
- package/dist/{chunk-TBIEB3JY.js → chunk-N5YK6YVI.js} +592 -767
- package/dist/chunk-N5YK6YVI.js.map +1 -0
- package/dist/{chunk-RIUI4ROA.js → chunk-PECYMYAK.js} +2 -2
- package/dist/{chunk-I3T573SU.js → chunk-PTIL5AY2.js} +65 -2
- package/dist/chunk-PTIL5AY2.js.map +1 -0
- package/dist/chunk-SWG2Y7YX.js +410 -0
- package/dist/chunk-SWG2Y7YX.js.map +1 -0
- package/dist/chunk-TZ6C7HL5.js +59 -0
- package/dist/chunk-TZ6C7HL5.js.map +1 -0
- package/dist/{chunk-IDUKWCC2.js → chunk-VFQYIC6L.js} +1151 -80
- package/dist/chunk-VFQYIC6L.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +8 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli.js +67 -3
- package/dist/cli.js.map +1 -1
- package/dist/clients/GongfengClient.d.ts +5 -0
- package/dist/clients/GongfengClient.d.ts.map +1 -1
- package/dist/config-6GFBDMGD.js +7 -0
- package/dist/config-6GFBDMGD.js.map +1 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/{doctor-B26Q6JWI.js → doctor-ZPGIBA5N.js} +3 -3
- package/dist/events/EventBus.d.ts +1 -1
- package/dist/events/EventBus.d.ts.map +1 -1
- package/dist/git/GitOperations.d.ts +12 -0
- package/dist/git/GitOperations.d.ts.map +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/{init-L3VIWCOV.js → init-QDTII4SP.js} +10 -5
- package/dist/init-QDTII4SP.js.map +1 -0
- package/dist/knowledge/KnowledgeAnalyzer.d.ts +31 -0
- package/dist/knowledge/KnowledgeAnalyzer.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeDefaults.d.ts +7 -0
- package/dist/knowledge/KnowledgeDefaults.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeEntry.d.ts +30 -0
- package/dist/knowledge/KnowledgeEntry.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeLoader.d.ts +18 -0
- package/dist/knowledge/KnowledgeLoader.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeStore.d.ts +35 -0
- package/dist/knowledge/KnowledgeStore.d.ts.map +1 -0
- package/dist/knowledge/ProjectKnowledge.d.ts +79 -0
- package/dist/knowledge/ProjectKnowledge.d.ts.map +1 -0
- package/dist/knowledge/analyze-prompt.d.ts +2 -0
- package/dist/knowledge/analyze-prompt.d.ts.map +1 -0
- package/dist/knowledge/importers/GongfengExtractor.d.ts +27 -0
- package/dist/knowledge/importers/GongfengExtractor.d.ts.map +1 -0
- package/dist/knowledge/importers/IwikiImporter.d.ts +21 -0
- package/dist/knowledge/importers/IwikiImporter.d.ts.map +1 -0
- package/dist/knowledge/index.d.ts +12 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/lib.js +19 -10
- package/dist/orchestrator/PipelineOrchestrator.d.ts +5 -1
- package/dist/orchestrator/PipelineOrchestrator.d.ts.map +1 -1
- package/dist/phases/BasePhase.d.ts.map +1 -1
- package/dist/poller/IssuePoller.d.ts +5 -0
- package/dist/poller/IssuePoller.d.ts.map +1 -1
- package/dist/prompts/chat-templates.d.ts +4 -0
- package/dist/prompts/chat-templates.d.ts.map +1 -0
- package/dist/prompts/templates.d.ts +11 -0
- package/dist/prompts/templates.d.ts.map +1 -1
- package/dist/rules/RuleResolver.d.ts +4 -0
- package/dist/rules/RuleResolver.d.ts.map +1 -1
- package/dist/run.js +11 -5
- package/dist/run.js.map +1 -1
- package/dist/services/ChatService.d.ts +39 -0
- package/dist/services/ChatService.d.ts.map +1 -0
- package/dist/shutdown/ShutdownSignal.d.ts +3 -0
- package/dist/shutdown/ShutdownSignal.d.ts.map +1 -0
- package/dist/{start-TVN4SS6E.js → start-EDOZC5WL.js} +1 -1
- package/dist/tracker/IssueState.d.ts +1 -0
- package/dist/tracker/IssueState.d.ts.map +1 -1
- package/dist/tracker/IssueTracker.d.ts +2 -0
- package/dist/tracker/IssueTracker.d.ts.map +1 -1
- package/dist/updater/AutoUpdater.d.ts +33 -0
- package/dist/updater/AutoUpdater.d.ts.map +1 -0
- package/dist/updater/UpdateExecutor.d.ts +7 -0
- package/dist/updater/UpdateExecutor.d.ts.map +1 -0
- package/dist/updater/VersionChecker.d.ts +22 -0
- package/dist/updater/VersionChecker.d.ts.map +1 -0
- package/dist/web/WebServer.d.ts +4 -0
- package/dist/web/WebServer.d.ts.map +1 -1
- package/dist/web/routes/api.d.ts +4 -0
- package/dist/web/routes/api.d.ts.map +1 -1
- package/dist/web/routes/chat.d.ts +7 -0
- package/dist/web/routes/chat.d.ts.map +1 -0
- package/dist/web/routes/knowledge.d.ts +13 -0
- package/dist/web/routes/knowledge.d.ts.map +1 -0
- package/dist/web/routes/setup.d.ts.map +1 -1
- package/dist/webhook/CommandExecutor.d.ts +4 -0
- package/dist/webhook/CommandExecutor.d.ts.map +1 -1
- package/dist/webhook/CommandParser.d.ts +2 -2
- package/dist/webhook/CommandParser.d.ts.map +1 -1
- package/dist/webhook/WebhookHandler.d.ts +8 -0
- package/dist/webhook/WebhookHandler.d.ts.map +1 -1
- package/dist/webhook/WebhookServer.d.ts +2 -0
- package/dist/webhook/WebhookServer.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/web/frontend/dist/assets/index-AcJ0lPIv.js +67 -0
- package/src/web/frontend/dist/assets/index-BbRt5BAr.css +1 -0
- package/src/web/frontend/dist/index.html +2 -2
- package/dist/chunk-I3T573SU.js.map +0 -1
- package/dist/chunk-IDUKWCC2.js.map +0 -1
- package/dist/chunk-OWVT3Z34.js.map +0 -1
- package/dist/chunk-TBIEB3JY.js.map +0 -1
- package/dist/init-L3VIWCOV.js.map +0 -1
- package/src/web/frontend/dist/assets/index-CQdlU9PE.js +0 -65
- package/src/web/frontend/dist/assets/index-CgMEkyZJ.css +0 -1
- /package/dist/{chunk-RIUI4ROA.js.map → chunk-PECYMYAK.js.map} +0 -0
- /package/dist/{doctor-B26Q6JWI.js.map → doctor-ZPGIBA5N.js.map} +0 -0
- /package/dist/{start-TVN4SS6E.js.map → start-EDOZC5WL.js.map} +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { config as loadDotenv } from "dotenv";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
function resolveEnvPath() {
|
|
9
|
+
if (process.env.IAF_CONFIG_PATH) return process.env.IAF_CONFIG_PATH;
|
|
10
|
+
const localEnv = path.resolve(__dirname, "../.env");
|
|
11
|
+
if (fs.existsSync(localEnv)) return localEnv;
|
|
12
|
+
const cwdEnv = path.resolve(process.cwd(), ".env");
|
|
13
|
+
if (fs.existsSync(cwdEnv)) return cwdEnv;
|
|
14
|
+
const globalEnv = path.join(os.homedir(), ".issue-auto-finish", ".env");
|
|
15
|
+
if (fs.existsSync(globalEnv)) return globalEnv;
|
|
16
|
+
return localEnv;
|
|
17
|
+
}
|
|
18
|
+
var _dotenvLoaded = false;
|
|
19
|
+
function ensureDotenvLoaded() {
|
|
20
|
+
if (_dotenvLoaded) return;
|
|
21
|
+
_dotenvLoaded = true;
|
|
22
|
+
loadDotenv({ path: resolveEnvPath() });
|
|
23
|
+
}
|
|
24
|
+
var DEFAULT_AI_MODEL = "Claude-4.6-Opus";
|
|
25
|
+
function requireEnv(key) {
|
|
26
|
+
const val = process.env[key];
|
|
27
|
+
if (!val) {
|
|
28
|
+
throw new Error(`Missing required environment variable: ${key}`);
|
|
29
|
+
}
|
|
30
|
+
return val;
|
|
31
|
+
}
|
|
32
|
+
function optionalEnv(key, defaultValue) {
|
|
33
|
+
return process.env[key] || defaultValue;
|
|
34
|
+
}
|
|
35
|
+
function loadConfig() {
|
|
36
|
+
ensureDotenvLoaded();
|
|
37
|
+
return {
|
|
38
|
+
gongfeng: {
|
|
39
|
+
apiUrl: requireEnv("GONGFENG_API_URL"),
|
|
40
|
+
privateToken: requireEnv("GONGFENG_PRIVATE_TOKEN"),
|
|
41
|
+
projectPath: requireEnv("GONGFENG_PROJECT_PATH")
|
|
42
|
+
},
|
|
43
|
+
project: {
|
|
44
|
+
workDir: requireEnv("PROJECT_WORK_DIR"),
|
|
45
|
+
gitRootDir: optionalEnv("GIT_ROOT_DIR", requireEnv("PROJECT_WORK_DIR")),
|
|
46
|
+
baseBranch: optionalEnv("BASE_BRANCH", "master"),
|
|
47
|
+
branchPrefix: optionalEnv("BRANCH_PREFIX", "feat/issue"),
|
|
48
|
+
worktreeBaseDir: optionalEnv("WORKTREE_BASE_DIR", ""),
|
|
49
|
+
projectSubDir: optionalEnv("PROJECT_SUBDIR", "")
|
|
50
|
+
},
|
|
51
|
+
claude: {
|
|
52
|
+
binary: optionalEnv("CLAUDE_BINARY", "claude-internal"),
|
|
53
|
+
phaseTimeoutMs: parseInt(optionalEnv("CLAUDE_PHASE_TIMEOUT_MS", "1800000"), 10),
|
|
54
|
+
nvmNodeVersion: optionalEnv("NVM_NODE_VERSION", "20")
|
|
55
|
+
},
|
|
56
|
+
ai: buildAIConfig(),
|
|
57
|
+
poll: {
|
|
58
|
+
intervalMs: parseInt(optionalEnv("POLL_INTERVAL_MS", "60000"), 10),
|
|
59
|
+
discoveryIntervalMs: parseInt(
|
|
60
|
+
optionalEnv("POLL_DISCOVERY_INTERVAL_MS", optionalEnv("POLL_INTERVAL_MS", "60000")),
|
|
61
|
+
10
|
|
62
|
+
),
|
|
63
|
+
driveIntervalMs: parseInt(optionalEnv("POLL_DRIVE_INTERVAL_MS", "15000"), 10),
|
|
64
|
+
maxRetries: parseInt(optionalEnv("MAX_RETRIES", "3"), 10),
|
|
65
|
+
maxConcurrent: parseInt(optionalEnv("MAX_CONCURRENT_ISSUES", "3"), 10)
|
|
66
|
+
},
|
|
67
|
+
pipeline: {
|
|
68
|
+
mode: optionalEnv("PIPELINE_MODE", "auto")
|
|
69
|
+
},
|
|
70
|
+
review: {
|
|
71
|
+
enabled: optionalEnv("REVIEW_ENABLED", "true") === "true",
|
|
72
|
+
autoApproveLabels: optionalEnv("REVIEW_AUTO_APPROVE_LABELS", "").split(",").map((s) => s.trim()).filter(Boolean)
|
|
73
|
+
},
|
|
74
|
+
web: {
|
|
75
|
+
enabled: optionalEnv("WEB_ENABLED", "true") === "true",
|
|
76
|
+
port: parseInt(optionalEnv("WEB_PORT", "3000"), 10),
|
|
77
|
+
frontendDistDir: optionalEnv(
|
|
78
|
+
"FRONTEND_DIST_DIR",
|
|
79
|
+
path.resolve(__dirname, "..", "src/web/frontend/dist")
|
|
80
|
+
)
|
|
81
|
+
},
|
|
82
|
+
issueNoteSync: {
|
|
83
|
+
enabled: optionalEnv("ISSUE_NOTE_SYNC_ENABLED", "true") === "true",
|
|
84
|
+
webBaseUrl: optionalEnv(
|
|
85
|
+
"WEB_BASE_URL",
|
|
86
|
+
`http://localhost:${optionalEnv("WEB_PORT", "3000")}`
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
webhook: {
|
|
90
|
+
enabled: optionalEnv("WEBHOOK_ENABLED", "false") === "true",
|
|
91
|
+
port: parseInt(optionalEnv("WEBHOOK_PORT", "8081"), 10),
|
|
92
|
+
secret: optionalEnv("WEBHOOK_SECRET", ""),
|
|
93
|
+
llmFallback: optionalEnv("WEBHOOK_LLM_FALLBACK", "true") === "true",
|
|
94
|
+
llmBinary: optionalEnv("WEBHOOK_LLM_BINARY", "claude-internal")
|
|
95
|
+
},
|
|
96
|
+
e2e: {
|
|
97
|
+
enabled: optionalEnv("E2E_UI_ENABLED", "false") === "true",
|
|
98
|
+
baseUrl: optionalEnv("E2E_BASE_URL", "https://localhost:8890"),
|
|
99
|
+
backendUrl: optionalEnv("E2E_BACKEND_URL", "http://127.0.0.1:3000"),
|
|
100
|
+
authCookies: optionalEnv("E2E_AUTH_COOKIES", "[]"),
|
|
101
|
+
backendPortBase: parseInt(optionalEnv("E2E_BACKEND_PORT_BASE", "4000"), 10),
|
|
102
|
+
frontendPortBase: parseInt(optionalEnv("E2E_FRONTEND_PORT_BASE", "9000"), 10)
|
|
103
|
+
},
|
|
104
|
+
preview: {
|
|
105
|
+
enabled: optionalEnv("PREVIEW_ENABLED", "false") === "true",
|
|
106
|
+
host: optionalEnv("PREVIEW_HOST", ""),
|
|
107
|
+
ttlMs: parseInt(optionalEnv("PREVIEW_TTL_MS", String(24 * 60 * 60 * 1e3)), 10),
|
|
108
|
+
keepAfterComplete: optionalEnv("PREVIEW_KEEP_AFTER_COMPLETE", "true") === "true"
|
|
109
|
+
},
|
|
110
|
+
brainstorm: {
|
|
111
|
+
enabled: optionalEnv("BRAINSTORM_ENABLED", "true") === "true",
|
|
112
|
+
maxRefinementRounds: parseInt(optionalEnv("BRAINSTORM_MAX_ROUNDS", "5"), 10),
|
|
113
|
+
timeoutMs: parseInt(optionalEnv("BRAINSTORM_TIMEOUT_MS", "600000"), 10),
|
|
114
|
+
generator: buildBrainstormAgentConfig("GENERATOR"),
|
|
115
|
+
reviewer: buildBrainstormAgentConfig("REVIEWER")
|
|
116
|
+
},
|
|
117
|
+
chat: {
|
|
118
|
+
enabled: optionalEnv("CHAT_ENABLED", "true") === "true",
|
|
119
|
+
timeoutMs: parseInt(optionalEnv("CHAT_TIMEOUT_MS", "300000"), 10),
|
|
120
|
+
maxSessionMessages: parseInt(optionalEnv("CHAT_MAX_SESSION_MESSAGES", "100"), 10),
|
|
121
|
+
agent: buildChatAgentConfig()
|
|
122
|
+
},
|
|
123
|
+
autoUpdate: {
|
|
124
|
+
enabled: optionalEnv("AUTO_UPDATE_ENABLED", "true") === "true",
|
|
125
|
+
intervalMs: parseInt(optionalEnv("AUTO_UPDATE_INTERVAL_MS", "600000"), 10),
|
|
126
|
+
registry: optionalEnv("AUTO_UPDATE_REGISTRY", "https://registry.npmjs.org"),
|
|
127
|
+
drainTimeoutMs: parseInt(optionalEnv("AUTO_UPDATE_DRAIN_TIMEOUT_MS", "300000"), 10)
|
|
128
|
+
},
|
|
129
|
+
iwiki: {
|
|
130
|
+
authCookie: process.env.IWIKI_AUTH_COOKIE || void 0,
|
|
131
|
+
authToken: process.env.IWIKI_AUTH_TOKEN || void 0,
|
|
132
|
+
baseUrl: process.env.IWIKI_BASE_URL || void 0
|
|
133
|
+
},
|
|
134
|
+
locale: optionalEnv("LOCALE", "zh-CN") === "en" ? "en" : "zh-CN",
|
|
135
|
+
knowledgePath: process.env.KNOWLEDGE_PATH || void 0
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function resolveAIRunnerMode(raw) {
|
|
139
|
+
if (raw === "cursor-agent") return "cursor-agent";
|
|
140
|
+
if (raw === "codebuddy") return "codebuddy";
|
|
141
|
+
return "claude-internal";
|
|
142
|
+
}
|
|
143
|
+
function resolveAIBinary(mode) {
|
|
144
|
+
switch (mode) {
|
|
145
|
+
case "cursor-agent":
|
|
146
|
+
return optionalEnv("CURSOR_BINARY", "cursor");
|
|
147
|
+
case "codebuddy":
|
|
148
|
+
return optionalEnv("CODEBUDDY_BINARY", "codebuddy");
|
|
149
|
+
default:
|
|
150
|
+
return optionalEnv("CLAUDE_BINARY", "claude-internal");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function buildAIConfig() {
|
|
154
|
+
const mode = resolveAIRunnerMode(optionalEnv("AI_RUNNER_MODE", "claude-internal"));
|
|
155
|
+
return {
|
|
156
|
+
mode,
|
|
157
|
+
binary: resolveAIBinary(mode),
|
|
158
|
+
phaseTimeoutMs: parseInt(optionalEnv("CLAUDE_PHASE_TIMEOUT_MS", "1800000"), 10),
|
|
159
|
+
nvmNodeVersion: optionalEnv("NVM_NODE_VERSION", "20"),
|
|
160
|
+
model: optionalEnv("AI_MODEL", DEFAULT_AI_MODEL)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function buildBrainstormAgentConfig(role) {
|
|
164
|
+
const globalMode = optionalEnv("AI_RUNNER_MODE", "claude-internal");
|
|
165
|
+
const roleMode = optionalEnv(`BRAINSTORM_${role}_MODE`, globalMode);
|
|
166
|
+
const mode = resolveAIRunnerMode(roleMode);
|
|
167
|
+
return {
|
|
168
|
+
mode,
|
|
169
|
+
binary: optionalEnv(`BRAINSTORM_${role}_BINARY`, resolveAIBinary(mode)),
|
|
170
|
+
nvmNodeVersion: optionalEnv("NVM_NODE_VERSION", "20"),
|
|
171
|
+
model: process.env[`BRAINSTORM_${role}_MODEL`] || optionalEnv("AI_MODEL", DEFAULT_AI_MODEL)
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function buildChatAgentConfig() {
|
|
175
|
+
const chatMode = optionalEnv("CHAT_AGENT_MODE", "claude-internal");
|
|
176
|
+
const mode = resolveAIRunnerMode(chatMode);
|
|
177
|
+
return {
|
|
178
|
+
mode,
|
|
179
|
+
binary: optionalEnv("CHAT_AGENT_BINARY", resolveAIBinary(mode)),
|
|
180
|
+
nvmNodeVersion: optionalEnv("NVM_NODE_VERSION", "20"),
|
|
181
|
+
model: process.env.CHAT_AGENT_MODEL || optionalEnv("AI_MODEL", DEFAULT_AI_MODEL)
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export {
|
|
186
|
+
loadConfig
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=chunk-MH6LHFPB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { config as loadDotenv } from 'dotenv';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction resolveEnvPath(): string {\n if (process.env.IAF_CONFIG_PATH) return process.env.IAF_CONFIG_PATH;\n\n const localEnv = path.resolve(__dirname, '../.env');\n if (fs.existsSync(localEnv)) return localEnv;\n\n const cwdEnv = path.resolve(process.cwd(), '.env');\n if (fs.existsSync(cwdEnv)) return cwdEnv;\n\n const globalEnv = path.join(os.homedir(), '.issue-auto-finish', '.env');\n if (fs.existsSync(globalEnv)) return globalEnv;\n\n return localEnv;\n}\n\nlet _dotenvLoaded = false;\nfunction ensureDotenvLoaded(): void {\n if (_dotenvLoaded) return;\n _dotenvLoaded = true;\n loadDotenv({ path: resolveEnvPath() });\n}\n\nexport interface Config {\n gongfeng: {\n apiUrl: string;\n privateToken: string;\n projectPath: string;\n };\n project: {\n workDir: string;\n gitRootDir: string;\n baseBranch: string;\n branchPrefix: string;\n worktreeBaseDir: string;\n projectSubDir: string;\n };\n /** @deprecated Use ai instead */\n claude?: {\n binary: string;\n phaseTimeoutMs: number;\n nvmNodeVersion: string;\n };\n ai: {\n mode: 'claude-internal' | 'cursor-agent' | 'codebuddy';\n binary: string;\n phaseTimeoutMs: number;\n nvmNodeVersion: string;\n model?: string;\n };\n poll: {\n /** @deprecated Use discoveryIntervalMs instead */\n intervalMs: number;\n discoveryIntervalMs: number;\n driveIntervalMs: number;\n maxRetries: number;\n maxConcurrent: number;\n };\n pipeline: {\n mode: 'auto' | 'classic' | 'plan-mode';\n };\n review: {\n enabled: boolean;\n autoApproveLabels: string[];\n };\n web: {\n enabled: boolean;\n port: number;\n frontendDistDir: string;\n };\n issueNoteSync: {\n enabled: boolean;\n webBaseUrl: string;\n };\n webhook: {\n enabled: boolean;\n port: number;\n secret: string;\n /** Use LLM to parse natural-language commands when regex fails */\n llmFallback: boolean;\n /** Binary for LLM intent recognition (defaults to claude-internal, independent of AI_RUNNER_MODE) */\n llmBinary: string;\n };\n e2e: {\n enabled: boolean;\n baseUrl: string;\n backendUrl: string;\n authCookies: string;\n backendPortBase: number;\n frontendPortBase: number;\n };\n preview: {\n enabled: boolean;\n host: string;\n ttlMs: number;\n keepAfterComplete: boolean;\n };\n brainstorm: {\n enabled: boolean;\n maxRefinementRounds: number;\n timeoutMs: number;\n generator: BrainstormAgentConfig;\n reviewer: BrainstormAgentConfig;\n };\n chat: {\n enabled: boolean;\n timeoutMs: number;\n maxSessionMessages: number;\n agent: ChatAgentConfig;\n };\n autoUpdate: {\n enabled: boolean;\n intervalMs: number;\n registry: string;\n drainTimeoutMs: number;\n };\n iwiki?: {\n authCookie?: string;\n authToken?: string;\n baseUrl?: string;\n };\n locale: 'zh-CN' | 'en';\n knowledgePath?: string;\n}\n\nexport type AIRunnerMode = 'claude-internal' | 'cursor-agent' | 'codebuddy';\n\nexport interface BrainstormAgentConfig {\n mode: AIRunnerMode;\n binary: string;\n nvmNodeVersion: string;\n model?: string;\n}\n\nexport type ChatAgentConfig = BrainstormAgentConfig;\n\nconst DEFAULT_AI_MODEL = 'Claude-4.6-Opus';\n\nfunction requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nfunction optionalEnv(key: string, defaultValue: string): string {\n return process.env[key] || defaultValue;\n}\n\nexport function loadConfig(): Config {\n ensureDotenvLoaded();\n return {\n gongfeng: {\n apiUrl: requireEnv('GONGFENG_API_URL'),\n privateToken: requireEnv('GONGFENG_PRIVATE_TOKEN'),\n projectPath: requireEnv('GONGFENG_PROJECT_PATH'),\n },\n project: {\n workDir: requireEnv('PROJECT_WORK_DIR'),\n gitRootDir: optionalEnv('GIT_ROOT_DIR', requireEnv('PROJECT_WORK_DIR')),\n baseBranch: optionalEnv('BASE_BRANCH', 'master'),\n branchPrefix: optionalEnv('BRANCH_PREFIX', 'feat/issue'),\n worktreeBaseDir: optionalEnv('WORKTREE_BASE_DIR', ''),\n projectSubDir: optionalEnv('PROJECT_SUBDIR', ''),\n },\n claude: {\n binary: optionalEnv('CLAUDE_BINARY', 'claude-internal'),\n phaseTimeoutMs: parseInt(optionalEnv('CLAUDE_PHASE_TIMEOUT_MS', '1800000'), 10),\n nvmNodeVersion: optionalEnv('NVM_NODE_VERSION', '20'),\n },\n ai: buildAIConfig(),\n poll: {\n intervalMs: parseInt(optionalEnv('POLL_INTERVAL_MS', '60000'), 10),\n discoveryIntervalMs: parseInt(\n optionalEnv('POLL_DISCOVERY_INTERVAL_MS', optionalEnv('POLL_INTERVAL_MS', '60000')),\n 10,\n ),\n driveIntervalMs: parseInt(optionalEnv('POLL_DRIVE_INTERVAL_MS', '15000'), 10),\n maxRetries: parseInt(optionalEnv('MAX_RETRIES', '3'), 10),\n maxConcurrent: parseInt(optionalEnv('MAX_CONCURRENT_ISSUES', '3'), 10),\n },\n pipeline: {\n mode: optionalEnv('PIPELINE_MODE', 'auto') as 'auto' | 'classic' | 'plan-mode',\n },\n review: {\n enabled: optionalEnv('REVIEW_ENABLED', 'true') === 'true',\n autoApproveLabels: optionalEnv('REVIEW_AUTO_APPROVE_LABELS', '')\n .split(',').map(s => s.trim()).filter(Boolean),\n },\n web: {\n enabled: optionalEnv('WEB_ENABLED', 'true') === 'true',\n port: parseInt(optionalEnv('WEB_PORT', '3000'), 10),\n frontendDistDir: optionalEnv(\n 'FRONTEND_DIST_DIR',\n path.resolve(__dirname, '..', 'src/web/frontend/dist'),\n ),\n },\n issueNoteSync: {\n enabled: optionalEnv('ISSUE_NOTE_SYNC_ENABLED', 'true') === 'true',\n webBaseUrl: optionalEnv(\n 'WEB_BASE_URL',\n `http://localhost:${optionalEnv('WEB_PORT', '3000')}`,\n ),\n },\n webhook: {\n enabled: optionalEnv('WEBHOOK_ENABLED', 'false') === 'true',\n port: parseInt(optionalEnv('WEBHOOK_PORT', '8081'), 10),\n secret: optionalEnv('WEBHOOK_SECRET', ''),\n llmFallback: optionalEnv('WEBHOOK_LLM_FALLBACK', 'true') === 'true',\n llmBinary: optionalEnv('WEBHOOK_LLM_BINARY', 'claude-internal'),\n },\n e2e: {\n enabled: optionalEnv('E2E_UI_ENABLED', 'false') === 'true',\n baseUrl: optionalEnv('E2E_BASE_URL', 'https://localhost:8890'),\n backendUrl: optionalEnv('E2E_BACKEND_URL', 'http://127.0.0.1:3000'),\n authCookies: optionalEnv('E2E_AUTH_COOKIES', '[]'),\n backendPortBase: parseInt(optionalEnv('E2E_BACKEND_PORT_BASE', '4000'), 10),\n frontendPortBase: parseInt(optionalEnv('E2E_FRONTEND_PORT_BASE', '9000'), 10),\n },\n preview: {\n enabled: optionalEnv('PREVIEW_ENABLED', 'false') === 'true',\n host: optionalEnv('PREVIEW_HOST', ''),\n ttlMs: parseInt(optionalEnv('PREVIEW_TTL_MS', String(24 * 60 * 60 * 1000)), 10),\n keepAfterComplete: optionalEnv('PREVIEW_KEEP_AFTER_COMPLETE', 'true') === 'true',\n },\n brainstorm: {\n enabled: optionalEnv('BRAINSTORM_ENABLED', 'true') === 'true',\n maxRefinementRounds: parseInt(optionalEnv('BRAINSTORM_MAX_ROUNDS', '5'), 10),\n timeoutMs: parseInt(optionalEnv('BRAINSTORM_TIMEOUT_MS', '600000'), 10),\n generator: buildBrainstormAgentConfig('GENERATOR'),\n reviewer: buildBrainstormAgentConfig('REVIEWER'),\n },\n chat: {\n enabled: optionalEnv('CHAT_ENABLED', 'true') === 'true',\n timeoutMs: parseInt(optionalEnv('CHAT_TIMEOUT_MS', '300000'), 10),\n maxSessionMessages: parseInt(optionalEnv('CHAT_MAX_SESSION_MESSAGES', '100'), 10),\n agent: buildChatAgentConfig(),\n },\n autoUpdate: {\n enabled: optionalEnv('AUTO_UPDATE_ENABLED', 'true') === 'true',\n intervalMs: parseInt(optionalEnv('AUTO_UPDATE_INTERVAL_MS', '600000'), 10),\n registry: optionalEnv('AUTO_UPDATE_REGISTRY', 'https://registry.npmjs.org'),\n drainTimeoutMs: parseInt(optionalEnv('AUTO_UPDATE_DRAIN_TIMEOUT_MS', '300000'), 10),\n },\n iwiki: {\n authCookie: process.env.IWIKI_AUTH_COOKIE || undefined,\n authToken: process.env.IWIKI_AUTH_TOKEN || undefined,\n baseUrl: process.env.IWIKI_BASE_URL || undefined,\n },\n locale: (optionalEnv('LOCALE', 'zh-CN') === 'en' ? 'en' : 'zh-CN') as 'zh-CN' | 'en',\n knowledgePath: process.env.KNOWLEDGE_PATH || undefined,\n };\n}\n\nfunction resolveAIRunnerMode(raw: string): AIRunnerMode {\n if (raw === 'cursor-agent') return 'cursor-agent';\n if (raw === 'codebuddy') return 'codebuddy';\n return 'claude-internal';\n}\n\nfunction resolveAIBinary(mode: AIRunnerMode): string {\n switch (mode) {\n case 'cursor-agent':\n return optionalEnv('CURSOR_BINARY', 'cursor');\n case 'codebuddy':\n return optionalEnv('CODEBUDDY_BINARY', 'codebuddy');\n default:\n return optionalEnv('CLAUDE_BINARY', 'claude-internal');\n }\n}\n\nfunction buildAIConfig(): Config['ai'] {\n const mode = resolveAIRunnerMode(optionalEnv('AI_RUNNER_MODE', 'claude-internal'));\n return {\n mode,\n binary: resolveAIBinary(mode),\n phaseTimeoutMs: parseInt(optionalEnv('CLAUDE_PHASE_TIMEOUT_MS', '1800000'), 10),\n nvmNodeVersion: optionalEnv('NVM_NODE_VERSION', '20'),\n model: optionalEnv('AI_MODEL', DEFAULT_AI_MODEL),\n };\n}\n\nfunction buildBrainstormAgentConfig(role: 'GENERATOR' | 'REVIEWER'): BrainstormAgentConfig {\n const globalMode = optionalEnv('AI_RUNNER_MODE', 'claude-internal');\n const roleMode = optionalEnv(`BRAINSTORM_${role}_MODE`, globalMode);\n const mode = resolveAIRunnerMode(roleMode);\n\n return {\n mode,\n binary: optionalEnv(`BRAINSTORM_${role}_BINARY`, resolveAIBinary(mode)),\n nvmNodeVersion: optionalEnv('NVM_NODE_VERSION', '20'),\n model: process.env[`BRAINSTORM_${role}_MODEL`] || optionalEnv('AI_MODEL', DEFAULT_AI_MODEL),\n };\n}\n\nfunction buildChatAgentConfig(): ChatAgentConfig {\n // Chat defaults to claude-internal for lightweight conversational use,\n // independent of the global AI_RUNNER_MODE (which may be cursor-agent).\n const chatMode = optionalEnv('CHAT_AGENT_MODE', 'claude-internal');\n const mode = resolveAIRunnerMode(chatMode);\n\n return {\n mode,\n binary: optionalEnv('CHAT_AGENT_BINARY', resolveAIBinary(mode)),\n nvmNodeVersion: optionalEnv('NVM_NODE_VERSION', '20'),\n model: process.env.CHAT_AGENT_MODEL || optionalEnv('AI_MODEL', DEFAULT_AI_MODEL),\n };\n}\n"],"mappings":";AAAA,SAAS,UAAU,kBAAkB;AACrC,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,SAAS,qBAAqB;AAE9B,IAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,SAAS,iBAAyB;AAChC,MAAI,QAAQ,IAAI,gBAAiB,QAAO,QAAQ,IAAI;AAEpD,QAAM,WAAW,KAAK,QAAQ,WAAW,SAAS;AAClD,MAAI,GAAG,WAAW,QAAQ,EAAG,QAAO;AAEpC,QAAM,SAAS,KAAK,QAAQ,QAAQ,IAAI,GAAG,MAAM;AACjD,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAElC,QAAM,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,sBAAsB,MAAM;AACtE,MAAI,GAAG,WAAW,SAAS,EAAG,QAAO;AAErC,SAAO;AACT;AAEA,IAAI,gBAAgB;AACpB,SAAS,qBAA2B;AAClC,MAAI,cAAe;AACnB,kBAAgB;AAChB,aAAW,EAAE,MAAM,eAAe,EAAE,CAAC;AACvC;AAmHA,IAAM,mBAAmB;AAEzB,SAAS,WAAW,KAAqB;AACvC,QAAM,MAAM,QAAQ,IAAI,GAAG;AAC3B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,0CAA0C,GAAG,EAAE;AAAA,EACjE;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAAa,cAA8B;AAC9D,SAAO,QAAQ,IAAI,GAAG,KAAK;AAC7B;AAEO,SAAS,aAAqB;AACnC,qBAAmB;AACnB,SAAO;AAAA,IACL,UAAU;AAAA,MACR,QAAQ,WAAW,kBAAkB;AAAA,MACrC,cAAc,WAAW,wBAAwB;AAAA,MACjD,aAAa,WAAW,uBAAuB;AAAA,IACjD;AAAA,IACA,SAAS;AAAA,MACP,SAAS,WAAW,kBAAkB;AAAA,MACtC,YAAY,YAAY,gBAAgB,WAAW,kBAAkB,CAAC;AAAA,MACtE,YAAY,YAAY,eAAe,QAAQ;AAAA,MAC/C,cAAc,YAAY,iBAAiB,YAAY;AAAA,MACvD,iBAAiB,YAAY,qBAAqB,EAAE;AAAA,MACpD,eAAe,YAAY,kBAAkB,EAAE;AAAA,IACjD;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ,YAAY,iBAAiB,iBAAiB;AAAA,MACtD,gBAAgB,SAAS,YAAY,2BAA2B,SAAS,GAAG,EAAE;AAAA,MAC9E,gBAAgB,YAAY,oBAAoB,IAAI;AAAA,IACtD;AAAA,IACA,IAAI,cAAc;AAAA,IAClB,MAAM;AAAA,MACJ,YAAY,SAAS,YAAY,oBAAoB,OAAO,GAAG,EAAE;AAAA,MACjE,qBAAqB;AAAA,QACnB,YAAY,8BAA8B,YAAY,oBAAoB,OAAO,CAAC;AAAA,QAClF;AAAA,MACF;AAAA,MACA,iBAAiB,SAAS,YAAY,0BAA0B,OAAO,GAAG,EAAE;AAAA,MAC5E,YAAY,SAAS,YAAY,eAAe,GAAG,GAAG,EAAE;AAAA,MACxD,eAAe,SAAS,YAAY,yBAAyB,GAAG,GAAG,EAAE;AAAA,IACvE;AAAA,IACA,UAAU;AAAA,MACR,MAAM,YAAY,iBAAiB,MAAM;AAAA,IAC3C;AAAA,IACA,QAAQ;AAAA,MACN,SAAS,YAAY,kBAAkB,MAAM,MAAM;AAAA,MACnD,mBAAmB,YAAY,8BAA8B,EAAE,EAC5D,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAAA,IACjD;AAAA,IACA,KAAK;AAAA,MACH,SAAS,YAAY,eAAe,MAAM,MAAM;AAAA,MAChD,MAAM,SAAS,YAAY,YAAY,MAAM,GAAG,EAAE;AAAA,MAClD,iBAAiB;AAAA,QACf;AAAA,QACA,KAAK,QAAQ,WAAW,MAAM,uBAAuB;AAAA,MACvD;AAAA,IACF;AAAA,IACA,eAAe;AAAA,MACb,SAAS,YAAY,2BAA2B,MAAM,MAAM;AAAA,MAC5D,YAAY;AAAA,QACV;AAAA,QACA,oBAAoB,YAAY,YAAY,MAAM,CAAC;AAAA,MACrD;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS,YAAY,mBAAmB,OAAO,MAAM;AAAA,MACrD,MAAM,SAAS,YAAY,gBAAgB,MAAM,GAAG,EAAE;AAAA,MACtD,QAAQ,YAAY,kBAAkB,EAAE;AAAA,MACxC,aAAa,YAAY,wBAAwB,MAAM,MAAM;AAAA,MAC7D,WAAW,YAAY,sBAAsB,iBAAiB;AAAA,IAChE;AAAA,IACA,KAAK;AAAA,MACH,SAAS,YAAY,kBAAkB,OAAO,MAAM;AAAA,MACpD,SAAS,YAAY,gBAAgB,wBAAwB;AAAA,MAC7D,YAAY,YAAY,mBAAmB,uBAAuB;AAAA,MAClE,aAAa,YAAY,oBAAoB,IAAI;AAAA,MACjD,iBAAiB,SAAS,YAAY,yBAAyB,MAAM,GAAG,EAAE;AAAA,MAC1E,kBAAkB,SAAS,YAAY,0BAA0B,MAAM,GAAG,EAAE;AAAA,IAC9E;AAAA,IACA,SAAS;AAAA,MACP,SAAS,YAAY,mBAAmB,OAAO,MAAM;AAAA,MACrD,MAAM,YAAY,gBAAgB,EAAE;AAAA,MACpC,OAAO,SAAS,YAAY,kBAAkB,OAAO,KAAK,KAAK,KAAK,GAAI,CAAC,GAAG,EAAE;AAAA,MAC9E,mBAAmB,YAAY,+BAA+B,MAAM,MAAM;AAAA,IAC5E;AAAA,IACA,YAAY;AAAA,MACV,SAAS,YAAY,sBAAsB,MAAM,MAAM;AAAA,MACvD,qBAAqB,SAAS,YAAY,yBAAyB,GAAG,GAAG,EAAE;AAAA,MAC3E,WAAW,SAAS,YAAY,yBAAyB,QAAQ,GAAG,EAAE;AAAA,MACtE,WAAW,2BAA2B,WAAW;AAAA,MACjD,UAAU,2BAA2B,UAAU;AAAA,IACjD;AAAA,IACA,MAAM;AAAA,MACJ,SAAS,YAAY,gBAAgB,MAAM,MAAM;AAAA,MACjD,WAAW,SAAS,YAAY,mBAAmB,QAAQ,GAAG,EAAE;AAAA,MAChE,oBAAoB,SAAS,YAAY,6BAA6B,KAAK,GAAG,EAAE;AAAA,MAChF,OAAO,qBAAqB;AAAA,IAC9B;AAAA,IACA,YAAY;AAAA,MACV,SAAS,YAAY,uBAAuB,MAAM,MAAM;AAAA,MACxD,YAAY,SAAS,YAAY,2BAA2B,QAAQ,GAAG,EAAE;AAAA,MACzE,UAAU,YAAY,wBAAwB,4BAA4B;AAAA,MAC1E,gBAAgB,SAAS,YAAY,gCAAgC,QAAQ,GAAG,EAAE;AAAA,IACpF;AAAA,IACA,OAAO;AAAA,MACL,YAAY,QAAQ,IAAI,qBAAqB;AAAA,MAC7C,WAAW,QAAQ,IAAI,oBAAoB;AAAA,MAC3C,SAAS,QAAQ,IAAI,kBAAkB;AAAA,IACzC;AAAA,IACA,QAAS,YAAY,UAAU,OAAO,MAAM,OAAO,OAAO;AAAA,IAC1D,eAAe,QAAQ,IAAI,kBAAkB;AAAA,EAC/C;AACF;AAEA,SAAS,oBAAoB,KAA2B;AACtD,MAAI,QAAQ,eAAgB,QAAO;AACnC,MAAI,QAAQ,YAAa,QAAO;AAChC,SAAO;AACT;AAEA,SAAS,gBAAgB,MAA4B;AACnD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,YAAY,iBAAiB,QAAQ;AAAA,IAC9C,KAAK;AACH,aAAO,YAAY,oBAAoB,WAAW;AAAA,IACpD;AACE,aAAO,YAAY,iBAAiB,iBAAiB;AAAA,EACzD;AACF;AAEA,SAAS,gBAA8B;AACrC,QAAM,OAAO,oBAAoB,YAAY,kBAAkB,iBAAiB,CAAC;AACjF,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,gBAAgB,IAAI;AAAA,IAC5B,gBAAgB,SAAS,YAAY,2BAA2B,SAAS,GAAG,EAAE;AAAA,IAC9E,gBAAgB,YAAY,oBAAoB,IAAI;AAAA,IACpD,OAAO,YAAY,YAAY,gBAAgB;AAAA,EACjD;AACF;AAEA,SAAS,2BAA2B,MAAuD;AACzF,QAAM,aAAa,YAAY,kBAAkB,iBAAiB;AAClE,QAAM,WAAW,YAAY,cAAc,IAAI,SAAS,UAAU;AAClE,QAAM,OAAO,oBAAoB,QAAQ;AAEzC,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,YAAY,cAAc,IAAI,WAAW,gBAAgB,IAAI,CAAC;AAAA,IACtE,gBAAgB,YAAY,oBAAoB,IAAI;AAAA,IACpD,OAAO,QAAQ,IAAI,cAAc,IAAI,QAAQ,KAAK,YAAY,YAAY,gBAAgB;AAAA,EAC5F;AACF;AAEA,SAAS,uBAAwC;AAG/C,QAAM,WAAW,YAAY,mBAAmB,iBAAiB;AACjE,QAAM,OAAO,oBAAoB,QAAQ;AAEzC,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,YAAY,qBAAqB,gBAAgB,IAAI,CAAC;AAAA,IAC9D,gBAAgB,YAAY,oBAAoB,IAAI;AAAA,IACpD,OAAO,QAAQ,IAAI,oBAAoB,YAAY,YAAY,gBAAgB;AAAA,EACjF;AACF;","names":[]}
|