autosnippet 3.2.3 → 3.2.6
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/README.md +2 -4
- package/bin/cli.js +164 -145
- package/config/constitution.yaml +3 -0
- package/dashboard/dist/assets/{index-DNOHYBhy.css → index-BaGY7kJI.css} +1 -1
- package/dashboard/dist/assets/{index-6itPuGFl.js → index-DfHY_3ln.js} +25 -25
- package/dashboard/dist/index.html +2 -2
- package/lib/cli/CliLogger.js +78 -0
- package/lib/cli/SetupService.js +9 -719
- package/lib/cli/UpgradeService.js +23 -398
- package/lib/cli/deploy/FileDeployer.js +562 -0
- package/lib/cli/deploy/FileManifest.js +272 -0
- package/lib/external/mcp/McpServer.js +22 -26
- package/lib/external/mcp/autoApproveInjector.js +1 -0
- package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +5 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +25 -3
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +6 -6
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +4 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +5 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +89 -44
- package/lib/external/mcp/handlers/consolidated.js +8 -9
- package/lib/external/mcp/handlers/dimension-complete-external.js +4 -4
- package/lib/external/mcp/handlers/guard.js +283 -5
- package/lib/external/mcp/handlers/task.js +183 -9
- package/lib/external/mcp/tools.js +32 -81
- package/lib/http/routes/task.js +55 -0
- package/lib/service/chat/AnalystAgent.js +12 -12
- package/lib/service/chat/ChatAgent.js +227 -545
- package/lib/service/chat/ChatAgentPrompts.js +9 -11
- package/lib/service/chat/ContextWindow.js +2 -296
- package/lib/service/chat/EpisodicConsolidator.js +15 -15
- package/lib/service/chat/ExplorationTracker.js +1262 -0
- package/lib/service/chat/HandoffProtocol.js +8 -9
- package/lib/service/chat/Memory.js +4 -0
- package/lib/service/chat/ProducerAgent.js +9 -6
- package/lib/service/chat/ProjectSemanticMemory.js +4 -0
- package/lib/service/chat/ReasoningTrace.js +182 -0
- package/lib/service/chat/WorkingMemory.js +4 -0
- package/lib/service/chat/memory/ActiveContext.js +910 -0
- package/lib/service/chat/memory/MemoryCoordinator.js +662 -0
- package/lib/service/chat/memory/PersistentMemory.js +450 -0
- package/lib/service/chat/memory/SessionStore.js +896 -0
- package/lib/service/chat/memory/index.js +13 -0
- package/lib/service/chat/tools/ast-graph.js +17 -16
- package/lib/service/cursor/AgentInstructionsGenerator.js +75 -40
- package/lib/service/cursor/FileProtection.js +4 -1
- package/lib/service/guard/GuardCheckEngine.js +10 -3
- package/lib/service/task/TaskGraphService.js +3 -3
- package/lib/shared/LanguageService.js +2 -1
- package/package.json +1 -1
- package/skills/autosnippet-intent/SKILL.md +1 -3
- package/skills/autosnippet-recipes/SKILL.md +1 -3
- package/templates/claude-code/commands/prime.md +19 -0
- package/templates/claude-code/hooks/autosnippet-session.sh +63 -0
- package/templates/claude-code/settings.json +21 -0
- package/templates/copilot-instructions.md +66 -177
- package/templates/cursor-hooks/commands/prime.md +12 -0
- package/templates/cursor-hooks/hooks/session-start.sh +10 -0
- package/templates/cursor-hooks/hooks.json +11 -0
- package/templates/cursor-rules/autosnippet-conventions.mdc +52 -3
- package/templates/cursor-rules/autosnippet-workflow.mdc +51 -27
- package/lib/external/mcp/handlers/decide.js +0 -109
- package/lib/external/mcp/handlers/ready.js +0 -42
- package/lib/service/chat/ReasoningLayer.js +0 -888
- package/templates/claude-hooks.yaml +0 -19
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileManifest — 所有可部署文件的单一真实来源
|
|
3
|
+
*
|
|
4
|
+
* Setup 和 Upgrade 共享同一份清单,由 FileDeployer 按策略执行。
|
|
5
|
+
*
|
|
6
|
+
* 字段说明:
|
|
7
|
+
* id — 唯一标识(用于日志和结果报告)
|
|
8
|
+
* src — 模板相对路径(相对于 templates/),null 表示需要 generate 函数
|
|
9
|
+
* dest — 目标相对路径(相对于 projectRoot)
|
|
10
|
+
* strategy — 部署策略(见 FileDeployer.STRATEGIES)
|
|
11
|
+
* on — 适用场景:'both' | 'setup' | 'upgrade'
|
|
12
|
+
* chmod — 是否需要 chmod +x(.sh 文件)
|
|
13
|
+
* generate — 自定义生成函数名(strategy 为 'generate' 时使用)
|
|
14
|
+
* category — 分组标签(用于 stepIDE 结果汇报)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 部署策略:
|
|
19
|
+
* 'overwrite' — AutoSnippet 完全拥有,始终覆盖
|
|
20
|
+
* 'overwrite-dir' — 递归覆盖整个目录(只覆盖 AutoSnippet 的文件)
|
|
21
|
+
* 'signature-safe' — 检查 AutoSnippet 签名再覆盖(保护用户自建文件)
|
|
22
|
+
* 'create-only' — 仅在文件不存在时创建(不更新)
|
|
23
|
+
* 'merge-json' — JSON 深度合并(只写入 autosnippet 键)
|
|
24
|
+
* 'merge-gitignore' — 增量追加缺失的 gitignore 规则
|
|
25
|
+
* 'backup-overwrite' — 备份旧文件后覆盖
|
|
26
|
+
* 'generate' — 自定义生成逻辑(由 generate 函数处理)
|
|
27
|
+
* 'inject-marker' — 在 <!-- autosnippet:begin/end --> 标记间注入/替换
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export const MANIFEST = [
|
|
31
|
+
// ═══ MCP Config ═══════════════════════════════════════
|
|
32
|
+
{
|
|
33
|
+
id: 'cursor-mcp',
|
|
34
|
+
dest: '.cursor/mcp.json',
|
|
35
|
+
strategy: 'merge-json',
|
|
36
|
+
on: 'both',
|
|
37
|
+
category: 'mcp',
|
|
38
|
+
jsonKey: 'mcpServers',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'vscode-mcp',
|
|
42
|
+
dest: '.vscode/mcp.json',
|
|
43
|
+
strategy: 'merge-json',
|
|
44
|
+
on: 'both',
|
|
45
|
+
category: 'mcp',
|
|
46
|
+
jsonKey: 'servers',
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
// ═══ Cursor Rules(AutoSnippet 完全拥有) ═══════════
|
|
50
|
+
{
|
|
51
|
+
id: 'cursor-conventions',
|
|
52
|
+
src: 'cursor-rules/autosnippet-conventions.mdc',
|
|
53
|
+
dest: '.cursor/rules/autosnippet-conventions.mdc',
|
|
54
|
+
strategy: 'overwrite',
|
|
55
|
+
on: 'both',
|
|
56
|
+
category: 'cursor-rules',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'cursor-skills-template',
|
|
60
|
+
src: 'cursor-rules/autosnippet-skills.mdc',
|
|
61
|
+
dest: '.cursor/rules/autosnippet-skills.mdc',
|
|
62
|
+
strategy: 'overwrite',
|
|
63
|
+
on: 'both',
|
|
64
|
+
category: 'cursor-rules',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'cursor-workflow',
|
|
68
|
+
src: 'cursor-rules/autosnippet-workflow.mdc',
|
|
69
|
+
dest: '.cursor/rules/autosnippet-workflow.mdc',
|
|
70
|
+
strategy: 'overwrite',
|
|
71
|
+
on: 'both',
|
|
72
|
+
category: 'cursor-rules',
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// ═══ Cursor Hooks ═════════════════════════════════════
|
|
76
|
+
{
|
|
77
|
+
id: 'cursor-hooks-json',
|
|
78
|
+
src: 'cursor-hooks/hooks.json',
|
|
79
|
+
dest: '.cursor/hooks.json',
|
|
80
|
+
strategy: 'overwrite',
|
|
81
|
+
on: 'both',
|
|
82
|
+
category: 'cursor-hooks',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'cursor-hooks-dir',
|
|
86
|
+
src: 'cursor-hooks/hooks/',
|
|
87
|
+
dest: '.cursor/hooks/',
|
|
88
|
+
strategy: 'overwrite-dir',
|
|
89
|
+
on: 'both',
|
|
90
|
+
category: 'cursor-hooks',
|
|
91
|
+
chmod: true,
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// ═══ Cursor Commands ══════════════════════════════════
|
|
95
|
+
{
|
|
96
|
+
id: 'cursor-commands',
|
|
97
|
+
src: 'cursor-hooks/commands/',
|
|
98
|
+
dest: '.cursor/commands/',
|
|
99
|
+
strategy: 'overwrite-dir',
|
|
100
|
+
on: 'both',
|
|
101
|
+
category: 'cursor-commands',
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// ═══ Claude Code ══════════════════════════════════════
|
|
105
|
+
{
|
|
106
|
+
id: 'claude-code',
|
|
107
|
+
src: 'claude-code/',
|
|
108
|
+
dest: '.claude/',
|
|
109
|
+
strategy: 'overwrite-dir',
|
|
110
|
+
on: 'both',
|
|
111
|
+
category: 'claude-hooks',
|
|
112
|
+
chmod: true,
|
|
113
|
+
cleanup: ['.claude/hooks.yaml'], // 清理旧格式文件
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// ═══ Agent Instructions(签名保护)════════════════════
|
|
117
|
+
{
|
|
118
|
+
id: 'copilot-instructions',
|
|
119
|
+
src: 'copilot-instructions.md',
|
|
120
|
+
dest: '.github/copilot-instructions.md',
|
|
121
|
+
strategy: 'signature-safe',
|
|
122
|
+
on: 'both',
|
|
123
|
+
category: 'copilot-instructions',
|
|
124
|
+
fallback: 'inject-marker', // 签名保护失败时,用标记注入
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'agents-md',
|
|
128
|
+
strategy: 'generate',
|
|
129
|
+
generate: 'generateAgentsMd',
|
|
130
|
+
dest: 'AGENTS.md',
|
|
131
|
+
on: 'setup',
|
|
132
|
+
category: 'agent-instructions',
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// ═══ CI/CD ════════════════════════════════════════════
|
|
136
|
+
{
|
|
137
|
+
id: 'guard-ci',
|
|
138
|
+
src: 'guard-ci.yml',
|
|
139
|
+
dest: '.github/workflows/autosnippet-guard.yml',
|
|
140
|
+
strategy: 'signature-safe',
|
|
141
|
+
on: 'both',
|
|
142
|
+
category: 'guard-ci',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: 'pre-commit',
|
|
146
|
+
src: 'pre-commit-guard.sh',
|
|
147
|
+
dest: null, // 动态决定:.husky/pre-commit 或 .git/hooks/pre-commit
|
|
148
|
+
strategy: 'create-only',
|
|
149
|
+
on: 'setup',
|
|
150
|
+
category: 'pre-commit-hook',
|
|
151
|
+
chmod: true,
|
|
152
|
+
resolveDest: 'resolvePreCommitDest',
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// ═══ Constitution ═════════════════════════════════════
|
|
156
|
+
// setup 由 stepCoreRepo 处理(create-only 语义)
|
|
157
|
+
// upgrade 时备份旧文件后覆盖
|
|
158
|
+
{
|
|
159
|
+
id: 'constitution',
|
|
160
|
+
src: 'constitution.yaml',
|
|
161
|
+
dest: 'AutoSnippet/constitution.yaml',
|
|
162
|
+
strategy: 'backup-overwrite',
|
|
163
|
+
on: 'upgrade',
|
|
164
|
+
category: 'constitution',
|
|
165
|
+
requireDir: 'AutoSnippet',
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
// ═══ Gitignore ════════════════════════════════════════
|
|
169
|
+
{
|
|
170
|
+
id: 'gitignore',
|
|
171
|
+
strategy: 'merge-gitignore',
|
|
172
|
+
dest: '.gitignore',
|
|
173
|
+
on: 'both',
|
|
174
|
+
category: 'gitignore',
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
// ═══ Skills ═══════════════════════════════════════════
|
|
178
|
+
{
|
|
179
|
+
id: 'skills-install',
|
|
180
|
+
strategy: 'generate',
|
|
181
|
+
generate: 'installSkills',
|
|
182
|
+
on: 'both',
|
|
183
|
+
category: 'skills',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'skills-ensure-dir',
|
|
187
|
+
strategy: 'generate',
|
|
188
|
+
generate: 'ensureSkillsDir',
|
|
189
|
+
on: 'both',
|
|
190
|
+
category: 'skills',
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// ═══ Dynamic Agent Instructions (requires DB) ════════
|
|
194
|
+
{
|
|
195
|
+
id: 'cursor-delivery',
|
|
196
|
+
strategy: 'generate',
|
|
197
|
+
generate: 'triggerCursorDelivery',
|
|
198
|
+
on: 'upgrade',
|
|
199
|
+
category: 'agent-instructions',
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// ═══ Auto-approve injection ═══════════════════════════
|
|
203
|
+
// setup 不注入 autoApprove — 让用户首次使用时亲眼授权每个工具
|
|
204
|
+
// bootstrap 成功后由 bootstrap-external.js 自动注入
|
|
205
|
+
{
|
|
206
|
+
id: 'auto-approve',
|
|
207
|
+
strategy: 'generate',
|
|
208
|
+
generate: 'injectAutoApprove',
|
|
209
|
+
on: 'upgrade',
|
|
210
|
+
category: 'mcp',
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// ═══ VSCode Extension ═════════════════════════════════
|
|
214
|
+
{
|
|
215
|
+
id: 'vscode-extension',
|
|
216
|
+
strategy: 'generate',
|
|
217
|
+
generate: 'installVSCodeExtension',
|
|
218
|
+
on: 'setup',
|
|
219
|
+
category: 'vscode-extension',
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* .gitignore 规则清单 — Setup 和 Upgrade 共用
|
|
225
|
+
* 每条规则:{ pattern, comment, negation? }
|
|
226
|
+
*/
|
|
227
|
+
export const GITIGNORE_RULES = [
|
|
228
|
+
// 核心运行时
|
|
229
|
+
{ pattern: '.autosnippet/*', comment: 'AutoSnippet 运行时缓存(不入库)' },
|
|
230
|
+
{ pattern: '!.autosnippet/config.json', negation: true },
|
|
231
|
+
|
|
232
|
+
// 环境变量
|
|
233
|
+
{ pattern: '.env', comment: 'AutoSnippet 环境变量(含 API Key,不入库)' },
|
|
234
|
+
|
|
235
|
+
// 日志
|
|
236
|
+
{ pattern: 'logs/', comment: 'AutoSnippet 运行日志' },
|
|
237
|
+
|
|
238
|
+
// AI 草稿
|
|
239
|
+
{ pattern: '.autosnippet-drafts/', comment: 'AutoSnippet AI 草稿(临时)' },
|
|
240
|
+
{ pattern: '_draft_*.md', comment: 'AutoSnippet AI 草稿文件(项目根目录临时文件)' },
|
|
241
|
+
|
|
242
|
+
// 系统 / 编辑器临时文件
|
|
243
|
+
{ pattern: '.DS_Store', comment: 'macOS 元数据' },
|
|
244
|
+
{ pattern: 'nohup.out' },
|
|
245
|
+
{ pattern: '*.sw[a-p]' },
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* .gitignore 迁移规则 — 升级时清理旧格式
|
|
250
|
+
*/
|
|
251
|
+
export const GITIGNORE_MIGRATIONS = [
|
|
252
|
+
// v2.4.0: ".autosnippet/" → ".autosnippet/*"
|
|
253
|
+
{ find: /^\.autosnippet\/$/m, replace: '.autosnippet/*' },
|
|
254
|
+
// Skills 已迁移到 AutoSnippet/skills/,清理旧 negation
|
|
255
|
+
{ find: /^!?\.autosnippet\/skills\/.*\n?/gm, replace: '' },
|
|
256
|
+
];
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* MCP Server 配置生成器
|
|
260
|
+
* @param {string} projectRoot
|
|
261
|
+
* @param {'cursor'|'vscode'} ide
|
|
262
|
+
*/
|
|
263
|
+
export function buildMcpServerEntry(projectRoot, ide) {
|
|
264
|
+
const base = {
|
|
265
|
+
command: 'asd-mcp',
|
|
266
|
+
env: { ASD_PROJECT_DIR: projectRoot },
|
|
267
|
+
};
|
|
268
|
+
if (ide === 'vscode') {
|
|
269
|
+
return { type: 'stdio', ...base };
|
|
270
|
+
}
|
|
271
|
+
return base;
|
|
272
|
+
}
|
|
@@ -38,9 +38,7 @@ import * as systemHandlers from './handlers/system.js';
|
|
|
38
38
|
// ─── External Agent Bootstrap 新 handler ──────────────────────
|
|
39
39
|
|
|
40
40
|
import { bootstrapExternal } from './handlers/bootstrap-external.js';
|
|
41
|
-
import { decideHandler } from './handlers/decide.js';
|
|
42
41
|
import { dimensionComplete } from './handlers/dimension-complete-external.js';
|
|
43
|
-
import { readyHandler } from './handlers/ready.js';
|
|
44
42
|
import { taskHandler } from './handlers/task.js';
|
|
45
43
|
import { wikiFinalize, wikiPlan } from './handlers/wiki-external.js';
|
|
46
44
|
|
|
@@ -185,6 +183,12 @@ export class McpServer {
|
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
const wrapped = wrapHandler(name, handler);
|
|
186
|
+
|
|
187
|
+
// Track task operation for _injectDecisions
|
|
188
|
+
if (name === 'autosnippet_task') {
|
|
189
|
+
this._lastTaskOperation = args.operation || '';
|
|
190
|
+
}
|
|
191
|
+
|
|
188
192
|
const result = await wrapped(ctx, args);
|
|
189
193
|
|
|
190
194
|
// ── P0+P3: Decision 注入 + Session 追踪 ──
|
|
@@ -211,10 +215,10 @@ export class McpServer {
|
|
|
211
215
|
* 在工具返回结果中注入 decisions 摘要 + 更新 session 统计
|
|
212
216
|
*
|
|
213
217
|
* 策略:
|
|
214
|
-
* -
|
|
215
|
-
* -
|
|
218
|
+
* - prime: 刷新缓存,不额外注入(response 本身含 decisions)
|
|
219
|
+
* - decision 写操作 (record/revise/unpin): invalidate 缓存(下次查询拉最新)
|
|
216
220
|
* - 其他工具: 注入 _activeDecisions 摘要
|
|
217
|
-
* - 首次未调
|
|
221
|
+
* - 首次未调 prime 的工具: 注入更强提醒
|
|
218
222
|
*
|
|
219
223
|
* @param {string} toolName
|
|
220
224
|
* @param {object} result — handler 返回的 envelope 对象
|
|
@@ -225,26 +229,20 @@ export class McpServer {
|
|
|
225
229
|
this._session.toolsUsed.add(toolName);
|
|
226
230
|
this._session.lastActivityAt = Date.now();
|
|
227
231
|
|
|
228
|
-
// 1)
|
|
229
|
-
if (toolName === 'autosnippet_ready') {
|
|
230
|
-
this._session.readyCalled = true;
|
|
231
|
-
this._refreshCacheFromReady(result);
|
|
232
|
-
return result;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// 2) decide 写操作:invalidate 缓存(record/revise/unpin 改变了 decisions)
|
|
236
|
-
if (toolName === 'autosnippet_decide') {
|
|
237
|
-
this._decisionCache.fetchedAt = 0;
|
|
238
|
-
this._decisionCache._pending = null;
|
|
239
|
-
return result;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// 3) autosnippet_task 也不注入(task 操作返回值已足够,避免 token 膨胀)
|
|
232
|
+
// 1) autosnippet_task: prime 刷新缓存,decision 写操作 invalidate 缓存
|
|
243
233
|
if (toolName === 'autosnippet_task') {
|
|
234
|
+
const op = this._lastTaskOperation;
|
|
235
|
+
if (op === 'prime') {
|
|
236
|
+
this._session.readyCalled = true;
|
|
237
|
+
this._refreshCacheFromReady(result);
|
|
238
|
+
} else if (['record_decision', 'revise_decision', 'unpin_decision'].includes(op)) {
|
|
239
|
+
this._decisionCache.fetchedAt = 0;
|
|
240
|
+
this._decisionCache._pending = null;
|
|
241
|
+
}
|
|
244
242
|
return result;
|
|
245
243
|
}
|
|
246
244
|
|
|
247
|
-
// 4) 对非
|
|
245
|
+
// 4) 对非 task 操作工具:注入 decisions 摘要
|
|
248
246
|
const decisions = await this._getDecisionsSummary();
|
|
249
247
|
if (decisions.length > 0 && typeof result === 'object' && result !== null) {
|
|
250
248
|
result._activeDecisions = decisions;
|
|
@@ -252,11 +250,11 @@ export class McpServer {
|
|
|
252
250
|
// P3: 如果 ready 从未被调用,注入更强提醒
|
|
253
251
|
if (!this._session.readyCalled) {
|
|
254
252
|
result._decisionReminder =
|
|
255
|
-
'⚠️ You have NOT called
|
|
256
|
-
'These decisions may affect your work. Call
|
|
253
|
+
'⚠️ You have NOT called autosnippet_task({ operation: "prime" }) yet this session. ' +
|
|
254
|
+
'These decisions may affect your work. Call autosnippet_task({ operation: "prime" }) for full context.';
|
|
257
255
|
} else {
|
|
258
256
|
result._decisionReminder =
|
|
259
|
-
'Respect these team decisions. Call
|
|
257
|
+
'Respect these team decisions. Call autosnippet_task({ operation: "list_decisions" }) for full details.';
|
|
260
258
|
}
|
|
261
259
|
}
|
|
262
260
|
|
|
@@ -362,8 +360,6 @@ export class McpServer {
|
|
|
362
360
|
knowledgeHandlers.submitKnowledgeBatch(ctx, args),
|
|
363
361
|
autosnippet_save_document: (ctx, args) => knowledgeHandlers.saveDocument(ctx, args),
|
|
364
362
|
autosnippet_skill: (ctx, args) => consolidated.consolidatedSkill(ctx, args),
|
|
365
|
-
autosnippet_ready: (ctx, args) => readyHandler(ctx, args),
|
|
366
|
-
autosnippet_decide: (ctx, args) => decideHandler(ctx, args),
|
|
367
363
|
autosnippet_task: (ctx, args) => taskHandler(ctx, args),
|
|
368
364
|
// ── External Agent Bootstrap (v3.1) ──
|
|
369
365
|
autosnippet_bootstrap: (ctx, _args) => bootstrapExternal(ctx),
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import crypto from 'node:crypto';
|
|
19
|
-
import {
|
|
19
|
+
import { SessionStore } from '../../../../service/chat/memory/SessionStore.js';
|
|
20
20
|
import { ExternalSubmissionTracker } from './ExternalSubmissionTracker.js';
|
|
21
21
|
|
|
22
22
|
// ── 常量 ────────────────────────────────────────────────────
|
|
@@ -37,7 +37,7 @@ export class BootstrapSession {
|
|
|
37
37
|
this.projectRoot = projectRoot;
|
|
38
38
|
this.dimensions = dimensions;
|
|
39
39
|
this.completedDimensions = new Map(); // dimId → { report, completedAt, recipeIds }
|
|
40
|
-
this.
|
|
40
|
+
this.sessionStore = new SessionStore(projectContext);
|
|
41
41
|
|
|
42
42
|
/** 外部 Agent 提交追踪 (v2: 对标内部 Agent 的 EvidenceCollector) */
|
|
43
43
|
this.submissionTracker = new ExternalSubmissionTracker();
|
|
@@ -98,9 +98,9 @@ export class BootstrapSession {
|
|
|
98
98
|
completedAt: Date.now(),
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
// 写入
|
|
102
|
-
// keyFindings 是字符串数组,需转换为
|
|
103
|
-
this.
|
|
101
|
+
// 写入 SessionStore
|
|
102
|
+
// keyFindings 是字符串数组,需转换为 SessionStore 期望的 { finding, importance } 格式
|
|
103
|
+
this.sessionStore.storeDimensionReport(dimId, {
|
|
104
104
|
analysisText: report.analysisText,
|
|
105
105
|
findings: (report.keyFindings || []).map((f) => ({ finding: f, importance: 7 })),
|
|
106
106
|
referencedFiles: report.referencedFiles || [],
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EpisodicMemory — Bootstrap 会话级情景记忆
|
|
3
3
|
*
|
|
4
|
+
* @deprecated Phase 4: 已合并入 SessionStore (lib/service/chat/memory/SessionStore.js)
|
|
5
|
+
* - 全部维度报告/证据/反思逻辑已迁入 SessionStore
|
|
6
|
+
* - 本文件保留做向后兼容,新代码请使用 SessionStore
|
|
7
|
+
*
|
|
4
8
|
* 内部 Agent 和外部 Agent 共享此模块。
|
|
5
9
|
*
|
|
6
10
|
* 提供跨维度上下文:
|
|
@@ -128,11 +132,19 @@ export class EpisodicMemory {
|
|
|
128
132
|
* @param {object} [report.digest] — DimensionDigest (兼容)
|
|
129
133
|
*/
|
|
130
134
|
storeDimensionReport(dimId, report) {
|
|
135
|
+
// findings 统一形状: { finding: string, evidence: string, importance: number }
|
|
136
|
+
// 源头 buildAnalysisArtifact() 和 ActiveContext.distill() 已保证一致
|
|
137
|
+
const findings = (report.findings || []).map((f) => ({
|
|
138
|
+
finding: f.finding || '',
|
|
139
|
+
evidence: f.evidence || '',
|
|
140
|
+
importance: f.importance || 5,
|
|
141
|
+
}));
|
|
142
|
+
|
|
131
143
|
this.#dimensionReports.set(dimId, {
|
|
132
144
|
dimId,
|
|
133
145
|
completedAt: Date.now(),
|
|
134
146
|
analysisText: report.analysisText || '',
|
|
135
|
-
findings
|
|
147
|
+
findings,
|
|
136
148
|
referencedFiles: report.referencedFiles || [],
|
|
137
149
|
candidatesSummary: report.candidatesSummary || [],
|
|
138
150
|
workingMemoryDistilled: report.workingMemoryDistilled || null,
|
|
@@ -140,7 +152,7 @@ export class EpisodicMemory {
|
|
|
140
152
|
});
|
|
141
153
|
|
|
142
154
|
// 自动提取文件级 Evidence
|
|
143
|
-
for (const f of
|
|
155
|
+
for (const f of findings) {
|
|
144
156
|
if (f.evidence) {
|
|
145
157
|
const filePath = f.evidence.split(':')[0]; // "file.m:123" → "file.m"
|
|
146
158
|
this.addEvidence(filePath, {
|
|
@@ -401,8 +413,18 @@ export class EpisodicMemory {
|
|
|
401
413
|
parts.push(`${report.analysisText.substring(0, 300)}…`);
|
|
402
414
|
}
|
|
403
415
|
|
|
416
|
+
// P0 Fix (B1): 优先使用 report.findings,为空时从 workingMemoryDistilled.keyFindings 补充
|
|
417
|
+
let findings = report.findings;
|
|
418
|
+
if ((!findings || findings.length === 0) && report.workingMemoryDistilled?.keyFindings) {
|
|
419
|
+
findings = report.workingMemoryDistilled.keyFindings.map((f) => ({
|
|
420
|
+
finding: f.finding || '',
|
|
421
|
+
evidence: f.evidence || '',
|
|
422
|
+
importance: f.importance || 5,
|
|
423
|
+
}));
|
|
424
|
+
}
|
|
425
|
+
|
|
404
426
|
// 选择与当前维度相关的 findings
|
|
405
|
-
const relevantFindings = this.#selectRelevantFindings(
|
|
427
|
+
const relevantFindings = this.#selectRelevantFindings(findings, focusKeywords, 5);
|
|
406
428
|
if (relevantFindings.length > 0) {
|
|
407
429
|
parts.push('**具体发现**:');
|
|
408
430
|
for (const f of relevantFindings) {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { BootstrapSnapshot } from './BootstrapSnapshot.js';
|
|
19
|
-
import {
|
|
19
|
+
import { SessionStore } from '../../../../../service/chat/memory/SessionStore.js';
|
|
20
20
|
|
|
21
21
|
// ──────────────────────────────────────────────────────────────
|
|
22
22
|
// IncrementalBootstrap 类
|
|
@@ -106,16 +106,16 @@ export class IncrementalBootstrap {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// 4. 增量可行 → 尝试恢复
|
|
109
|
+
// 4. 增量可行 → 尝试恢复 SessionStore
|
|
110
110
|
let restoredEpisodic = null;
|
|
111
111
|
if (previousSnapshot.episodicData) {
|
|
112
112
|
try {
|
|
113
|
-
restoredEpisodic =
|
|
113
|
+
restoredEpisodic = SessionStore.fromJSON(previousSnapshot.episodicData);
|
|
114
114
|
this.#log(
|
|
115
|
-
`Restored
|
|
115
|
+
`Restored SessionStore: ${restoredEpisodic.getCompletedDimensions().length} dimensions`
|
|
116
116
|
);
|
|
117
117
|
} catch (err) {
|
|
118
|
-
this.#log(`Failed to restore
|
|
118
|
+
this.#log(`Failed to restore SessionStore: ${err.message}`, 'warn');
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -156,7 +156,7 @@ export class IncrementalBootstrap {
|
|
|
156
156
|
* @param {string} params.sessionId
|
|
157
157
|
* @param {Array} params.allFiles
|
|
158
158
|
* @param {object} params.dimensionStats
|
|
159
|
-
* @param {
|
|
159
|
+
* @param {SessionStore} [params.episodicMemory]
|
|
160
160
|
* @param {object} [params.meta] — { durationMs, candidateCount, primaryLang }
|
|
161
161
|
* @param {IncrementalPlan} [params.plan] — evaluate() 返回的计划 (增量时)
|
|
162
162
|
* @returns {string} 快照 ID
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ToolResultCache — 跨维度工具结果缓存
|
|
3
3
|
*
|
|
4
|
+
* @deprecated Phase 4: 已合并入 SessionStore (lib/service/chat/memory/SessionStore.js)
|
|
5
|
+
* - LRU 缓存逻辑 (仅只读工具) 已迁入 SessionStore
|
|
6
|
+
* - 本文件保留做向后兼容,新代码请使用 SessionStore
|
|
7
|
+
*
|
|
4
8
|
* 缓存 search_project_code 和 read_project_file 的调用结果,
|
|
5
9
|
* 避免后续维度重复执行已知搜索/读取操作。
|
|
6
10
|
*
|
|
@@ -86,16 +86,16 @@ export function getFullDimensionConfig(dimId) {
|
|
|
86
86
|
*
|
|
87
87
|
* @param {number} tierIndex — Tier 索引 (0-based)
|
|
88
88
|
* @param {Map<string, object>} tierResults — 本 Tier 的维度结果
|
|
89
|
-
* @param {import('
|
|
89
|
+
* @param {import('../../../../../service/chat/memory/SessionStore.js').SessionStore} sessionStore
|
|
90
90
|
* @returns {object} TierReflection
|
|
91
91
|
*/
|
|
92
|
-
export function buildTierReflection(tierIndex, tierResults,
|
|
92
|
+
export function buildTierReflection(tierIndex, tierResults, sessionStore) {
|
|
93
93
|
const completedDimensions = [...tierResults.keys()];
|
|
94
94
|
|
|
95
95
|
// 收集本 Tier 所有维度的 findings
|
|
96
96
|
const allFindings = [];
|
|
97
97
|
for (const dimId of completedDimensions) {
|
|
98
|
-
const report =
|
|
98
|
+
const report = sessionStore.getDimensionReport(dimId);
|
|
99
99
|
if (report?.findings) {
|
|
100
100
|
for (const f of report.findings) {
|
|
101
101
|
allFindings.push({ dimId, ...f });
|
|
@@ -148,7 +148,7 @@ export function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
|
148
148
|
|
|
149
149
|
// 找出 gaps (各维度报告的未覆盖方面)
|
|
150
150
|
for (const dimId of completedDimensions) {
|
|
151
|
-
const report =
|
|
151
|
+
const report = sessionStore.getDimensionReport(dimId);
|
|
152
152
|
const gaps = report?.digest?.gaps || [];
|
|
153
153
|
for (const gap of gaps) {
|
|
154
154
|
if (gap && typeof gap === 'string' && gap.length > 5) {
|
|
@@ -159,7 +159,7 @@ export function buildTierReflection(tierIndex, tierResults, episodicMemory) {
|
|
|
159
159
|
|
|
160
160
|
// remainingTasks
|
|
161
161
|
for (const dimId of completedDimensions) {
|
|
162
|
-
const report =
|
|
162
|
+
const report = sessionStore.getDimensionReport(dimId);
|
|
163
163
|
const remaining = report?.digest?.remainingTasks || [];
|
|
164
164
|
for (const task of remaining) {
|
|
165
165
|
if (task?.signal) {
|