autosnippet 3.1.0 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/dist/assets/{index-D13KZZ6B.css → index-C-eKKKJx.css} +1 -1
- package/dashboard/dist/assets/{index-Bnm26ulL.js → index-D9fV5GGQ.js} +37 -37
- package/dashboard/dist/index.html +2 -2
- package/lib/domain/knowledge/values/Relations.js +9 -4
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +61 -0
- package/lib/external/mcp/handlers/bootstrap/refine.js +3 -2
- package/lib/http/routes/candidates.js +1 -2
- package/lib/http/routes/wiki.js +16 -0
- package/lib/service/wiki/WikiGenerator.js +13 -4
- package/package.json +1 -1
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>AutoSnippet Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-D9fV5GGQ.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/yaml-qRaU8Ldn.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-CEnWn7aV.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/axios-C0Zqfgkc.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/icons-eQ_rWCus.js">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C-eKKKJx.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -29,10 +29,15 @@ export class Relations {
|
|
|
29
29
|
this._b = {};
|
|
30
30
|
for (const k of RELATION_BUCKETS) {
|
|
31
31
|
const vals = buckets[k] || [];
|
|
32
|
-
this._b[k] = vals
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
this._b[k] = vals
|
|
33
|
+
.map((r) => {
|
|
34
|
+
// 兼容字符串数组:AI prompt 可能返回 ["recipeName"] 而非 [{target,description}]
|
|
35
|
+
if (typeof r === 'string') {
|
|
36
|
+
return r.trim() ? { target: r.trim(), description: '' } : null;
|
|
37
|
+
}
|
|
38
|
+
return { target: r.target || '', description: r.description || '' };
|
|
39
|
+
})
|
|
40
|
+
.filter(Boolean);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -1087,6 +1087,29 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1087
1087
|
const wikiContainer = getWikiContainer();
|
|
1088
1088
|
const { WikiGenerator } = await import('../../../../../service/wiki/WikiGenerator.js');
|
|
1089
1089
|
|
|
1090
|
+
// 同步 wiki 路由的任务状态,让前端轮询 /wiki/status 能看到进度
|
|
1091
|
+
let patchWikiTask = null;
|
|
1092
|
+
let realtimeService = null;
|
|
1093
|
+
try {
|
|
1094
|
+
const wikiRoute = await import('../../../../../http/routes/wiki.js');
|
|
1095
|
+
patchWikiTask = wikiRoute.patchWikiTask;
|
|
1096
|
+
} catch { /* ok */ }
|
|
1097
|
+
try {
|
|
1098
|
+
realtimeService = wikiContainer.singletons?.realtimeService || null;
|
|
1099
|
+
} catch { /* ok */ }
|
|
1100
|
+
|
|
1101
|
+
// 标记任务开始
|
|
1102
|
+
patchWikiTask?.({
|
|
1103
|
+
status: 'running',
|
|
1104
|
+
startedAt: Date.now(),
|
|
1105
|
+
phase: null,
|
|
1106
|
+
progress: 0,
|
|
1107
|
+
message: 'Bootstrap Wiki 生成中...',
|
|
1108
|
+
finishedAt: null,
|
|
1109
|
+
result: null,
|
|
1110
|
+
error: null,
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1090
1113
|
let moduleService = null,
|
|
1091
1114
|
knowledgeService = null,
|
|
1092
1115
|
codeEntityGraph = null;
|
|
@@ -1113,6 +1136,18 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1113
1136
|
projectGraph, // 来自 Step 0.5 构建的 ProjectGraph
|
|
1114
1137
|
codeEntityGraph,
|
|
1115
1138
|
aiProvider: wikiContainer.singletons?.aiProvider || null,
|
|
1139
|
+
onProgress: (phase, progress, message) => {
|
|
1140
|
+
// 同步到 wiki 路由的任务状态
|
|
1141
|
+
patchWikiTask?.({ phase, progress, message });
|
|
1142
|
+
// 通过 Socket.io 推送进度
|
|
1143
|
+
if (realtimeService) {
|
|
1144
|
+
try {
|
|
1145
|
+
realtimeService.broadcastEvent('wiki:progress', {
|
|
1146
|
+
phase, progress, message, timestamp: Date.now(),
|
|
1147
|
+
});
|
|
1148
|
+
} catch { /* non-critical */ }
|
|
1149
|
+
}
|
|
1150
|
+
},
|
|
1116
1151
|
options: { language: process.env.ASD_WIKI_LANG || 'zh' },
|
|
1117
1152
|
});
|
|
1118
1153
|
const wikiResult = await wiki.generate();
|
|
@@ -1123,8 +1158,34 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1123
1158
|
`Dedup removed: ${wikiResult.dedup?.removed?.length || 0}`
|
|
1124
1159
|
);
|
|
1125
1160
|
}
|
|
1161
|
+
|
|
1162
|
+
// 标记任务完成
|
|
1163
|
+
patchWikiTask?.({
|
|
1164
|
+
status: wikiResult.success ? 'done' : 'error',
|
|
1165
|
+
finishedAt: Date.now(),
|
|
1166
|
+
result: wikiResult,
|
|
1167
|
+
error: wikiResult.success ? null : (wikiResult.error || 'Unknown error'),
|
|
1168
|
+
progress: 100,
|
|
1169
|
+
});
|
|
1170
|
+
if (realtimeService) {
|
|
1171
|
+
try {
|
|
1172
|
+
realtimeService.broadcastEvent('wiki:completed', {
|
|
1173
|
+
success: wikiResult.success,
|
|
1174
|
+
filesGenerated: wikiResult.filesGenerated,
|
|
1175
|
+
duration: wikiResult.duration,
|
|
1176
|
+
});
|
|
1177
|
+
} catch { /* non-critical */ }
|
|
1178
|
+
}
|
|
1126
1179
|
} catch (wikiErr) {
|
|
1127
1180
|
logger.warn(`[Bootstrap-v3] Wiki generation failed (non-blocking): ${wikiErr.message}`);
|
|
1181
|
+
try {
|
|
1182
|
+
const wikiRoute = await import('../../../../../http/routes/wiki.js');
|
|
1183
|
+
wikiRoute.patchWikiTask?.({
|
|
1184
|
+
status: 'error',
|
|
1185
|
+
finishedAt: Date.now(),
|
|
1186
|
+
error: wikiErr.message,
|
|
1187
|
+
});
|
|
1188
|
+
} catch { /* ok */ }
|
|
1128
1189
|
}
|
|
1129
1190
|
}
|
|
1130
1191
|
|
|
@@ -171,9 +171,10 @@ ${refineInstruction}
|
|
|
171
171
|
|
|
172
172
|
1. 只修改需要改进的字段,未涉及的必须原样返回。
|
|
173
173
|
2. tags 采用合并策略(保留原有 + 补充新建议),不要删除已有标签。
|
|
174
|
-
3. relations 为 object 格式,key 为关系类型(如 inherits/implements/calls/depends_on/extends/related),value 为 string[]。
|
|
174
|
+
3. relations 为 object 格式,key 为关系类型(如 inherits/implements/calls/depends_on/extends/related),value 为 Array<{target: string, description: string}>。示例: {"related": [{"target": "某 Recipe 标题", "description": "关联原因"}]}。
|
|
175
175
|
4. relations 只能指向已发布的 Recipe,不能在候选之间建立关联。如果没有已发布的 Recipe,relations 应保持为空 {}。
|
|
176
|
-
5.
|
|
176
|
+
5. relations 必须精准:只在候选与某个 Recipe 有明确的技术依赖、继承、调用或扩展关系时才添加。仅仅因为属于同一项目或使用相同框架不构成关联。如果没有强关联,related 应为空数组。
|
|
177
|
+
6. 每个 key 都必须存在,key 名称必须与上述完全一致。
|
|
177
178
|
|
|
178
179
|
仅返回 JSON,不要添加任何其他文字或代码块标记。`;
|
|
179
180
|
|
|
@@ -285,8 +285,7 @@ ${userPrompt}
|
|
|
285
285
|
2. **未涉及的字段必须原样返回**,不得做任何改写、改善、优化或翻译。
|
|
286
286
|
3. 如果不确定用户指的是哪个字段,优先修改 description(摘要)、pattern(代码)、markdown(文档)、rationale(设计原理)。
|
|
287
287
|
4. **翻译/语言转换类指令**(如“翻译为中文”): 翻译 description、pattern、markdown、rationale、aiInsight、agentNotes 等文本字段,但 tags/relations/confidence 保持原样。
|
|
288
|
-
5. **tags 和 relations** 只在用户明确提及“标签”或“关联”时才修改,其他情况一律原样返回。
|
|
289
|
-
|
|
288
|
+
5. **tags 和 relations** 只在用户明确提及“标签”或“关联”时才修改,其他情况一律原样返回。6. **relations 格式**: object,key 为关系类型,value 为 Array<{target: string, description: string}>。示例: {"related": [{"target": "某 Recipe", "description": "原因"}]}。
|
|
290
289
|
## 输出格式
|
|
291
290
|
|
|
292
291
|
返回严格符合以下结构的 JSON,不要添加任何其他文字或代码块标记:
|
package/lib/http/routes/wiki.js
CHANGED
|
@@ -54,6 +54,22 @@ function resetWikiTask() {
|
|
|
54
54
|
currentGenerator = null;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* 外部读取 wikiTask 状态(供 bootstrap orchestrator 等外部流程同步使用)
|
|
59
|
+
* @returns {typeof wikiTask}
|
|
60
|
+
*/
|
|
61
|
+
export function getWikiTask() {
|
|
62
|
+
return wikiTask;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 外部设置 wikiTask 状态(供 bootstrap orchestrator 等外部流程同步使用)
|
|
67
|
+
* @param {Partial<typeof wikiTask>} patch
|
|
68
|
+
*/
|
|
69
|
+
export function patchWikiTask(patch) {
|
|
70
|
+
Object.assign(wikiTask, patch);
|
|
71
|
+
}
|
|
72
|
+
|
|
57
73
|
/**
|
|
58
74
|
* 创建 WikiGenerator 实例
|
|
59
75
|
*/
|
|
@@ -639,14 +639,19 @@ export class WikiGenerator {
|
|
|
639
639
|
});
|
|
640
640
|
}
|
|
641
641
|
|
|
642
|
-
// ── 7. 文件夹画像文档
|
|
643
|
-
//
|
|
642
|
+
// ── 7. 文件夹画像文档 ──
|
|
643
|
+
// 触发条件 (满足任一即启用):
|
|
644
|
+
// a) AST 稀疏: 类/协议 < 5 且无模块文档
|
|
645
|
+
// b) generic monolith: 仅 generic discoverer + 单 target + 多目录
|
|
646
|
+
// c) 核心文章过少: 当前主题 ≤ 4 篇 → 用文件夹分析补充内容丰富度
|
|
644
647
|
const astEntityCount = (astInfo.classes?.length || 0) + (astInfo.protocols?.length || 0);
|
|
645
648
|
const hasModuleDocs = topics.some((t) => t.type === 'module');
|
|
646
649
|
const astSparse = astEntityCount < 5 && !hasModuleDocs;
|
|
647
650
|
const shouldProfileForGenericMonolith =
|
|
648
651
|
genericOnlyDiscovery && monolithSingleTarget && sourceModuleKeys.length >= 2;
|
|
649
|
-
const
|
|
652
|
+
const tooFewCoreArticles = topics.length <= 4 && sourceModuleKeys.length >= 2;
|
|
653
|
+
const shouldEnableFolderProfiling =
|
|
654
|
+
astSparse || shouldProfileForGenericMonolith || tooFewCoreArticles;
|
|
650
655
|
|
|
651
656
|
if (shouldEnableFolderProfiling) {
|
|
652
657
|
const rawFolderProfiles = profileFolders(projectInfo, {
|
|
@@ -712,7 +717,11 @@ export class WikiGenerator {
|
|
|
712
717
|
folderDocCount++;
|
|
713
718
|
}
|
|
714
719
|
|
|
715
|
-
const folderProfileReason = astSparse
|
|
720
|
+
const folderProfileReason = astSparse
|
|
721
|
+
? 'AST sparse'
|
|
722
|
+
: tooFewCoreArticles
|
|
723
|
+
? `few core articles (${topics.length - topics.filter((t) => t.type === 'folder-overview' || t.type === 'folder-profile').length} core)`
|
|
724
|
+
: 'generic monolith';
|
|
716
725
|
logger.info(
|
|
717
726
|
`[WikiGenerator] Folder profiling (${folderProfileReason}): ${folderProfiles.length} folders analyzed, ` +
|
|
718
727
|
`${topics.filter((t) => t.type === 'folder-profile').length} folder docs planned`
|