autosnippet 3.3.6 → 3.3.7
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/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
- package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
- package/dashboard/dist/assets/index-DzoB7kxK.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +1 -0
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
- package/dist/lib/agent/forced-summary.js +7 -2
- package/dist/lib/cli/AiScanService.js +4 -4
- package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
- package/dist/lib/external/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +16 -8
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +2 -1
- package/dist/lib/external/mcp/handlers/evolve-external.js +5 -2
- package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
- package/dist/lib/http/routes/ai.js +111 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/modules.js +27 -0
- package/dist/lib/http/routes/recipes.js +7 -0
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- package/dist/lib/injection/ServiceContainer.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +11 -27
- package/dist/lib/injection/ServiceMap.d.ts +2 -0
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- package/dist/lib/injection/modules/PanoramaModule.js +1 -1
- package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
- package/dist/lib/service/cleanup/CleanupService.js +284 -37
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +6 -0
- package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +23 -10
- package/dist/lib/service/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
- package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +1 -1
- package/dist/lib/service/panorama/DimensionAnalyzer.js +31 -17
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
- package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
- package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
- package/dist/lib/service/panorama/PanoramaService.js +10 -5
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
- package/dist/lib/service/panorama/RoleRefiner.js +41 -0
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +1 -0
- package/dist/lib/service/skills/SignalCollector.js +6 -5
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- package/dist/lib/shared/LanguageService.js +3 -0
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
- package/dist/lib/shared/schemas/http-requests.js +9 -6
- package/dist/lib/types/knowledge-wire.d.ts +1 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
- package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
- package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module StarlarkParser
|
|
3
|
+
* @description Starlark (Python 子集) 轻量解析器 — 从 BUILD / BUILD.bazel / BUCK 文件提取构建目标信息
|
|
4
|
+
*
|
|
5
|
+
* 支持解析:
|
|
6
|
+
* - load() 语句 → 推断语言
|
|
7
|
+
* - 目标声明 (swift_library, cc_binary, java_library 等)
|
|
8
|
+
* - name / deps / srcs / visibility 字段
|
|
9
|
+
*
|
|
10
|
+
* 设计策略: 正则 + 逐行状态机(不做宏展开)
|
|
11
|
+
*/
|
|
12
|
+
export interface StarlarkTarget {
|
|
13
|
+
rule: string;
|
|
14
|
+
name: string;
|
|
15
|
+
srcs: string[];
|
|
16
|
+
deps: string[];
|
|
17
|
+
visibility: string[];
|
|
18
|
+
testonly?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface LoadStatement {
|
|
21
|
+
repository: string;
|
|
22
|
+
path: string;
|
|
23
|
+
symbols: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface ParsedBuildFile {
|
|
26
|
+
targets: StarlarkTarget[];
|
|
27
|
+
loads: LoadStatement[];
|
|
28
|
+
}
|
|
29
|
+
export declare const RULE_TO_LANGUAGE: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* 解析单个 BUILD/BUILD.bazel/BUCK 文件内容
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseStarlarkBuildFile(content: string): ParsedBuildFile;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module StarlarkParser
|
|
3
|
+
* @description Starlark (Python 子集) 轻量解析器 — 从 BUILD / BUILD.bazel / BUCK 文件提取构建目标信息
|
|
4
|
+
*
|
|
5
|
+
* 支持解析:
|
|
6
|
+
* - load() 语句 → 推断语言
|
|
7
|
+
* - 目标声明 (swift_library, cc_binary, java_library 等)
|
|
8
|
+
* - name / deps / srcs / visibility 字段
|
|
9
|
+
*
|
|
10
|
+
* 设计策略: 正则 + 逐行状态机(不做宏展开)
|
|
11
|
+
*/
|
|
12
|
+
// ── 规则名 → 语言映射 ────────────────────────────────
|
|
13
|
+
export const RULE_TO_LANGUAGE = {
|
|
14
|
+
// Bazel
|
|
15
|
+
swift_library: 'swift',
|
|
16
|
+
swift_binary: 'swift',
|
|
17
|
+
swift_test: 'swift',
|
|
18
|
+
cc_library: 'cpp',
|
|
19
|
+
cc_binary: 'cpp',
|
|
20
|
+
cc_test: 'cpp',
|
|
21
|
+
java_library: 'java',
|
|
22
|
+
java_binary: 'java',
|
|
23
|
+
java_test: 'java',
|
|
24
|
+
kt_jvm_library: 'kotlin',
|
|
25
|
+
kt_jvm_binary: 'kotlin',
|
|
26
|
+
py_library: 'python',
|
|
27
|
+
py_binary: 'python',
|
|
28
|
+
py_test: 'python',
|
|
29
|
+
go_library: 'go',
|
|
30
|
+
go_binary: 'go',
|
|
31
|
+
go_test: 'go',
|
|
32
|
+
rust_library: 'rust',
|
|
33
|
+
rust_binary: 'rust',
|
|
34
|
+
rust_test: 'rust',
|
|
35
|
+
ts_project: 'typescript',
|
|
36
|
+
proto_library: 'protobuf',
|
|
37
|
+
// Buck2
|
|
38
|
+
cxx_library: 'cpp',
|
|
39
|
+
cxx_binary: 'cpp',
|
|
40
|
+
cxx_test: 'cpp',
|
|
41
|
+
android_library: 'kotlin',
|
|
42
|
+
android_binary: 'kotlin',
|
|
43
|
+
apple_library: 'swift',
|
|
44
|
+
apple_binary: 'swift',
|
|
45
|
+
python_library: 'python',
|
|
46
|
+
python_binary: 'python',
|
|
47
|
+
// Pants
|
|
48
|
+
python_source: 'python',
|
|
49
|
+
python_sources: 'python',
|
|
50
|
+
docker_image: 'docker',
|
|
51
|
+
};
|
|
52
|
+
// ── 正则模式 ────────────────────────────────────────
|
|
53
|
+
const LOAD_RE = /^load\(\s*"([^"]+)"\s*,\s*((?:"[^"]+"(?:\s*,\s*)?)+)\s*\)/;
|
|
54
|
+
const RULE_CALL_RE = /^(\w+)\(\s*$/;
|
|
55
|
+
const NAME_RE = /name\s*=\s*"([^"]+)"/;
|
|
56
|
+
const TESTONLY_RE = /testonly\s*=\s*(True|1)/;
|
|
57
|
+
const STRING_LIST_RE = (field) => new RegExp(`${field}\\s*=\\s*(?:glob\\(\\s*)?\\[([^\\]]*)\\]`, 's');
|
|
58
|
+
const DEP_LABEL_RE = /"((?:\/\/[^"]*|:[^"]*))"/g;
|
|
59
|
+
const GLOB_RE = /glob\(\s*\[([^\]]*)\]\s*\)/;
|
|
60
|
+
// ── 公开 API ────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* 解析单个 BUILD/BUILD.bazel/BUCK 文件内容
|
|
63
|
+
*/
|
|
64
|
+
export function parseStarlarkBuildFile(content) {
|
|
65
|
+
const result = { targets: [], loads: [] };
|
|
66
|
+
const lines = content.split('\n');
|
|
67
|
+
// Pass 1: 提取 load 语句
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
const trimmed = line.trim();
|
|
70
|
+
if (trimmed.startsWith('#')) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const loadMatch = trimmed.match(LOAD_RE);
|
|
74
|
+
if (loadMatch) {
|
|
75
|
+
const fullLabel = loadMatch[1];
|
|
76
|
+
const symbolsPart = loadMatch[2];
|
|
77
|
+
// 解析 repository 和 path
|
|
78
|
+
let repository = '';
|
|
79
|
+
let path = fullLabel;
|
|
80
|
+
if (fullLabel.startsWith('@')) {
|
|
81
|
+
const slashIdx = fullLabel.indexOf('//');
|
|
82
|
+
if (slashIdx !== -1) {
|
|
83
|
+
repository = fullLabel.substring(0, slashIdx);
|
|
84
|
+
path = fullLabel.substring(slashIdx);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const symbols = [];
|
|
88
|
+
const symRe = /"([^"]+)"/g;
|
|
89
|
+
let symMatch;
|
|
90
|
+
while ((symMatch = symRe.exec(symbolsPart)) !== null) {
|
|
91
|
+
symbols.push(symMatch[1]);
|
|
92
|
+
}
|
|
93
|
+
result.loads.push({ repository, path, symbols });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Pass 2: 提取目标声明(逐行状态机)
|
|
97
|
+
let i = 0;
|
|
98
|
+
while (i < lines.length) {
|
|
99
|
+
const trimmed = lines[i].trim();
|
|
100
|
+
// 跳过注释和空行
|
|
101
|
+
if (trimmed.startsWith('#') || trimmed === '') {
|
|
102
|
+
i++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// 检测规则调用开始: rule_name(
|
|
106
|
+
const ruleMatch = trimmed.match(RULE_CALL_RE);
|
|
107
|
+
if (ruleMatch) {
|
|
108
|
+
const rule = ruleMatch[1];
|
|
109
|
+
// 收集整个调用块直到匹配的 )
|
|
110
|
+
const blockLines = [trimmed];
|
|
111
|
+
let depth = 1;
|
|
112
|
+
let j = i + 1;
|
|
113
|
+
while (j < lines.length && depth > 0) {
|
|
114
|
+
const bLine = lines[j];
|
|
115
|
+
for (const ch of bLine) {
|
|
116
|
+
if (ch === '(') {
|
|
117
|
+
depth++;
|
|
118
|
+
}
|
|
119
|
+
if (ch === ')') {
|
|
120
|
+
depth--;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
blockLines.push(bLine);
|
|
124
|
+
j++;
|
|
125
|
+
}
|
|
126
|
+
const block = blockLines.join('\n');
|
|
127
|
+
const target = parseTargetBlock(rule, block);
|
|
128
|
+
if (target) {
|
|
129
|
+
result.targets.push(target);
|
|
130
|
+
}
|
|
131
|
+
i = j;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// 也检测单行调用: rule_name(name = "...")
|
|
135
|
+
const inlineMatch = trimmed.match(/^(\w+)\(/);
|
|
136
|
+
if (inlineMatch && RULE_TO_LANGUAGE[inlineMatch[1]]) {
|
|
137
|
+
// 同样收集到闭合 )
|
|
138
|
+
const rule = inlineMatch[1];
|
|
139
|
+
const blockLines = [trimmed];
|
|
140
|
+
let depth = 0;
|
|
141
|
+
for (const ch of trimmed) {
|
|
142
|
+
if (ch === '(') {
|
|
143
|
+
depth++;
|
|
144
|
+
}
|
|
145
|
+
if (ch === ')') {
|
|
146
|
+
depth--;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
let j = i + 1;
|
|
150
|
+
while (j < lines.length && depth > 0) {
|
|
151
|
+
const bLine = lines[j];
|
|
152
|
+
for (const ch of bLine) {
|
|
153
|
+
if (ch === '(') {
|
|
154
|
+
depth++;
|
|
155
|
+
}
|
|
156
|
+
if (ch === ')') {
|
|
157
|
+
depth--;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
blockLines.push(bLine);
|
|
161
|
+
j++;
|
|
162
|
+
}
|
|
163
|
+
const block = blockLines.join('\n');
|
|
164
|
+
const target = parseTargetBlock(rule, block);
|
|
165
|
+
if (target) {
|
|
166
|
+
result.targets.push(target);
|
|
167
|
+
}
|
|
168
|
+
i = j;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
i++;
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
// ── 内部解析函数 ────────────────────────────────────
|
|
176
|
+
function parseTargetBlock(rule, block) {
|
|
177
|
+
const nameMatch = block.match(NAME_RE);
|
|
178
|
+
if (!nameMatch) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
rule,
|
|
183
|
+
name: nameMatch[1],
|
|
184
|
+
srcs: extractStringList(block, 'srcs'),
|
|
185
|
+
deps: extractDepLabels(block),
|
|
186
|
+
visibility: extractStringList(block, 'visibility'),
|
|
187
|
+
testonly: TESTONLY_RE.test(block) ? true : undefined,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function extractStringList(block, field) {
|
|
191
|
+
const listMatch = block.match(STRING_LIST_RE(field));
|
|
192
|
+
if (!listMatch) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
let inner = listMatch[1];
|
|
196
|
+
// 处理 glob() 模式
|
|
197
|
+
const globMatch = inner.match(GLOB_RE);
|
|
198
|
+
if (globMatch) {
|
|
199
|
+
inner = globMatch[1];
|
|
200
|
+
}
|
|
201
|
+
const items = [];
|
|
202
|
+
const strRe = /"([^"]+)"/g;
|
|
203
|
+
let m;
|
|
204
|
+
while ((m = strRe.exec(inner)) !== null) {
|
|
205
|
+
items.push(m[1]);
|
|
206
|
+
}
|
|
207
|
+
return items;
|
|
208
|
+
}
|
|
209
|
+
function extractDepLabels(block) {
|
|
210
|
+
const depsMatch = block.match(STRING_LIST_RE('deps'));
|
|
211
|
+
if (!depsMatch) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const inner = depsMatch[1];
|
|
215
|
+
const deps = [];
|
|
216
|
+
const re = new RegExp(DEP_LABEL_RE.source, 'g');
|
|
217
|
+
let m;
|
|
218
|
+
while ((m = re.exec(inner)) !== null) {
|
|
219
|
+
deps.push(m[1]);
|
|
220
|
+
}
|
|
221
|
+
// 也捕获非标签格式的字符串依赖
|
|
222
|
+
const strRe = /"([^"]+)"/g;
|
|
223
|
+
while ((m = strRe.exec(inner)) !== null) {
|
|
224
|
+
if (!m[1].startsWith('//') && !m[1].startsWith(':') && !deps.includes(m[1])) {
|
|
225
|
+
deps.push(m[1]);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return deps;
|
|
229
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module YamlConfigParser
|
|
3
|
+
* @description YAML 配置解析器 — 从 XcodeGen project.yml 中提取项目结构信息
|
|
4
|
+
*
|
|
5
|
+
* 支持解析:
|
|
6
|
+
* - targets(构建目标)及其依赖关系
|
|
7
|
+
* - settings(项目级/目标级构建设置)
|
|
8
|
+
* - schemes(构建方案)
|
|
9
|
+
* - sources(源文件路径)
|
|
10
|
+
*
|
|
11
|
+
* 使用 js-yaml 进行安全解析(禁用危险的 YAML 特性)。
|
|
12
|
+
*/
|
|
13
|
+
import type { ParsedModuleSpec, ParsedProjectConfig } from './RubyDslParser.js';
|
|
14
|
+
/**
|
|
15
|
+
* 解析 XcodeGen project.yml 内容
|
|
16
|
+
* 返回与 RubyDslParser 兼容的 ParsedProjectConfig
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseXcodeGenProject(content: string): ParsedProjectConfig;
|
|
19
|
+
/**
|
|
20
|
+
* 解析单个 target 为 ParsedModuleSpec 格式
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseXcodeGenTarget(targetName: string, content: string): ParsedModuleSpec | null;
|
|
23
|
+
/**
|
|
24
|
+
* 提取所有 target 的依赖图
|
|
25
|
+
* 返回 [from, to][] 形式的有向边列表
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractXcodeGenDependencyEdges(content: string): Array<[string, string]>;
|
|
28
|
+
export interface ParsedMelosProject {
|
|
29
|
+
name: string;
|
|
30
|
+
packageGlobs: string[];
|
|
31
|
+
scripts: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 解析 melos.yaml 内容
|
|
35
|
+
* 提取项目名、包路径 glob 模式、scripts 列表
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseMelosProject(content: string): ParsedMelosProject;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module YamlConfigParser
|
|
3
|
+
* @description YAML 配置解析器 — 从 XcodeGen project.yml 中提取项目结构信息
|
|
4
|
+
*
|
|
5
|
+
* 支持解析:
|
|
6
|
+
* - targets(构建目标)及其依赖关系
|
|
7
|
+
* - settings(项目级/目标级构建设置)
|
|
8
|
+
* - schemes(构建方案)
|
|
9
|
+
* - sources(源文件路径)
|
|
10
|
+
*
|
|
11
|
+
* 使用 js-yaml 进行安全解析(禁用危险的 YAML 特性)。
|
|
12
|
+
*/
|
|
13
|
+
import yaml from 'js-yaml';
|
|
14
|
+
// ── 目标类型 → 层级推断 ────────────────────────────────
|
|
15
|
+
const TARGET_TYPE_LAYER = {
|
|
16
|
+
application: 'App',
|
|
17
|
+
'app-extension': 'Extension',
|
|
18
|
+
framework: 'Framework',
|
|
19
|
+
'static-library': 'Library',
|
|
20
|
+
'dynamic-library': 'Library',
|
|
21
|
+
bundle: 'Resource',
|
|
22
|
+
'unit-test': 'Test',
|
|
23
|
+
'ui-test': 'Test',
|
|
24
|
+
tool: 'Tool',
|
|
25
|
+
};
|
|
26
|
+
// ── 公开 API ────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* 解析 XcodeGen project.yml 内容
|
|
29
|
+
* 返回与 RubyDslParser 兼容的 ParsedProjectConfig
|
|
30
|
+
*/
|
|
31
|
+
export function parseXcodeGenProject(content) {
|
|
32
|
+
let doc;
|
|
33
|
+
try {
|
|
34
|
+
doc = yaml.load(content, { schema: yaml.CORE_SCHEMA });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { layers: [], globalDependencies: [] };
|
|
38
|
+
}
|
|
39
|
+
if (!doc || typeof doc !== 'object') {
|
|
40
|
+
return { layers: [], globalDependencies: [] };
|
|
41
|
+
}
|
|
42
|
+
const result = {
|
|
43
|
+
layers: [],
|
|
44
|
+
globalDependencies: [],
|
|
45
|
+
};
|
|
46
|
+
// 提取宿主应用
|
|
47
|
+
if (doc.name) {
|
|
48
|
+
result.hostApp = { name: doc.name, version: '0.0.0' };
|
|
49
|
+
}
|
|
50
|
+
if (!doc.targets) {
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
// 将 targets 按类型分层
|
|
54
|
+
const layerMap = new Map();
|
|
55
|
+
for (const [targetName, target] of Object.entries(doc.targets)) {
|
|
56
|
+
const targetType = target.type ?? 'framework';
|
|
57
|
+
const layerName = TARGET_TYPE_LAYER[targetType] ?? 'Other';
|
|
58
|
+
const isLocal = !isExternalTarget(targetName, doc);
|
|
59
|
+
const mod = {
|
|
60
|
+
name: targetName,
|
|
61
|
+
version: '0.0.0',
|
|
62
|
+
isLocal,
|
|
63
|
+
localPath: extractSourcePath(target),
|
|
64
|
+
group: layerName,
|
|
65
|
+
};
|
|
66
|
+
if (!layerMap.has(layerName)) {
|
|
67
|
+
layerMap.set(layerName, []);
|
|
68
|
+
}
|
|
69
|
+
layerMap.get(layerName)?.push(mod);
|
|
70
|
+
}
|
|
71
|
+
// 转为 ParsedLayer[]
|
|
72
|
+
let order = 0;
|
|
73
|
+
for (const [name, modules] of layerMap.entries()) {
|
|
74
|
+
result.layers.push({
|
|
75
|
+
name,
|
|
76
|
+
order: order++,
|
|
77
|
+
accessibleLayers: [],
|
|
78
|
+
modules,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// 提取 SPM packages → globalDependencies
|
|
82
|
+
if (doc.packages) {
|
|
83
|
+
for (const [pkgName, pkg] of Object.entries(doc.packages)) {
|
|
84
|
+
result.globalDependencies.push({
|
|
85
|
+
name: pkgName,
|
|
86
|
+
version: pkg.from ?? pkg.version ?? pkg.branch ?? '0.0.0',
|
|
87
|
+
isLocal: !!pkg.path,
|
|
88
|
+
localPath: pkg.path,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 解析单个 target 为 ParsedModuleSpec 格式
|
|
96
|
+
*/
|
|
97
|
+
export function parseXcodeGenTarget(targetName, content) {
|
|
98
|
+
let doc;
|
|
99
|
+
try {
|
|
100
|
+
doc = yaml.load(content, { schema: yaml.CORE_SCHEMA });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (!doc?.targets?.[targetName]) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const target = doc.targets[targetName];
|
|
109
|
+
return {
|
|
110
|
+
name: targetName,
|
|
111
|
+
version: '0.0.0',
|
|
112
|
+
sources: extractSourcePath(target) ?? targetName,
|
|
113
|
+
dependencies: extractTargetDependencies(target),
|
|
114
|
+
publicHeaders: [],
|
|
115
|
+
deploymentTarget: extractDeploymentTarget(target),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 提取所有 target 的依赖图
|
|
120
|
+
* 返回 [from, to][] 形式的有向边列表
|
|
121
|
+
*/
|
|
122
|
+
export function extractXcodeGenDependencyEdges(content) {
|
|
123
|
+
let doc;
|
|
124
|
+
try {
|
|
125
|
+
doc = yaml.load(content, { schema: yaml.CORE_SCHEMA });
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
if (!doc?.targets) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
const edges = [];
|
|
134
|
+
for (const [targetName, target] of Object.entries(doc.targets)) {
|
|
135
|
+
if (!target.dependencies) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
for (const dep of target.dependencies) {
|
|
139
|
+
const depName = dep.target ?? dep.framework ?? dep.package ?? dep.carthage;
|
|
140
|
+
if (depName) {
|
|
141
|
+
edges.push([targetName, depName]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return edges;
|
|
146
|
+
}
|
|
147
|
+
// ── 内部帮助函数 ────────────────────────────────────
|
|
148
|
+
function extractSourcePath(target) {
|
|
149
|
+
if (!target.sources || target.sources.length === 0) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const first = target.sources[0];
|
|
153
|
+
if (typeof first === 'string') {
|
|
154
|
+
return first;
|
|
155
|
+
}
|
|
156
|
+
return first.path;
|
|
157
|
+
}
|
|
158
|
+
function extractTargetDependencies(target) {
|
|
159
|
+
if (!target.dependencies) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
return target.dependencies
|
|
163
|
+
.map((dep) => dep.target ?? dep.framework ?? dep.package ?? dep.carthage)
|
|
164
|
+
.filter((name) => !!name);
|
|
165
|
+
}
|
|
166
|
+
function extractDeploymentTarget(target) {
|
|
167
|
+
if (!target.deploymentTarget) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
if (typeof target.deploymentTarget === 'string') {
|
|
171
|
+
return target.deploymentTarget;
|
|
172
|
+
}
|
|
173
|
+
// Object form: { iOS: "15.0", macOS: "12.0" }
|
|
174
|
+
const values = Object.values(target.deploymentTarget);
|
|
175
|
+
return values[0];
|
|
176
|
+
}
|
|
177
|
+
function isExternalTarget(targetName, doc) {
|
|
178
|
+
// SPM packages referenced as targets are external
|
|
179
|
+
if (doc.packages?.[targetName]) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
// Targets defined in the project are local
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 解析 melos.yaml 内容
|
|
187
|
+
* 提取项目名、包路径 glob 模式、scripts 列表
|
|
188
|
+
*/
|
|
189
|
+
export function parseMelosProject(content) {
|
|
190
|
+
const result = {
|
|
191
|
+
name: '',
|
|
192
|
+
packageGlobs: [],
|
|
193
|
+
scripts: [],
|
|
194
|
+
};
|
|
195
|
+
try {
|
|
196
|
+
const doc = yaml.load(content, { schema: yaml.CORE_SCHEMA });
|
|
197
|
+
if (!doc) {
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
result.name = doc.name ?? '';
|
|
201
|
+
if (Array.isArray(doc.packages)) {
|
|
202
|
+
result.packageGlobs = doc.packages.filter((p) => typeof p === 'string');
|
|
203
|
+
}
|
|
204
|
+
if (doc.scripts && typeof doc.scripts === 'object') {
|
|
205
|
+
result.scripts = Object.keys(doc.scripts);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// YAML 解析失败时返回空结果
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
@@ -61,6 +61,7 @@ export declare class KnowledgeEntry {
|
|
|
61
61
|
from: string;
|
|
62
62
|
to: string;
|
|
63
63
|
at: number;
|
|
64
|
+
by?: string;
|
|
64
65
|
}>;
|
|
65
66
|
autoApprovable: boolean;
|
|
66
67
|
stagingDeadline: number | null;
|
|
@@ -152,6 +153,11 @@ export declare class KnowledgeEntry {
|
|
|
152
153
|
success: boolean;
|
|
153
154
|
error?: string;
|
|
154
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* 将最后一条 lifecycleHistory 条目标记操作人。
|
|
158
|
+
* 由 KnowledgeService._lifecycleTransition() 在 entity method 执行后调用。
|
|
159
|
+
*/
|
|
160
|
+
stampLastTransition(by: string): void;
|
|
155
161
|
/** 是否处于候选阶段 */
|
|
156
162
|
isCandidate(): boolean;
|
|
157
163
|
/** 是否可被 Guard/Search/Export 消费 */
|
|
@@ -194,7 +200,7 @@ export declare class KnowledgeEntry {
|
|
|
194
200
|
/** JSON → Domain (camelCase 直入) */
|
|
195
201
|
static fromJSON(data: unknown): KnowledgeEntry;
|
|
196
202
|
/** @returns } */
|
|
197
|
-
_transition(to: string): {
|
|
203
|
+
_transition(to: string, by?: string): {
|
|
198
204
|
success: boolean;
|
|
199
205
|
error?: string;
|
|
200
206
|
};
|
|
@@ -173,6 +173,16 @@ export class KnowledgeEntry {
|
|
|
173
173
|
}
|
|
174
174
|
return result;
|
|
175
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* 将最后一条 lifecycleHistory 条目标记操作人。
|
|
178
|
+
* 由 KnowledgeService._lifecycleTransition() 在 entity method 执行后调用。
|
|
179
|
+
*/
|
|
180
|
+
stampLastTransition(by) {
|
|
181
|
+
const last = this.lifecycleHistory[this.lifecycleHistory.length - 1];
|
|
182
|
+
if (last) {
|
|
183
|
+
last.by = by;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
176
186
|
/* ═══ 谓词 ═══════════════════════════════════════════ */
|
|
177
187
|
/** 是否处于候选阶段 */
|
|
178
188
|
isCandidate() {
|
|
@@ -289,18 +299,22 @@ export class KnowledgeEntry {
|
|
|
289
299
|
}
|
|
290
300
|
/* ═══ 私有 ═══════════════════════════════════════════ */
|
|
291
301
|
/** @returns } */
|
|
292
|
-
_transition(to) {
|
|
302
|
+
_transition(to, by) {
|
|
293
303
|
if (!isValidTransition(this.lifecycle, to)) {
|
|
294
304
|
return {
|
|
295
305
|
success: false,
|
|
296
306
|
error: `Invalid lifecycle transition: ${this.lifecycle} → ${to}`,
|
|
297
307
|
};
|
|
298
308
|
}
|
|
299
|
-
|
|
309
|
+
const entry = {
|
|
300
310
|
from: this.lifecycle,
|
|
301
311
|
to,
|
|
302
312
|
at: this._now(),
|
|
303
|
-
}
|
|
313
|
+
};
|
|
314
|
+
if (by) {
|
|
315
|
+
entry.by = by;
|
|
316
|
+
}
|
|
317
|
+
this.lifecycleHistory.push(entry);
|
|
304
318
|
this.lifecycle = to;
|
|
305
319
|
this.updatedAt = this._now();
|
|
306
320
|
return { success: true };
|
|
@@ -148,6 +148,13 @@ export declare class AiProvider {
|
|
|
148
148
|
name: string;
|
|
149
149
|
timeout: number;
|
|
150
150
|
_fallbackFrom?: string;
|
|
151
|
+
/**
|
|
152
|
+
* Token 用量回调 — 每次 API 调用后触发(包括 chat / chatWithStructuredOutput / chatWithTools)
|
|
153
|
+
* 由外部(如 DI 容器)注入以实现全局 token 计量。
|
|
154
|
+
*/
|
|
155
|
+
_onTokenUsage: ((usage: TokenUsage & {
|
|
156
|
+
source?: string;
|
|
157
|
+
}) => void) | null;
|
|
151
158
|
constructor(config?: AiProviderConfig);
|
|
152
159
|
_acquireRequestSlot(): Promise<void>;
|
|
153
160
|
_releaseRequestSlot(): void;
|
|
@@ -158,6 +165,11 @@ export declare class AiProvider {
|
|
|
158
165
|
* @param context {history: [], temperature, maxTokens}
|
|
159
166
|
*/
|
|
160
167
|
chat(prompt: string, context?: ChatContext): Promise<string>;
|
|
168
|
+
/**
|
|
169
|
+
* 从 API 原始响应中提取 token 用量并触发回调。
|
|
170
|
+
* 子类在 chat() / chatWithStructuredOutput() 中调用。
|
|
171
|
+
*/
|
|
172
|
+
_emitTokenUsage(usage: TokenUsage | null | undefined, source?: string): void;
|
|
161
173
|
/** 摘要 - 对代码/文档生成结构化摘要 */
|
|
162
174
|
summarize(code: string): Promise<unknown>;
|
|
163
175
|
/** 向量嵌入 - 返回浮点数组 */
|
|
@@ -21,6 +21,11 @@ export class AiProvider {
|
|
|
21
21
|
name;
|
|
22
22
|
timeout;
|
|
23
23
|
_fallbackFrom;
|
|
24
|
+
/**
|
|
25
|
+
* Token 用量回调 — 每次 API 调用后触发(包括 chat / chatWithStructuredOutput / chatWithTools)
|
|
26
|
+
* 由外部(如 DI 容器)注入以实现全局 token 计量。
|
|
27
|
+
*/
|
|
28
|
+
_onTokenUsage = null;
|
|
24
29
|
constructor(config = {}) {
|
|
25
30
|
this.model = config.model || '';
|
|
26
31
|
this.apiKey = config.apiKey || '';
|
|
@@ -79,6 +84,25 @@ export class AiProvider {
|
|
|
79
84
|
async chat(prompt, context = {}) {
|
|
80
85
|
throw new Error(`${this.name}.chat() not implemented`);
|
|
81
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* 从 API 原始响应中提取 token 用量并触发回调。
|
|
89
|
+
* 子类在 chat() / chatWithStructuredOutput() 中调用。
|
|
90
|
+
*/
|
|
91
|
+
_emitTokenUsage(usage, source) {
|
|
92
|
+
if (!usage || !this._onTokenUsage) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const total = (usage.inputTokens || 0) + (usage.outputTokens || 0);
|
|
96
|
+
if (total === 0) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
this._onTokenUsage({ ...usage, source });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
/* token tracking should never break execution */
|
|
104
|
+
}
|
|
105
|
+
}
|
|
82
106
|
/** 摘要 - 对代码/文档生成结构化摘要 */
|
|
83
107
|
async summarize(code) {
|
|
84
108
|
throw new Error(`${this.name}.summarize() not implemented`);
|