autosnippet 3.2.4 → 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 +2 -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 -718
- 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 +76 -47
- 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 +64 -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
|
@@ -1,36 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* UpgradeService — IDE 集成升级服务
|
|
3
3
|
*
|
|
4
|
-
* 当 AutoSnippet 发布新版本后,老用户执行 `asd upgrade`
|
|
5
|
-
*
|
|
6
|
-
* ② Cursor Skills(.cursor/skills/)
|
|
7
|
-
* ③ Cursor Rules(.cursor/rules/autosnippet-conventions.mdc + autosnippet-skills.mdc)
|
|
8
|
-
* ④ Agent Instructions(AGENTS.md + CLAUDE.md + .github/copilot-instructions.md — 通过 Channel F 动态生成)
|
|
9
|
-
* ⑤ Constitution(AutoSnippet/constitution.yaml)
|
|
10
|
-
* ⑥ .gitignore(升级规则 + 清理旧版本残留)
|
|
11
|
-
* ⑦ Skills 路径迁移(.autosnippet/skills/ → AutoSnippet/skills/)
|
|
4
|
+
* 当 AutoSnippet 发布新版本后,老用户执行 `asd upgrade` 即可更新所有 IDE 集成文件。
|
|
5
|
+
* 底层委托 FileDeployer 按 MANIFEST 定义的策略执行,确保与 SetupService 使用同一套部署逻辑。
|
|
12
6
|
*
|
|
13
|
-
*
|
|
7
|
+
* 额外职责:
|
|
8
|
+
* - Skills 路径迁移(.autosnippet/skills/ → AutoSnippet/skills/)
|
|
14
9
|
*/
|
|
15
10
|
|
|
16
11
|
import { execSync } from 'node:child_process';
|
|
17
12
|
import {
|
|
18
|
-
copyFileSync,
|
|
19
13
|
existsSync,
|
|
20
14
|
mkdirSync,
|
|
21
15
|
readdirSync,
|
|
22
|
-
readFileSync,
|
|
23
|
-
writeFileSync,
|
|
24
16
|
} from 'node:fs';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { safeCopyFile } from '../service/cursor/FileProtection.js';
|
|
28
|
-
import { injectAutoApprove } from '../external/mcp/autoApproveInjector.js';
|
|
29
|
-
|
|
30
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
-
const __dirname = dirname(__filename);
|
|
32
|
-
|
|
33
|
-
const REPO_ROOT = resolve(__dirname, '..', '..');
|
|
17
|
+
import { join, resolve } from 'node:path';
|
|
18
|
+
import { FileDeployer } from './deploy/FileDeployer.js';
|
|
34
19
|
|
|
35
20
|
export class UpgradeService {
|
|
36
21
|
constructor(options) {
|
|
@@ -39,378 +24,32 @@ export class UpgradeService {
|
|
|
39
24
|
}
|
|
40
25
|
|
|
41
26
|
async run({ skillsOnly = false, mcpOnly = false } = {}) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
if (!mcpOnly) {
|
|
48
|
-
results.push(this._upgradeSkills());
|
|
49
|
-
}
|
|
50
|
-
if (!skillsOnly && !mcpOnly) {
|
|
51
|
-
results.push(this._upgradeCursorRules());
|
|
52
|
-
// NOTE: .qoder/ .trae/ 不再自动镜像,用户可通过 `asd mirror` 按需同步
|
|
53
|
-
results.push(this._upgradeSkillsTemplate());
|
|
54
|
-
results.push(this._upgradeCopilotInstructions());
|
|
55
|
-
results.push(this._upgradeConstitution());
|
|
56
|
-
results.push(this._upgradeGitignore());
|
|
57
|
-
results.push(this._migrateSkillsPath());
|
|
58
|
-
results.push(this._ensureSkillsDir());
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return results;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* ═══ MCP 配置 ══════════════════════════════════════ */
|
|
65
|
-
|
|
66
|
-
_upgradeMCP() {
|
|
67
|
-
// Cursor
|
|
68
|
-
this._updateCursorMCP();
|
|
69
|
-
// VSCode
|
|
70
|
-
this._updateVSCodeMCP();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
_updateCursorMCP() {
|
|
74
|
-
const configPath = join(this.projectRoot, '.cursor', 'mcp.json');
|
|
75
|
-
if (!existsSync(configPath)) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let config = {};
|
|
80
|
-
try {
|
|
81
|
-
config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
82
|
-
} catch {
|
|
83
|
-
/* */
|
|
84
|
-
}
|
|
85
|
-
if (!config.mcpServers) {
|
|
86
|
-
config.mcpServers = {};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
config.mcpServers.autosnippet = {
|
|
90
|
-
command: 'asd-mcp',
|
|
91
|
-
env: {
|
|
92
|
-
ASD_PROJECT_DIR: this.projectRoot,
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
97
|
-
|
|
98
|
-
// 升级时注入 autoApprove(老用户已经使用过,无需首次授权体验)
|
|
99
|
-
injectAutoApprove(this.projectRoot);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_updateVSCodeMCP() {
|
|
103
|
-
const vscodeDir = join(this.projectRoot, '.vscode');
|
|
104
|
-
const mcpConfigPath = join(vscodeDir, 'mcp.json');
|
|
105
|
-
|
|
106
|
-
let config = {};
|
|
107
|
-
if (existsSync(mcpConfigPath)) {
|
|
108
|
-
try {
|
|
109
|
-
config = JSON.parse(readFileSync(mcpConfigPath, 'utf8'));
|
|
110
|
-
} catch {
|
|
111
|
-
/* */
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (!config.servers) {
|
|
116
|
-
config.servers = {};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
config.servers.autosnippet = {
|
|
120
|
-
type: 'stdio',
|
|
121
|
-
command: 'asd-mcp',
|
|
122
|
-
env: {
|
|
123
|
-
ASD_PROJECT_DIR: this.projectRoot,
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
mkdirSync(vscodeDir, { recursive: true });
|
|
128
|
-
writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/* ═══ Skills ════════════════════════════════════════ */
|
|
132
|
-
|
|
133
|
-
_upgradeSkills() {
|
|
134
|
-
const installScript = join(REPO_ROOT, 'scripts', 'install-cursor-skill.js');
|
|
135
|
-
if (!existsSync(installScript)) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
execSync(`node "${installScript}"`, {
|
|
141
|
-
cwd: this.projectRoot,
|
|
142
|
-
stdio: 'inherit',
|
|
143
|
-
env: { ...process.env, NODE_PATH: join(REPO_ROOT, 'node_modules') },
|
|
144
|
-
});
|
|
145
|
-
} catch (e) {
|
|
146
|
-
console.error(` ❌ Skills 安装失败: ${e.message}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/* ═══ Cursor Rules ══════════════════════════════════ */
|
|
151
|
-
|
|
152
|
-
_upgradeCursorRules() {
|
|
153
|
-
const src = join(REPO_ROOT, 'templates', 'cursor-rules', 'autosnippet-conventions.mdc');
|
|
154
|
-
if (!existsSync(src)) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const destDir = join(this.projectRoot, '.cursor', 'rules');
|
|
159
|
-
const dest = join(destDir, 'autosnippet-conventions.mdc');
|
|
160
|
-
mkdirSync(destDir, { recursive: true });
|
|
161
|
-
copyFileSync(src, dest);
|
|
162
|
-
|
|
163
|
-
// 动态生成 4 通道交付物料(如 ServiceContainer 已初始化)
|
|
164
|
-
this._triggerCursorDelivery();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* 触发 Cursor Delivery Pipeline 动态生成
|
|
169
|
-
* 包含 Channel A-D + Channel F (AGENTS.md / CLAUDE.md / copilot-instructions)
|
|
170
|
-
* 非阻塞 — 失败不影响 upgrade 流程
|
|
171
|
-
*/
|
|
172
|
-
_triggerCursorDelivery() {
|
|
173
|
-
import('../injection/ServiceContainer.js')
|
|
174
|
-
.then(({ getServiceContainer }) => {
|
|
175
|
-
const container = getServiceContainer();
|
|
176
|
-
if (container.services.cursorDeliveryPipeline) {
|
|
177
|
-
const pipeline = container.get('cursorDeliveryPipeline');
|
|
178
|
-
pipeline
|
|
179
|
-
.deliver()
|
|
180
|
-
.then((_result) => {})
|
|
181
|
-
.catch((_err) => {
|
|
182
|
-
/* fire-and-forget: delivery failure is non-critical during upgrade */
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
.catch(() => {
|
|
187
|
-
// ServiceContainer 未初始化 — 正常(upgrade 可能在无 DB 环境执行)
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/* ═══ Mirror IDE Rules (Qoder / Trae) ═══════════════ */
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* 镜像 .cursor/rules/ 中的 autosnippet-* 文件到目标 IDE 目录
|
|
195
|
-
* 只触碰 autosnippet- 前缀的文件,保留用户自定义规则
|
|
196
|
-
* @param {string} targetDirName - '.qoder' 或 '.trae'
|
|
197
|
-
*/
|
|
198
|
-
_upgradeMirrorIDE(targetDirName) {
|
|
199
|
-
const _label = targetDirName.replace('.', '').charAt(0).toUpperCase() + targetDirName.slice(2);
|
|
200
|
-
|
|
201
|
-
// 镜像 .cursor/rules/ 中的 autosnippet-* 文件
|
|
202
|
-
const cursorRulesDir = join(this.projectRoot, '.cursor', 'rules');
|
|
203
|
-
if (!existsSync(cursorRulesDir)) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const targetRulesDir = join(this.projectRoot, targetDirName, 'rules');
|
|
208
|
-
mkdirSync(targetRulesDir, { recursive: true });
|
|
209
|
-
|
|
210
|
-
// 只复制 autosnippet- 前缀的文件,不触碰用户自己创建的规则
|
|
211
|
-
const files = readdirSync(cursorRulesDir).filter(
|
|
212
|
-
(f) => (f.endsWith('.mdc') || f.endsWith('.md')) && f.startsWith('autosnippet-')
|
|
213
|
-
);
|
|
214
|
-
for (const file of files) {
|
|
215
|
-
const destName = file.endsWith('.mdc') ? file.replace(/\.mdc$/, '.md') : file;
|
|
216
|
-
copyFileSync(join(cursorRulesDir, file), join(targetRulesDir, destName));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// 镜像 .cursor/skills/ 中的 autosnippet-* 技能目录
|
|
220
|
-
const cursorSkillsDir = join(this.projectRoot, '.cursor', 'skills');
|
|
221
|
-
if (existsSync(cursorSkillsDir)) {
|
|
222
|
-
const targetSkillsDir = join(this.projectRoot, targetDirName, 'skills');
|
|
223
|
-
mkdirSync(targetSkillsDir, { recursive: true });
|
|
224
|
-
const skillDirs = readdirSync(cursorSkillsDir, { withFileTypes: true }).filter(
|
|
225
|
-
(d) => d.isDirectory() && d.name.startsWith('autosnippet-')
|
|
226
|
-
);
|
|
227
|
-
for (const dir of skillDirs) {
|
|
228
|
-
this._copyDirRecursiveSkill(
|
|
229
|
-
join(cursorSkillsDir, dir.name),
|
|
230
|
-
join(targetSkillsDir, dir.name)
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** @private 递归复制目录(合并模式,不删除目标已有文件) */
|
|
237
|
-
_copyDirRecursiveSkill(src, dest) {
|
|
238
|
-
mkdirSync(dest, { recursive: true });
|
|
239
|
-
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
240
|
-
const srcPath = join(src, entry.name);
|
|
241
|
-
const destPath = join(dest, entry.name);
|
|
242
|
-
if (entry.isDirectory()) {
|
|
243
|
-
this._copyDirRecursiveSkill(srcPath, destPath);
|
|
244
|
-
} else {
|
|
245
|
-
copyFileSync(srcPath, destPath);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/* ═══ Copilot Instructions (fallback static copy) ══════════════════ */
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* 静态模板回退 — 当 _triggerCursorDelivery() 无法运行时
|
|
254
|
-
* (无 DB 环境),至少保证有一份基础模板。
|
|
255
|
-
* Channel F 动态生成会覆盖此文件。
|
|
256
|
-
*/
|
|
257
|
-
_upgradeCopilotInstructions() {
|
|
258
|
-
const src = join(REPO_ROOT, 'templates', 'copilot-instructions.md');
|
|
259
|
-
if (!existsSync(src)) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const destDir = join(this.projectRoot, '.github');
|
|
264
|
-
const dest = join(destDir, 'copilot-instructions.md');
|
|
265
|
-
mkdirSync(destDir, { recursive: true });
|
|
266
|
-
const { written } = safeCopyFile(src, dest);
|
|
267
|
-
if (!written) {
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/* ═══ Constitution ══════════════════════════════════ */
|
|
27
|
+
const deployer = new FileDeployer({
|
|
28
|
+
projectRoot: this.projectRoot,
|
|
29
|
+
force: false,
|
|
30
|
+
});
|
|
272
31
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
32
|
+
let filter;
|
|
33
|
+
if (skillsOnly) {
|
|
34
|
+
filter = ['skills'];
|
|
35
|
+
} else if (mcpOnly) {
|
|
36
|
+
filter = ['mcp'];
|
|
277
37
|
}
|
|
278
38
|
|
|
279
|
-
|
|
280
|
-
const dest = join(this.projectRoot, 'AutoSnippet', 'constitution.yaml');
|
|
281
|
-
if (!existsSync(join(this.projectRoot, 'AutoSnippet'))) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
39
|
+
const { deployed, skipped, errors } = deployer.deployAll('upgrade', { filter });
|
|
284
40
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const newContent = readFileSync(src, 'utf8');
|
|
289
|
-
if (oldContent === newContent) {
|
|
290
|
-
return;
|
|
41
|
+
if (errors.length > 0) {
|
|
42
|
+
for (const { id, error } of errors) {
|
|
43
|
+
console.error(` ⚠ ${id}: ${error}`);
|
|
291
44
|
}
|
|
292
|
-
const backupPath = `${dest}.bak`;
|
|
293
|
-
copyFileSync(dest, backupPath);
|
|
294
45
|
}
|
|
295
46
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const gitDir = join(this.projectRoot, 'AutoSnippet', '.git');
|
|
300
|
-
if (existsSync(gitDir)) {
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
/* ═══ Skills Template ════════════════════════════════ */
|
|
304
|
-
|
|
305
|
-
_upgradeSkillsTemplate() {
|
|
306
|
-
const src = join(REPO_ROOT, 'templates', 'cursor-rules', 'autosnippet-skills.mdc');
|
|
307
|
-
if (!existsSync(src)) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const destDir = join(this.projectRoot, '.cursor', 'rules');
|
|
312
|
-
const dest = join(destDir, 'autosnippet-skills.mdc');
|
|
313
|
-
mkdirSync(destDir, { recursive: true });
|
|
314
|
-
copyFileSync(src, dest);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/* ═══ .gitignore ════════════════════════════════════ */
|
|
318
|
-
|
|
319
|
-
_upgradeGitignore() {
|
|
320
|
-
const giPath = join(this.projectRoot, '.gitignore');
|
|
321
|
-
if (!existsSync(giPath)) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
let content = readFileSync(giPath, 'utf8');
|
|
326
|
-
let changed = false;
|
|
327
|
-
|
|
328
|
-
// v2.4.0 迁移:旧格式 ".autosnippet/" → 新格式 ".autosnippet/*"
|
|
329
|
-
if (content.includes('.autosnippet/') && !content.includes('.autosnippet/*')) {
|
|
330
|
-
content = content.replace(/^\.autosnippet\/$/m, '.autosnippet/*');
|
|
331
|
-
changed = true;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// 确保有 .autosnippet/*
|
|
335
|
-
if (!content.includes('.autosnippet/') && !content.includes('.autosnippet/*')) {
|
|
336
|
-
content += `\n# AutoSnippet 运行时缓存(不入库)\n.autosnippet/*\n`;
|
|
337
|
-
changed = true;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// 确保 config.json 跟踪
|
|
341
|
-
if (!content.includes('!.autosnippet/config.json')) {
|
|
342
|
-
content += `!.autosnippet/config.json\n`;
|
|
343
|
-
changed = true;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// 清理旧版本的 .autosnippet/skills/ negation(已迁移到 AutoSnippet/skills/)
|
|
347
|
-
if (content.includes('!.autosnippet/skills/')) {
|
|
348
|
-
content = content.replace(/^!?\.autosnippet\/skills\/.*\n?/gm, '');
|
|
349
|
-
changed = true;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// ── v2.8.1: 新增缺失的 gitignore 规则 ──
|
|
353
|
-
|
|
354
|
-
// _draft_*.md — AI Agent 在项目根目录创建的草稿文件
|
|
355
|
-
if (!content.includes('_draft_*.md')) {
|
|
356
|
-
content += `\n# AutoSnippet AI 草稿文件(项目根目录临时文件)\n_draft_*.md\n`;
|
|
357
|
-
changed = true;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// .DS_Store — macOS 元数据
|
|
361
|
-
if (!content.includes('.DS_Store')) {
|
|
362
|
-
content += `\n# macOS 元数据\n.DS_Store\n`;
|
|
363
|
-
changed = true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// nohup.out — 后台进程输出
|
|
367
|
-
if (!content.includes('nohup.out')) {
|
|
368
|
-
content += `nohup.out\n`;
|
|
369
|
-
changed = true;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// *.sw[a-p] — vim swap 文件
|
|
373
|
-
if (!content.match(/\*\.sw\[a-p\]/)) {
|
|
374
|
-
content += `*.sw[a-p]\n`;
|
|
375
|
-
changed = true;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// .autosnippet-drafts/ — AI 草稿目录
|
|
379
|
-
if (!content.includes('.autosnippet-drafts')) {
|
|
380
|
-
content += `\n# AutoSnippet AI 草稿(临时)\n.autosnippet-drafts/\n`;
|
|
381
|
-
changed = true;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// .env — 环境变量
|
|
385
|
-
if (!content.includes('.env') || (!content.match(/^\.env$/m) && !content.match(/^\.env\s/m))) {
|
|
386
|
-
content += `\n# AutoSnippet 环境变量(含 API Key,不入库)\n.env\n`;
|
|
387
|
-
changed = true;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// logs/ — 运行日志
|
|
391
|
-
if (!content.match(/^logs\/?$/m)) {
|
|
392
|
-
content += `\n# AutoSnippet 运行日志\nlogs/\n`;
|
|
393
|
-
changed = true;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 确保 AutoSnippet/ 不被忽略
|
|
397
|
-
const lines = content.split('\n');
|
|
398
|
-
const hasIgnoreAS = lines.some((l) => {
|
|
399
|
-
const t = l.trim();
|
|
400
|
-
return (
|
|
401
|
-
(t === 'AutoSnippet/' || t === 'AutoSnippet') && !t.startsWith('#') && !t.startsWith('!')
|
|
402
|
-
);
|
|
403
|
-
});
|
|
404
|
-
const hasNegation = lines.some((l) => l.trim() === '!AutoSnippet/');
|
|
405
|
-
if (hasIgnoreAS && !hasNegation) {
|
|
406
|
-
content += `\n# AutoSnippet 知识库必须入库(取消上方忽略)\n!AutoSnippet/\n`;
|
|
407
|
-
changed = true;
|
|
47
|
+
// Skills 路径迁移(一次性操作,不属于文件部署)
|
|
48
|
+
if (!skillsOnly && !mcpOnly) {
|
|
49
|
+
this._migrateSkillsPath();
|
|
408
50
|
}
|
|
409
51
|
|
|
410
|
-
|
|
411
|
-
writeFileSync(giPath, content);
|
|
412
|
-
} else {
|
|
413
|
-
}
|
|
52
|
+
return { deployed, skipped, errors };
|
|
414
53
|
}
|
|
415
54
|
|
|
416
55
|
/* ═══ Skills 路径迁移 ═══════════════════════════════ */
|
|
@@ -452,20 +91,6 @@ export class UpgradeService {
|
|
|
452
91
|
console.error(` ❌ 迁移失败: ${e.message}`);
|
|
453
92
|
}
|
|
454
93
|
}
|
|
455
|
-
|
|
456
|
-
/* ═══ 确保 Skills 目录存在 ══════════════════════════ */
|
|
457
|
-
|
|
458
|
-
_ensureSkillsDir() {
|
|
459
|
-
const skillsDir = join(this.projectRoot, 'AutoSnippet', 'skills');
|
|
460
|
-
if (!existsSync(join(this.projectRoot, 'AutoSnippet'))) {
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
if (existsSync(skillsDir)) {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
mkdirSync(skillsDir, { recursive: true });
|
|
468
|
-
}
|
|
469
94
|
}
|
|
470
95
|
|
|
471
96
|
export default UpgradeService;
|