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
package/bin/cli.js
CHANGED
|
@@ -9,18 +9,20 @@
|
|
|
9
9
|
* asd ais [Target] - AI 扫描 Target → 直接发布 Recipes
|
|
10
10
|
* asd search <query> - 搜索知识库
|
|
11
11
|
* asd guard <file> - Guard 检查
|
|
12
|
+
* asd guard:ci [path] - CI/CD Guard 合规检查
|
|
12
13
|
* asd watch - 文件监控
|
|
13
|
-
* asd compliance - 合规评估
|
|
14
14
|
* asd server - 启动 API 服务
|
|
15
|
-
* asd status - 环境状态
|
|
16
15
|
* asd ui - 启动 Dashboard UI
|
|
16
|
+
* asd upgrade - 升级 IDE 集成
|
|
17
17
|
* asd mirror - 镜像 .cursor/ → .qoder/ .trae/
|
|
18
|
+
* asd status - 环境状态
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
21
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
|
|
21
22
|
import { dirname, join, resolve } from 'node:path';
|
|
22
23
|
import { fileURLToPath } from 'node:url';
|
|
23
24
|
import { Command } from 'commander';
|
|
25
|
+
import { cli } from '../lib/cli/CliLogger.js';
|
|
24
26
|
|
|
25
27
|
const __filename = fileURLToPath(import.meta.url);
|
|
26
28
|
const __dirname = dirname(__filename);
|
|
@@ -89,7 +91,7 @@ program
|
|
|
89
91
|
.action(async (opts) => {
|
|
90
92
|
const projectRoot = resolve(opts.dir);
|
|
91
93
|
if (opts.skipGuard) {
|
|
92
|
-
|
|
94
|
+
cli.log('ℹ️ Guard 审计已跳过');
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
try {
|
|
@@ -111,7 +113,7 @@ program
|
|
|
111
113
|
spinner.stop();
|
|
112
114
|
|
|
113
115
|
if (opts.json) {
|
|
114
|
-
|
|
116
|
+
cli.json(result);
|
|
115
117
|
} else {
|
|
116
118
|
// 输出骨架报告
|
|
117
119
|
const report = result.report || {};
|
|
@@ -121,11 +123,11 @@ program
|
|
|
121
123
|
const astSummary = result.astSummary;
|
|
122
124
|
const framework = result.analysisFramework || {};
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
cli.log('\n📊 Coldstart Report');
|
|
127
|
+
cli.log(`${'─'.repeat(50)}`);
|
|
126
128
|
|
|
127
129
|
if (targets.length > 0) {
|
|
128
|
-
|
|
130
|
+
cli.log(`\n Targets: ${targets.map(t => t.name || t).join(', ')}`);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
if (Object.keys(langStats).length > 0) {
|
|
@@ -133,40 +135,40 @@ program
|
|
|
133
135
|
.sort((a, b) => b[1] - a[1])
|
|
134
136
|
.slice(0, 5)
|
|
135
137
|
.map(([ext, count]) => `${ext}(${count})`);
|
|
136
|
-
|
|
138
|
+
cli.log(` Languages: ${langParts.join(', ')}`);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
// AST 分析
|
|
140
142
|
if (astSummary) {
|
|
141
143
|
if (astSummary.metrics) {
|
|
142
|
-
|
|
144
|
+
cli.log(` AST Metrics: ${JSON.stringify(astSummary.metrics)}`);
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
// SPM 依赖
|
|
147
149
|
if (report.phases?.spmDependencyGraph) {
|
|
148
150
|
const spm = report.phases.spmDependencyGraph;
|
|
149
|
-
|
|
151
|
+
cli.log(` SPM Dependencies: ${spm.packageCount ?? '?'} packages`);
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
// Guard 审计
|
|
153
155
|
if (guardSummary) {
|
|
154
|
-
|
|
156
|
+
cli.log(` Guard: ${guardSummary.totalViolations ?? guardSummary.total ?? '?'} violations (${guardSummary.errors ?? '?'} errors, ${guardSummary.warnings ?? '?'} warnings)`);
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
// 维度分析框架
|
|
158
160
|
if (framework.dimensions) {
|
|
159
|
-
|
|
161
|
+
cli.log('\n Analysis Dimensions:');
|
|
160
162
|
for (const dim of framework.dimensions) {
|
|
161
163
|
const type = dim.skillWorthy ? (dim.dualOutput ? 'Dual' : 'Skill') : 'Candidate';
|
|
162
|
-
|
|
164
|
+
cli.log(` ${type.padEnd(10)} ${dim.id || dim.name || '?'}`);
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
if (result.bootstrapSession) {
|
|
166
168
|
const session = result.bootstrapSession;
|
|
167
|
-
|
|
169
|
+
cli.log(`\n Session: ${session.id || 'N/A'} (${session.status || 'unknown'})`);
|
|
168
170
|
}
|
|
169
|
-
|
|
171
|
+
cli.blank();
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
// 等待模式: 轮询 BootstrapTaskManager 直到所有维度完成
|
|
@@ -210,12 +212,12 @@ program
|
|
|
210
212
|
if (!opts.json) {
|
|
211
213
|
const succeeded = sessionStatus.tasks.filter((t) => t.status === 'done').length;
|
|
212
214
|
const failed = sessionStatus.tasks.filter((t) => t.status === 'error').length;
|
|
213
|
-
|
|
215
|
+
cli.log(`\n Results: ${succeeded} succeeded, ${failed} failed`);
|
|
214
216
|
for (const t of sessionStatus.tasks) {
|
|
215
217
|
const icon = t.status === 'done' ? '✅' : '❌';
|
|
216
|
-
|
|
218
|
+
cli.log(` ${icon} ${t.meta?.label || t.id}`);
|
|
217
219
|
}
|
|
218
|
-
|
|
220
|
+
cli.blank();
|
|
219
221
|
}
|
|
220
222
|
break;
|
|
221
223
|
}
|
|
@@ -228,15 +230,13 @@ program
|
|
|
228
230
|
waitSpinner.warn('AI 填充超时(10 分钟),可通过 asd ui 查看进度');
|
|
229
231
|
}
|
|
230
232
|
} else if (!opts.json) {
|
|
231
|
-
|
|
233
|
+
cli.log(' 💡 AI 填充已在后台运行。用 --wait 等待完成,或用 asd ui 查看进度。');
|
|
232
234
|
}
|
|
233
235
|
|
|
234
236
|
await bootstrap.shutdown();
|
|
235
237
|
} catch (err) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
console.error(err.stack);
|
|
239
|
-
}
|
|
238
|
+
cli.error(`\n❌ ${err.message}`);
|
|
239
|
+
cli.debug(err.stack);
|
|
240
240
|
process.exit(1);
|
|
241
241
|
}
|
|
242
242
|
});
|
|
@@ -254,10 +254,10 @@ program
|
|
|
254
254
|
.action(async (target, opts) => {
|
|
255
255
|
const projectRoot = resolve(opts.dir);
|
|
256
256
|
if (target) {
|
|
257
|
-
|
|
257
|
+
cli.log(`Target: ${target}`);
|
|
258
258
|
}
|
|
259
259
|
if (opts.dryRun) {
|
|
260
|
-
|
|
260
|
+
cli.log('ℹ️ Dry-run mode: no Recipes will be published');
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
try {
|
|
@@ -277,33 +277,31 @@ program
|
|
|
277
277
|
spinner.stop();
|
|
278
278
|
|
|
279
279
|
if (opts.json) {
|
|
280
|
-
|
|
280
|
+
cli.json(report);
|
|
281
281
|
} else {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
cli.log(`\n📝 AI Scan Report`);
|
|
283
|
+
cli.log(` Files scanned: ${report.files}`);
|
|
284
|
+
cli.log(` Published: ${report.published}`);
|
|
285
|
+
cli.log(` Skipped: ${report.skipped || 0}`);
|
|
286
286
|
if (report.errors.length > 0) {
|
|
287
|
-
|
|
287
|
+
cli.log(` Errors: ${report.errors.length}`);
|
|
288
288
|
for (const err of report.errors.slice(0, 10)) {
|
|
289
|
-
|
|
289
|
+
cli.log(` ❌ ${err}`);
|
|
290
290
|
}
|
|
291
291
|
if (report.errors.length > 10) {
|
|
292
|
-
|
|
292
|
+
cli.log(` ... and ${report.errors.length - 10} more`);
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
if (!opts.dryRun && report.published > 0) {
|
|
296
|
-
|
|
296
|
+
cli.log(`\n ✅ ${report.published} Recipes published successfully.`);
|
|
297
297
|
}
|
|
298
|
-
|
|
298
|
+
cli.blank();
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
await bootstrap.shutdown();
|
|
302
302
|
} catch (err) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
console.error(err.stack);
|
|
306
|
-
}
|
|
303
|
+
cli.error(`\n❌ ${err.message}`);
|
|
304
|
+
cli.debug(err.stack);
|
|
307
305
|
process.exit(1);
|
|
308
306
|
}
|
|
309
307
|
});
|
|
@@ -328,23 +326,23 @@ program
|
|
|
328
326
|
});
|
|
329
327
|
|
|
330
328
|
if (results.items.length === 0) {
|
|
331
|
-
|
|
329
|
+
cli.log('No results found.');
|
|
332
330
|
} else {
|
|
333
|
-
|
|
331
|
+
cli.log(`\n🔍 ${results.items.length} result(s) for "${query}"\n`);
|
|
334
332
|
for (const item of results.items) {
|
|
335
333
|
const badge = item.type === 'recipe' ? '📘' : item.type === 'solution' ? '💡' : '🛡️';
|
|
336
334
|
const score = item.score ? ` [${(item.score * 100).toFixed(0)}%]` : '';
|
|
337
|
-
|
|
335
|
+
cli.log(` ${badge} ${item.title || item.trigger || item.id}${score}`);
|
|
338
336
|
if (item.description) {
|
|
339
|
-
|
|
337
|
+
cli.log(` ${item.description.slice(0, 100)}`);
|
|
340
338
|
}
|
|
341
339
|
}
|
|
342
|
-
|
|
340
|
+
cli.blank();
|
|
343
341
|
}
|
|
344
342
|
|
|
345
343
|
await bootstrap.shutdown();
|
|
346
344
|
} catch (err) {
|
|
347
|
-
|
|
345
|
+
cli.error('Error:', err.message);
|
|
348
346
|
process.exit(1);
|
|
349
347
|
}
|
|
350
348
|
});
|
|
@@ -361,7 +359,7 @@ program
|
|
|
361
359
|
try {
|
|
362
360
|
const filePath = resolve(file);
|
|
363
361
|
if (!existsSync(filePath)) {
|
|
364
|
-
|
|
362
|
+
cli.error(`File not found: ${filePath}`);
|
|
365
363
|
process.exit(1);
|
|
366
364
|
}
|
|
367
365
|
|
|
@@ -374,26 +372,26 @@ program
|
|
|
374
372
|
const violations = engine.checkCode(code, language, { scope: opts.scope });
|
|
375
373
|
|
|
376
374
|
if (opts.json) {
|
|
377
|
-
|
|
375
|
+
cli.json({ violations, summary: { total: violations.length, errors: violations.filter(v => v.severity === 'error').length, warnings: violations.filter(v => v.severity === 'warning').length } });
|
|
378
376
|
} else if (violations.length === 0) {
|
|
379
|
-
|
|
377
|
+
cli.log('✅ No violations found.');
|
|
380
378
|
} else {
|
|
381
379
|
const errors = violations.filter((v) => v.severity === 'error');
|
|
382
380
|
const warnings = violations.filter((v) => v.severity === 'warning');
|
|
383
|
-
|
|
381
|
+
cli.log(`\n🔍 Guard: ${violations.length} violation(s) — ${errors.length} error(s), ${warnings.length} warning(s)\n`);
|
|
384
382
|
for (const v of violations) {
|
|
385
383
|
const icon = v.severity === 'error' ? '❌' : v.severity === 'warning' ? '⚠️' : 'ℹ️';
|
|
386
|
-
|
|
387
|
-
if (v.line)
|
|
388
|
-
if (v.fixSuggestion)
|
|
384
|
+
cli.log(` ${icon} [${v.ruleId}] ${v.message}`);
|
|
385
|
+
if (v.line) cli.log(` Line ${v.line}: ${v.snippet || ''}`);
|
|
386
|
+
if (v.fixSuggestion) cli.log(` 💡 Fix: ${v.fixSuggestion}`);
|
|
389
387
|
}
|
|
390
|
-
|
|
388
|
+
cli.blank();
|
|
391
389
|
}
|
|
392
390
|
|
|
393
391
|
await bootstrap.shutdown();
|
|
394
392
|
process.exit(violations.some((v) => v.severity === 'error') ? 1 : 0);
|
|
395
393
|
} catch (err) {
|
|
396
|
-
|
|
394
|
+
cli.error('Error:', err.message);
|
|
397
395
|
process.exit(1);
|
|
398
396
|
}
|
|
399
397
|
});
|
|
@@ -432,9 +430,9 @@ program
|
|
|
432
430
|
if (opts.output) {
|
|
433
431
|
const { writeFileSync } = await import('node:fs');
|
|
434
432
|
writeFileSync(opts.output, output, 'utf8');
|
|
435
|
-
|
|
433
|
+
cli.log(`Report written to ${opts.output}`);
|
|
436
434
|
} else {
|
|
437
|
-
|
|
435
|
+
cli.log(output);
|
|
438
436
|
}
|
|
439
437
|
} else {
|
|
440
438
|
reporter.printReport(report, { format: opts.report });
|
|
@@ -454,10 +452,8 @@ program
|
|
|
454
452
|
}
|
|
455
453
|
process.exit(0);
|
|
456
454
|
} catch (err) {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
console.error(err.stack);
|
|
460
|
-
}
|
|
455
|
+
cli.error(`Error: ${err.message}`);
|
|
456
|
+
cli.debug(err.stack);
|
|
461
457
|
process.exit(1);
|
|
462
458
|
}
|
|
463
459
|
});
|
|
@@ -484,7 +480,7 @@ program
|
|
|
484
480
|
.split('\n')
|
|
485
481
|
.filter(Boolean);
|
|
486
482
|
} catch (_err) {
|
|
487
|
-
|
|
483
|
+
cli.error('❌ 无法获取 git staged 文件(是否在 git 仓库中?)');
|
|
488
484
|
process.exit(1);
|
|
489
485
|
}
|
|
490
486
|
|
|
@@ -520,32 +516,30 @@ program
|
|
|
520
516
|
const { summary } = result;
|
|
521
517
|
|
|
522
518
|
if (opts.json) {
|
|
523
|
-
|
|
519
|
+
cli.json({ files: result.files, summary });
|
|
524
520
|
} else if (summary.totalViolations === 0) {
|
|
525
|
-
|
|
521
|
+
cli.log(`✅ ${sourceFiles.length} staged file(s) checked — no violations.`);
|
|
526
522
|
} else {
|
|
527
|
-
|
|
523
|
+
cli.log(`\n🔍 Guard (staged): ${summary.totalViolations} violation(s) in ${sourceFiles.length} file(s)\n`);
|
|
528
524
|
const filesWithIssues = result.files.filter((f) => f.summary.total > 0);
|
|
529
525
|
for (const file of filesWithIssues.slice(0, 10)) {
|
|
530
|
-
|
|
526
|
+
cli.log(` 📄 ${file.filePath || file.path}`);
|
|
531
527
|
for (const v of file.violations.slice(0, 5)) {
|
|
532
528
|
const icon = v.severity === 'error' ? '❌' : '⚠️';
|
|
533
|
-
|
|
529
|
+
cli.log(` ${icon} [${v.ruleId}] ${v.message}`);
|
|
534
530
|
}
|
|
535
531
|
if (file.violations.length > 5) {
|
|
536
|
-
|
|
532
|
+
cli.log(` ... and ${file.violations.length - 5} more`);
|
|
537
533
|
}
|
|
538
534
|
}
|
|
539
|
-
|
|
535
|
+
cli.blank();
|
|
540
536
|
}
|
|
541
537
|
|
|
542
538
|
await bootstrap.shutdown();
|
|
543
539
|
process.exit(summary.totalErrors > 0 ? 1 : 0);
|
|
544
540
|
} catch (err) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
console.error(err.stack);
|
|
548
|
-
}
|
|
541
|
+
cli.error(`Error: ${err.message}`);
|
|
542
|
+
cli.debug(err.stack);
|
|
549
543
|
process.exit(1);
|
|
550
544
|
}
|
|
551
545
|
});
|
|
@@ -596,10 +590,8 @@ program
|
|
|
596
590
|
process.exit(0);
|
|
597
591
|
});
|
|
598
592
|
} catch (err) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
console.error(err.stack);
|
|
602
|
-
}
|
|
593
|
+
cli.error(`Error: ${err.message}`);
|
|
594
|
+
cli.debug(err.stack);
|
|
603
595
|
process.exit(1);
|
|
604
596
|
}
|
|
605
597
|
});
|
|
@@ -686,10 +678,8 @@ program
|
|
|
686
678
|
signalCollector.start();
|
|
687
679
|
global._signalCollector = signalCollector;
|
|
688
680
|
} catch (scErr) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
console.error(scErr.stack);
|
|
692
|
-
}
|
|
681
|
+
cli.warn(`⚠️ SignalCollector failed to start: ${scErr.message}`);
|
|
682
|
+
cli.debug(scErr.stack);
|
|
693
683
|
}
|
|
694
684
|
|
|
695
685
|
// 3. 启动文件监听器(仅 iOS/macOS 项目 — Xcode 工作流)
|
|
@@ -779,17 +769,15 @@ program
|
|
|
779
769
|
if (isDebugMode) {
|
|
780
770
|
}
|
|
781
771
|
} catch (watchErr) {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
console.error(watchErr.stack);
|
|
785
|
-
}
|
|
772
|
+
cli.warn(`⚠️ File watcher failed to start: ${watchErr.message}`);
|
|
773
|
+
cli.debug(watchErr.stack);
|
|
786
774
|
}
|
|
787
775
|
} else if (process.env.ASD_DEBUG === '1') {
|
|
788
776
|
}
|
|
789
777
|
} catch (err) {
|
|
790
|
-
|
|
778
|
+
cli.error(`❌ API server failed to start: ${err.message}`);
|
|
791
779
|
if (err.code === 'EADDRINUSE') {
|
|
792
|
-
|
|
780
|
+
cli.error(
|
|
793
781
|
` Port ${port} is already in use. Kill it with: lsof -ti:${port} | xargs kill -9`
|
|
794
782
|
);
|
|
795
783
|
}
|
|
@@ -836,7 +824,7 @@ program
|
|
|
836
824
|
});
|
|
837
825
|
|
|
838
826
|
vite.on('error', (err) => {
|
|
839
|
-
|
|
827
|
+
cli.error(`❌ Vite failed to start: ${err.message}`);
|
|
840
828
|
});
|
|
841
829
|
|
|
842
830
|
process.on('SIGINT', () => {
|
|
@@ -853,35 +841,35 @@ program
|
|
|
853
841
|
.command('status')
|
|
854
842
|
.description('检查环境状态')
|
|
855
843
|
.action(async () => {
|
|
856
|
-
|
|
857
|
-
|
|
844
|
+
cli.log('\n AutoSnippet Environment Status');
|
|
845
|
+
cli.log(` ${'─'.repeat(40)}`);
|
|
858
846
|
|
|
859
847
|
// AI 配置
|
|
860
848
|
const { getAiConfigInfo } = await import('../lib/external/ai/AiFactory.js');
|
|
861
849
|
const aiInfo = getAiConfigInfo();
|
|
862
|
-
|
|
863
|
-
if (aiInfo.model)
|
|
850
|
+
cli.log(` AI Provider: ${aiInfo.provider || 'not configured'}`);
|
|
851
|
+
if (aiInfo.model) cli.log(` AI Model: ${aiInfo.model}`);
|
|
864
852
|
|
|
865
853
|
// 检查数据库
|
|
866
854
|
const dbPath = join(process.cwd(), '.autosnippet', 'autosnippet.db');
|
|
867
855
|
const dbExists = existsSync(dbPath);
|
|
868
|
-
|
|
856
|
+
cli.log(` Database: ${dbExists ? '✅ ' + dbPath : '❌ not found'}`);
|
|
869
857
|
|
|
870
858
|
// 检查 .autosnippet 目录
|
|
871
859
|
const asdDir = join(process.cwd(), '.autosnippet');
|
|
872
|
-
|
|
860
|
+
cli.log(` Workspace: ${existsSync(asdDir) ? '✅ .autosnippet/' : '❌ not initialized (run asd setup)'}`);
|
|
873
861
|
|
|
874
862
|
// 检查依赖
|
|
875
|
-
|
|
863
|
+
cli.log(' Dependencies:');
|
|
876
864
|
for (const dep of ['better-sqlite3', 'commander', 'express']) {
|
|
877
865
|
try {
|
|
878
866
|
await import(dep);
|
|
879
|
-
|
|
867
|
+
cli.log(` ✅ ${dep}`);
|
|
880
868
|
} catch {
|
|
881
|
-
|
|
869
|
+
cli.log(` ❌ ${dep} (missing)`);
|
|
882
870
|
}
|
|
883
871
|
}
|
|
884
|
-
|
|
872
|
+
cli.blank();
|
|
885
873
|
});
|
|
886
874
|
|
|
887
875
|
// ─────────────────────────────────────────────────────
|
|
@@ -889,7 +877,7 @@ program
|
|
|
889
877
|
// ─────────────────────────────────────────────────────
|
|
890
878
|
program
|
|
891
879
|
.command('upgrade')
|
|
892
|
-
.description('升级 IDE
|
|
880
|
+
.description('升级 IDE 集成(全量:MCP + Rules + Hooks + Instructions + Skills + Constitution + .gitignore)')
|
|
893
881
|
.option('-d, --dir <path>', '项目目录', '.')
|
|
894
882
|
.option('--skills-only', '仅更新 Skills')
|
|
895
883
|
.option('--mcp-only', '仅更新 MCP 配置')
|
|
@@ -918,22 +906,22 @@ program
|
|
|
918
906
|
try {
|
|
919
907
|
const pipeline = container.get('cursorDeliveryPipeline');
|
|
920
908
|
const result = await pipeline.deliver();
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
909
|
+
cli.log('\n Cursor Rules Delivery');
|
|
910
|
+
cli.log(` ${'─'.repeat(40)}`);
|
|
911
|
+
cli.log(` Channel A: ${result.channelA?.count ?? '?'} always-on rules`);
|
|
912
|
+
cli.log(` Channel B: ${result.channelB?.count ?? Object.keys(result.channelB?.topics || {}).length} topic rules`);
|
|
913
|
+
cli.log(` Channel C: ${result.channelC?.count ?? '?'} skills (${result.channelC?.errors ?? 0} errors)`);
|
|
926
914
|
if (result.channelC.errors > 0) {
|
|
927
|
-
|
|
915
|
+
cli.log(` ⚠️ ${result.channelC.errors} skill(s) failed to deliver`);
|
|
928
916
|
}
|
|
929
917
|
|
|
930
918
|
if (opts.verbose && result.channelB.topics) {
|
|
931
|
-
|
|
919
|
+
cli.log('\n Channel B Topics:');
|
|
932
920
|
for (const [topic, info] of Object.entries(result.channelB.topics)) {
|
|
933
|
-
|
|
921
|
+
cli.log(` ${topic}: ${info.count ?? info.rules?.length ?? '?'} rules`);
|
|
934
922
|
}
|
|
935
923
|
}
|
|
936
|
-
|
|
924
|
+
cli.blank();
|
|
937
925
|
} finally {
|
|
938
926
|
await bootstrap.shutdown?.();
|
|
939
927
|
}
|
|
@@ -961,18 +949,18 @@ taskCmd
|
|
|
961
949
|
if (opts.status) filters.status = opts.status;
|
|
962
950
|
const tasks = await svc.list(filters, { limit: parseInt(opts.limit, 10) });
|
|
963
951
|
if (tasks.length === 0) {
|
|
964
|
-
|
|
952
|
+
cli.log('No tasks found.');
|
|
965
953
|
} else {
|
|
966
|
-
|
|
967
|
-
|
|
954
|
+
cli.log(`\n ID Status Priority Title`);
|
|
955
|
+
cli.log(` ${'─'.repeat(70)}`);
|
|
968
956
|
for (const t of tasks) {
|
|
969
957
|
const j = t.toJSON ? t.toJSON() : t;
|
|
970
958
|
const id = (j.id || '').padEnd(16);
|
|
971
959
|
const status = (j.status || '').padEnd(13);
|
|
972
960
|
const pri = String(j.priority ?? '-').padEnd(9);
|
|
973
|
-
|
|
961
|
+
cli.log(` ${id} ${status} ${pri} ${j.title}`);
|
|
974
962
|
}
|
|
975
|
-
|
|
963
|
+
cli.log(`\n Total: ${tasks.length}\n`);
|
|
976
964
|
}
|
|
977
965
|
} finally {
|
|
978
966
|
await bootstrap.shutdown?.();
|
|
@@ -994,19 +982,19 @@ taskCmd
|
|
|
994
982
|
withKnowledge: true,
|
|
995
983
|
});
|
|
996
984
|
if (tasks.length === 0) {
|
|
997
|
-
|
|
985
|
+
cli.log('No ready tasks.');
|
|
998
986
|
} else {
|
|
999
987
|
for (const t of tasks) {
|
|
1000
988
|
const j = t.toJSON ? t.toJSON() : t;
|
|
1001
|
-
|
|
989
|
+
cli.log(`\n ▸ ${j.id} — ${j.title} (P${j.priority ?? '?'})`);
|
|
1002
990
|
if (t.knowledgeContext?.relatedKnowledge?.length) {
|
|
1003
|
-
|
|
991
|
+
cli.log(` Knowledge: ${t.knowledgeContext.relatedKnowledge.map(k => k.title).join(', ')}`);
|
|
1004
992
|
}
|
|
1005
993
|
if (t.knowledgeContext?.guardRules?.length) {
|
|
1006
|
-
|
|
994
|
+
cli.log(` Guard: ${t.knowledgeContext.guardRules.map(r => r.title).join(', ')}`);
|
|
1007
995
|
}
|
|
1008
996
|
}
|
|
1009
|
-
|
|
997
|
+
cli.blank();
|
|
1010
998
|
}
|
|
1011
999
|
} finally {
|
|
1012
1000
|
await bootstrap.shutdown?.();
|
|
@@ -1023,24 +1011,24 @@ taskCmd
|
|
|
1023
1011
|
try {
|
|
1024
1012
|
const svc = container.get('taskGraphService');
|
|
1025
1013
|
const result = await svc.prime({ withKnowledge: true });
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1014
|
+
cli.log(`\n TaskGraph Prime`);
|
|
1015
|
+
cli.log(` ${'─'.repeat(40)}`);
|
|
1016
|
+
cli.log(` In Progress: ${result.inProgress.length}`);
|
|
1017
|
+
cli.log(` Ready: ${result.ready.length}`);
|
|
1018
|
+
cli.log(` Stats: ${JSON.stringify(result.stats)}`);
|
|
1031
1019
|
if (result.inProgress.length > 0) {
|
|
1032
|
-
|
|
1020
|
+
cli.log(`\n ▸ In Progress:`);
|
|
1033
1021
|
for (const t of result.inProgress) {
|
|
1034
|
-
|
|
1022
|
+
cli.log(` ${t.id} — ${t.title}`);
|
|
1035
1023
|
}
|
|
1036
1024
|
}
|
|
1037
1025
|
if (result.ready.length > 0) {
|
|
1038
|
-
|
|
1026
|
+
cli.log(`\n ▸ Ready:`);
|
|
1039
1027
|
for (const t of result.ready) {
|
|
1040
|
-
|
|
1028
|
+
cli.log(` ${t.id} — ${t.title}`);
|
|
1041
1029
|
}
|
|
1042
1030
|
}
|
|
1043
|
-
|
|
1031
|
+
cli.blank();
|
|
1044
1032
|
} finally {
|
|
1045
1033
|
await bootstrap.shutdown?.();
|
|
1046
1034
|
}
|
|
@@ -1056,12 +1044,12 @@ taskCmd
|
|
|
1056
1044
|
try {
|
|
1057
1045
|
const svc = container.get('taskGraphService');
|
|
1058
1046
|
const stats = await svc.stats();
|
|
1059
|
-
|
|
1060
|
-
|
|
1047
|
+
cli.log(`\n TaskGraph Statistics`);
|
|
1048
|
+
cli.log(` ${'─'.repeat(30)}`);
|
|
1061
1049
|
for (const [key, val] of Object.entries(stats)) {
|
|
1062
|
-
|
|
1050
|
+
cli.log(` ${key.padEnd(15)} ${val}`);
|
|
1063
1051
|
}
|
|
1064
|
-
|
|
1052
|
+
cli.blank();
|
|
1065
1053
|
} finally {
|
|
1066
1054
|
await bootstrap.shutdown?.();
|
|
1067
1055
|
}
|
|
@@ -1081,11 +1069,14 @@ program
|
|
|
1081
1069
|
|
|
1082
1070
|
const cursorDir = join(projectRoot, '.cursor');
|
|
1083
1071
|
if (!existsSync(cursorDir)) {
|
|
1084
|
-
|
|
1072
|
+
cli.error('❌ 未找到 .cursor/ 目录,请先运行 asd setup 或 asd cursor-rules');
|
|
1085
1073
|
process.exit(1);
|
|
1086
1074
|
}
|
|
1087
1075
|
|
|
1088
1076
|
for (const target of targets) {
|
|
1077
|
+
let count = 0;
|
|
1078
|
+
|
|
1079
|
+
// 1. 镜像 rules/ — autosnippet- 前缀文件(.mdc → .md 改名)
|
|
1089
1080
|
const cursorRulesDir = join(cursorDir, 'rules');
|
|
1090
1081
|
if (existsSync(cursorRulesDir)) {
|
|
1091
1082
|
const targetRulesDir = join(projectRoot, target, 'rules');
|
|
@@ -1096,9 +1087,11 @@ program
|
|
|
1096
1087
|
for (const file of files) {
|
|
1097
1088
|
const destName = file.endsWith('.mdc') ? file.replace(/\.mdc$/, '.md') : file;
|
|
1098
1089
|
copyFileSync(join(cursorRulesDir, file), join(targetRulesDir, destName));
|
|
1090
|
+
count++;
|
|
1099
1091
|
}
|
|
1100
1092
|
}
|
|
1101
1093
|
|
|
1094
|
+
// 2. 镜像 skills/ — autosnippet- 前缀目录
|
|
1102
1095
|
const cursorSkillsDir = join(cursorDir, 'skills');
|
|
1103
1096
|
if (existsSync(cursorSkillsDir)) {
|
|
1104
1097
|
const targetSkillsDir = join(projectRoot, target, 'skills');
|
|
@@ -1107,8 +1100,34 @@ program
|
|
|
1107
1100
|
);
|
|
1108
1101
|
for (const dir of skillDirs) {
|
|
1109
1102
|
_copyDirRecursive(join(cursorSkillsDir, dir.name), join(targetSkillsDir, dir.name));
|
|
1103
|
+
count++;
|
|
1110
1104
|
}
|
|
1111
1105
|
}
|
|
1106
|
+
|
|
1107
|
+
// 3. 镜像 hooks/ — hook 脚本(全覆盖)
|
|
1108
|
+
const cursorHooksDir = join(cursorDir, 'hooks');
|
|
1109
|
+
if (existsSync(cursorHooksDir)) {
|
|
1110
|
+
_copyDirRecursive(cursorHooksDir, join(projectRoot, target, 'hooks'));
|
|
1111
|
+
count++;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// 4. 镜像 commands/ — 斜杠命令(全覆盖)
|
|
1115
|
+
const cursorCommandsDir = join(cursorDir, 'commands');
|
|
1116
|
+
if (existsSync(cursorCommandsDir)) {
|
|
1117
|
+
_copyDirRecursive(cursorCommandsDir, join(projectRoot, target, 'commands'));
|
|
1118
|
+
count++;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// 5. 镜像 hooks.json
|
|
1122
|
+
const hooksJson = join(cursorDir, 'hooks.json');
|
|
1123
|
+
if (existsSync(hooksJson)) {
|
|
1124
|
+
mkdirSync(join(projectRoot, target), { recursive: true });
|
|
1125
|
+
copyFileSync(hooksJson, join(projectRoot, target, 'hooks.json'));
|
|
1126
|
+
count++;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
const label = target.replace('.', '').charAt(0).toUpperCase() + target.slice(2);
|
|
1130
|
+
cli.log(` ✅ ${label}: ${count} item(s) mirrored`);
|
|
1112
1131
|
}
|
|
1113
1132
|
});
|
|
1114
1133
|
|
|
@@ -1140,7 +1159,7 @@ program
|
|
|
1140
1159
|
const { KnowledgeSyncService } = await import('../lib/cli/KnowledgeSyncService.js');
|
|
1141
1160
|
const syncService = new KnowledgeSyncService(projectRoot);
|
|
1142
1161
|
if (opts.dryRun) {
|
|
1143
|
-
|
|
1162
|
+
cli.log('ℹ️ Dry-run mode: no changes will be written');
|
|
1144
1163
|
}
|
|
1145
1164
|
|
|
1146
1165
|
// 通过 Bootstrap 打开目标项目的 DB
|
|
@@ -1153,7 +1172,7 @@ program
|
|
|
1153
1172
|
const { bootstrap, container } = await initContainer({ projectRoot });
|
|
1154
1173
|
const db = container.get('database')?.getDb?.();
|
|
1155
1174
|
if (!db) {
|
|
1156
|
-
|
|
1175
|
+
cli.error('❌ 无法打开数据库,请先运行 asd setup');
|
|
1157
1176
|
process.exit(1);
|
|
1158
1177
|
}
|
|
1159
1178
|
|
|
@@ -1163,27 +1182,27 @@ program
|
|
|
1163
1182
|
force: opts.force,
|
|
1164
1183
|
});
|
|
1165
1184
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1185
|
+
cli.log('\n Knowledge Sync Report');
|
|
1186
|
+
cli.log(` ${'─'.repeat(40)}`);
|
|
1187
|
+
cli.log(` Created: ${report.created ?? 0}`);
|
|
1188
|
+
cli.log(` Updated: ${report.updated ?? 0}`);
|
|
1189
|
+
cli.log(` Unchanged: ${report.unchanged ?? 0}`);
|
|
1190
|
+
cli.log(` Deleted: ${report.deleted ?? 0}`);
|
|
1172
1191
|
|
|
1173
1192
|
if (report.violations.length > 0) {
|
|
1174
|
-
|
|
1193
|
+
cli.log(`\n ⚠️ Violations (${report.violations.length}):`);
|
|
1175
1194
|
for (const v of report.violations) {
|
|
1176
|
-
|
|
1195
|
+
cli.log(` ❌ ${v.file || v.id}: ${v.message || v}`);
|
|
1177
1196
|
}
|
|
1178
1197
|
}
|
|
1179
1198
|
|
|
1180
1199
|
if (report.orphaned.length > 0) {
|
|
1181
|
-
|
|
1200
|
+
cli.log(`\n 👻 Orphaned entries (${report.orphaned.length}):`);
|
|
1182
1201
|
for (const id of report.orphaned) {
|
|
1183
|
-
|
|
1202
|
+
cli.log(` ${id}`);
|
|
1184
1203
|
}
|
|
1185
1204
|
}
|
|
1186
|
-
|
|
1205
|
+
cli.blank();
|
|
1187
1206
|
} finally {
|
|
1188
1207
|
await bootstrap.shutdown?.();
|
|
1189
1208
|
}
|