autosnippet 3.3.2 → 3.3.4

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.
Files changed (55) hide show
  1. package/README.md +8 -4
  2. package/dist/bin/cli.js +27 -1
  3. package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
  4. package/dist/lib/cli/KnowledgeSyncService.js +33 -1
  5. package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
  6. package/dist/lib/external/mcp/handlers/browse.js +2 -1
  7. package/dist/lib/external/mcp/handlers/consolidated.d.ts +1 -0
  8. package/dist/lib/external/mcp/handlers/panorama.d.ts +11 -11
  9. package/dist/lib/external/mcp/handlers/panorama.js +20 -20
  10. package/dist/lib/external/mcp/handlers/system.d.ts +1 -1
  11. package/dist/lib/external/mcp/handlers/task.js +38 -15
  12. package/dist/lib/external/mcp/tools.d.ts +12 -12
  13. package/dist/lib/external/mcp/tools.js +120 -118
  14. package/dist/lib/http/middleware/validate.js +7 -3
  15. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +100 -0
  16. package/dist/lib/infrastructure/database/drizzle/schema.js +10 -0
  17. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
  18. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
  19. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
  20. package/dist/lib/injection/ServiceContainer.js +2 -0
  21. package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
  22. package/dist/lib/injection/modules/KnowledgeModule.js +80 -0
  23. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
  24. package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
  25. package/dist/lib/service/evolution/ConsolidationAdvisor.js +9 -9
  26. package/dist/lib/service/evolution/ContradictionDetector.js +2 -2
  27. package/dist/lib/service/evolution/RedundancyAnalyzer.js +2 -2
  28. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
  29. package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
  30. package/dist/lib/service/panorama/PanoramaService.d.ts +18 -1
  31. package/dist/lib/service/panorama/PanoramaService.js +148 -5
  32. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  33. package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
  34. package/dist/lib/service/search/CoarseRanker.js +11 -10
  35. package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
  36. package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
  37. package/dist/lib/service/search/MultiSignalRanker.d.ts +2 -2
  38. package/dist/lib/service/search/MultiSignalRanker.js +1 -1
  39. package/dist/lib/service/search/SearchEngine.d.ts +8 -7
  40. package/dist/lib/service/search/SearchEngine.js +59 -10
  41. package/dist/lib/service/search/SearchTypes.d.ts +23 -3
  42. package/dist/lib/service/search/SearchTypes.js +6 -1
  43. package/dist/lib/service/task/IntentExtractor.d.ts +11 -1
  44. package/dist/lib/service/task/IntentExtractor.js +137 -3
  45. package/dist/lib/service/task/PrimeSearchPipeline.js +95 -25
  46. package/dist/lib/service/vector/VectorService.d.ts +3 -0
  47. package/dist/lib/service/vector/VectorService.js +38 -4
  48. package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -0
  49. package/dist/lib/shared/schemas/mcp-tools.js +5 -1
  50. package/package.json +1 -1
  51. package/skills/autosnippet-create/SKILL.md +98 -89
  52. package/skills/autosnippet-devdocs/SKILL.md +55 -60
  53. package/templates/guard-ci.yml +2 -2
  54. package/templates/instructions/conventions.md +4 -2
  55. package/templates/recipes-setup/_template.md +39 -39
package/README.md CHANGED
@@ -93,13 +93,17 @@ Want to know the blast radius before refactoring a function? Static call graph a
93
93
 
94
94
  Keyword search only finds literal matches. With an LLM API Key, search upgrades to vector + BM25 hybrid retrieval — asking "how to manage memory" finds Recipes about garbage collection, semantically similar results rank first.
95
95
 
96
- ### Knowledge Graph
96
+ ### Intent-Aware Search (Prime)
97
97
 
98
- Recipes have relationships. Query impact paths, dependency depth, and related Recipes for any module once you've accumulated enough knowledge, it helps you see the structure behind it.
98
+ At the start of every conversation, the Agent auto-triggers prime to intelligently inject knowledge based on the user query and current file. IntentExtractor extracts tech terms, infers language and module, performs cross-language (EN↔CJK) synonym expansion; PrimeSearchPipeline executes multi-query parallel search (raw query + term query + file context + focused synonyms), returning precise results after 3-layer quality filtering. Supports long natural-language sentences, short exact matches, and mixed-language queries.
99
+
100
+ ### Recipe Source Evidence (sourceRefs)
99
101
 
100
- ### TaskGraph Orchestration
102
+ Recipes carry the project file paths analyzed during creation as evidence. The 📍 sourceRefs in search results point to real project files — the Agent can trust and reference them without self-verification. Path validity is monitored automatically, with git rename auto-repair.
101
103
 
102
- Break a large task into steps, declare dependencies between them, and each step auto-injects relevant Recipes as context. Team decisions (rationale, confidence) persist alongside tasks — they don't vanish with the conversation.
104
+ ### Knowledge Graph
105
+
106
+ Recipes have relationships. Query impact paths, dependency depth, and related Recipes for any module — once you've accumulated enough knowledge, it helps you see the structure behind it.
103
107
 
104
108
  ### Self-Cycling Signal Mechanism
105
109
 
package/dist/bin/cli.js CHANGED
@@ -742,6 +742,17 @@ program
742
742
  httpServer = new HttpServer({ port, host });
743
743
  await httpServer.initialize();
744
744
  await httpServer.start();
745
+ // ── UiStartupTasks: 后台异步刷新(不阻塞 UI) ──
746
+ import('../lib/service/bootstrap/UiStartupTasks.js')
747
+ .then(({ runUiStartupTasks }) => runUiStartupTasks({ projectRoot, container }))
748
+ .then((report) => {
749
+ if (report.errors.length > 0) {
750
+ cli.warn(`⚠️ UiStartupTasks completed with ${report.errors.length} error(s)`);
751
+ }
752
+ })
753
+ .catch((err) => {
754
+ cli.debug(`UiStartupTasks failed: ${err.message}`);
755
+ });
745
756
  // ── MCP 配置检测 ──
746
757
  const cursorMcpPath = join(projectRoot, '.cursor', 'mcp.json');
747
758
  const vscodeMcpPath = join(projectRoot, '.vscode', 'mcp.json');
@@ -1337,7 +1348,7 @@ program
1337
1348
  process.exit(1);
1338
1349
  }
1339
1350
  try {
1340
- const report = syncService.sync(db, {
1351
+ const report = await syncService.syncAll(db, {
1341
1352
  dryRun: opts.dryRun,
1342
1353
  force: opts.force,
1343
1354
  });
@@ -1347,6 +1358,21 @@ program
1347
1358
  cli.log(` Updated: ${report.updated ?? 0}`);
1348
1359
  cli.log(` Unchanged: ${report.unchanged ?? 0}`);
1349
1360
  cli.log(` Deleted: ${report.deleted ?? 0}`);
1361
+ if (report.reconcileReport) {
1362
+ cli.log(`\n 📍 Source Refs`);
1363
+ cli.log(` ${'─'.repeat(40)}`);
1364
+ cli.log(` Inserted: ${report.reconcileReport.inserted ?? 0}`);
1365
+ cli.log(` Active: ${report.reconcileReport.active ?? 0}`);
1366
+ cli.log(` Stale: ${report.reconcileReport.stale ?? 0}`);
1367
+ cli.log(` Skipped: ${report.reconcileReport.skipped ?? 0}`);
1368
+ }
1369
+ if (report.repairReport &&
1370
+ (report.repairReport.renamed > 0 || report.repairReport.stillStale > 0)) {
1371
+ cli.log(`\n 🔧 Rename Repairs`);
1372
+ cli.log(` ${'─'.repeat(40)}`);
1373
+ cli.log(` Renamed: ${report.repairReport.renamed ?? 0}`);
1374
+ cli.log(` Still Stale: ${report.repairReport.stillStale ?? 0}`);
1375
+ }
1350
1376
  if (report.violations.length > 0) {
1351
1377
  cli.log(`\n ⚠️ Violations (${report.violations.length}):`);
1352
1378
  for (const v of report.violations) {
@@ -14,12 +14,38 @@
14
14
  * - 内部: SetupService.stepDatabase() 委托调用(skipViolations = true)
15
15
  */
16
16
  import Logger from '../infrastructure/logging/Logger.js';
17
+ import type { ApplyReport, ReconcileReport, RepairReport } from '../service/knowledge/SourceRefReconciler.js';
18
+ export interface SyncAllReport {
19
+ synced: number;
20
+ created: number;
21
+ updated: number;
22
+ violations: string[];
23
+ orphaned: string[];
24
+ skipped: number;
25
+ reconcileReport?: ReconcileReport;
26
+ repairReport?: RepairReport;
27
+ applyReport?: ApplyReport;
28
+ }
17
29
  export declare class KnowledgeSyncService {
18
30
  candidatesDir: string;
19
31
  logger: ReturnType<typeof Logger.getInstance>;
20
32
  projectRoot: string;
21
33
  recipesDir: string;
22
34
  constructor(projectRoot: string);
35
+ /**
36
+ * 完整同步入口 — sync + reconcile + repair
37
+ *
38
+ * asd sync CLI 和 asd ui 启动都调用此方法。
39
+ *
40
+ * @param db better-sqlite3 原始句柄
41
+ * @param opts 同步选项
42
+ * @returns 包含 sync + reconcile + repair 报告的综合结果
43
+ */
44
+ syncAll(db: Parameters<KnowledgeSyncService['sync']>[0], opts?: {
45
+ dryRun?: boolean;
46
+ force?: boolean;
47
+ skipViolations?: boolean;
48
+ }): Promise<SyncAllReport>;
23
49
  /**
24
50
  * 执行增量同步:.md → DB(knowledge_entries 表)
25
51
  *
@@ -19,6 +19,7 @@ import path from 'node:path';
19
19
  import { CANDIDATES_DIR, RECIPES_DIR } from '../infrastructure/config/Defaults.js';
20
20
  import Logger from '../infrastructure/logging/Logger.js';
21
21
  import { computeKnowledgeHash, parseKnowledgeMarkdown, } from '../service/knowledge/KnowledgeFileWriter.js';
22
+ import { SourceRefReconciler } from '../service/knowledge/SourceRefReconciler.js';
22
23
  export class KnowledgeSyncService {
23
24
  candidatesDir;
24
25
  logger;
@@ -30,6 +31,37 @@ export class KnowledgeSyncService {
30
31
  this.candidatesDir = path.join(projectRoot, CANDIDATES_DIR);
31
32
  this.logger = Logger.getInstance();
32
33
  }
34
+ /**
35
+ * 完整同步入口 — sync + reconcile + repair
36
+ *
37
+ * asd sync CLI 和 asd ui 启动都调用此方法。
38
+ *
39
+ * @param db better-sqlite3 原始句柄
40
+ * @param opts 同步选项
41
+ * @returns 包含 sync + reconcile + repair 报告的综合结果
42
+ */
43
+ async syncAll(db, opts = {}) {
44
+ // 1. .md → DB 同步
45
+ const syncReport = this.sync(db, opts);
46
+ const report = { ...syncReport };
47
+ // 2. 填充/验证 recipe_source_refs 桥接表
48
+ try {
49
+ const reconciler = new SourceRefReconciler(this.projectRoot, db);
50
+ report.reconcileReport = reconciler.reconcile({ force: opts.force });
51
+ // 3. git rename 修复
52
+ report.repairReport = await reconciler.repairRenames();
53
+ // 4. 写回修复
54
+ if (report.repairReport.renamed > 0) {
55
+ report.applyReport = reconciler.applyRepairs();
56
+ }
57
+ }
58
+ catch (err) {
59
+ this.logger.warn('KnowledgeSyncService: sourceRef reconcile failed (non-blocking)', {
60
+ error: err.message,
61
+ });
62
+ }
63
+ return report;
64
+ }
33
65
  /**
34
66
  * 执行增量同步:.md → DB(knowledge_entries 表)
35
67
  *
@@ -89,7 +121,7 @@ export class KnowledgeSyncService {
89
121
  if (!dryRun) {
90
122
  const existed = this._entryExists(db, parsed.id);
91
123
  const row = this._buildDbRow(parsed, relPath, content);
92
- upsertStmt.run(...Object.values(row));
124
+ upsertStmt?.run(...Object.values(row));
93
125
  if (existed) {
94
126
  report.updated++;
95
127
  }
@@ -67,6 +67,7 @@ export declare function getRecipe(ctx: McpContext, args: BrowseGetArgs): Promise
67
67
  } | undefined;
68
68
  headers: string[] | undefined;
69
69
  reasoning: {
70
+ sources?: unknown[] | undefined;
70
71
  confidence?: number | undefined;
71
72
  whyStandard?: string | undefined;
72
73
  } | undefined;
@@ -74,11 +74,12 @@ function _projectForAgent(json) {
74
74
  ...((json.content.steps?.length ?? 0) > 0 ? { steps: json.content.steps } : {}),
75
75
  }
76
76
  : undefined;
77
- // reasoning 精简:仅保留 whyStandard + confidence
77
+ // reasoning 精简:保留 whyStandard + confidence + sources(可信度证据链)
78
78
  const reasoning = json.reasoning
79
79
  ? {
80
80
  ...(json.reasoning.whyStandard ? { whyStandard: json.reasoning.whyStandard } : {}),
81
81
  ...(json.reasoning.confidence != null ? { confidence: json.reasoning.confidence } : {}),
82
+ ...((json.reasoning.sources?.length ?? 0) > 0 ? { sources: json.reasoning.sources } : {}),
82
83
  }
83
84
  : undefined;
84
85
  // constraints 精简:仅保留 guards 和 sideEffects
@@ -112,6 +112,7 @@ export declare function consolidatedKnowledge(ctx: McpContext, args: Consolidate
112
112
  } | undefined;
113
113
  headers: string[] | undefined;
114
114
  reasoning: {
115
+ sources?: unknown[] | undefined;
115
116
  confidence?: number | undefined;
116
117
  whyStandard?: string | undefined;
117
118
  } | undefined;
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * MCP Handler — autosnippet_panorama
3
3
  *
4
- * 项目全景查询工具,提供 8 个 operation:
5
- * overview — 项目骨架 + 层级 + 模块角色
6
- * module — 单模块详情 + 邻居关系
7
- * gaps — 知识空白区 (有代码无 Recipe)
8
- * health — 全景健康度 (覆盖率 + 耦合度 + 循环)
9
- * governance_cycle — 新陈代谢完整周期 (矛盾+冗余+衰退)
10
- * decay_report — 衰退评估报告
11
- * staging_check — staging 条目检查 + 自动发布
12
- * enhancement_suggestions — 基于使用数据的增强建议
4
+ * Project panorama query tool with 8 operations:
5
+ * overview — project skeleton + layers + module roles
6
+ * module — single module detail + neighbors + recipes + file groups
7
+ * gaps — knowledge gaps (code without Recipes)
8
+ * health — panorama health (coverage + coupling + cycles)
9
+ * governance_cycle — full metabolism cycle (contradiction + redundancy + decay)
10
+ * decay_report — decay assessment report
11
+ * staging_check — staging entry check + auto-publish
12
+ * enhancement_suggestions — usage-data-based enhancement suggestions
13
13
  *
14
- * 全部为只读操作(governance_cycle staging_check 除外,会执行状态转换)。
14
+ * All read-only except governance_cycle and staging_check (which perform state transitions).
15
15
  */
16
16
  import type { McpContext } from './types.js';
17
17
  interface PanoramaArgs {
@@ -19,7 +19,7 @@ interface PanoramaArgs {
19
19
  module?: string;
20
20
  }
21
21
  /**
22
- * autosnippet_panorama — 统合全景查询
22
+ * autosnippet_panorama — unified panorama query
23
23
  */
24
24
  export declare function panoramaHandler(ctx: McpContext, args: PanoramaArgs): Promise<{
25
25
  success: boolean;
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * MCP Handler — autosnippet_panorama
3
3
  *
4
- * 项目全景查询工具,提供 8 个 operation:
5
- * overview — 项目骨架 + 层级 + 模块角色
6
- * module — 单模块详情 + 邻居关系
7
- * gaps — 知识空白区 (有代码无 Recipe)
8
- * health — 全景健康度 (覆盖率 + 耦合度 + 循环)
9
- * governance_cycle — 新陈代谢完整周期 (矛盾+冗余+衰退)
10
- * decay_report — 衰退评估报告
11
- * staging_check — staging 条目检查 + 自动发布
12
- * enhancement_suggestions — 基于使用数据的增强建议
4
+ * Project panorama query tool with 8 operations:
5
+ * overview — project skeleton + layers + module roles
6
+ * module — single module detail + neighbors + recipes + file groups
7
+ * gaps — knowledge gaps (code without Recipes)
8
+ * health — panorama health (coverage + coupling + cycles)
9
+ * governance_cycle — full metabolism cycle (contradiction + redundancy + decay)
10
+ * decay_report — decay assessment report
11
+ * staging_check — staging entry check + auto-publish
12
+ * enhancement_suggestions — usage-data-based enhancement suggestions
13
13
  *
14
- * 全部为只读操作(governance_cycle staging_check 除外,会执行状态转换)。
14
+ * All read-only except governance_cycle and staging_check (which perform state transitions).
15
15
  */
16
16
  import { envelope } from '../envelope.js';
17
17
  /**
18
- * autosnippet_panorama — 统合全景查询
18
+ * autosnippet_panorama — unified panorama query
19
19
  */
20
20
  export async function panoramaHandler(ctx, args) {
21
21
  const op = args.operation || 'overview';
@@ -23,11 +23,11 @@ export async function panoramaHandler(ctx, args) {
23
23
  if (!panoramaService) {
24
24
  return envelope({
25
25
  success: false,
26
- message: '全景服务未初始化',
26
+ message: 'Panorama service not initialized',
27
27
  meta: { tool: 'autosnippet_panorama' },
28
28
  });
29
29
  }
30
- // 自动确保数据就绪(无数据时触发内置扫描)
30
+ // Auto-ensure data is ready (triggers built-in scan when no data exists)
31
31
  await panoramaService.ensureData();
32
32
  switch (op) {
33
33
  case 'overview': {
@@ -43,7 +43,7 @@ export async function panoramaHandler(ctx, args) {
43
43
  if (!moduleName) {
44
44
  return envelope({
45
45
  success: false,
46
- message: 'operation=module 需要提供 module 参数(模块名称)',
46
+ message: 'operation=module requires the "module" parameter (module name)',
47
47
  meta: { tool: 'autosnippet_panorama' },
48
48
  });
49
49
  }
@@ -51,7 +51,7 @@ export async function panoramaHandler(ctx, args) {
51
51
  if (!detail) {
52
52
  return envelope({
53
53
  success: false,
54
- message: `未找到模块: ${moduleName}`,
54
+ message: `Module not found: ${moduleName}`,
55
55
  meta: { tool: 'autosnippet_panorama' },
56
56
  });
57
57
  }
@@ -78,7 +78,7 @@ export async function panoramaHandler(ctx, args) {
78
78
  });
79
79
  }
80
80
  default:
81
- // ── Governance operations (不依赖 panoramaService) ──
81
+ // ── Governance operations (independent of panoramaService) ──
82
82
  return handleGovernanceOps(ctx, op);
83
83
  }
84
84
  }
@@ -90,7 +90,7 @@ async function handleGovernanceOps(ctx, op) {
90
90
  if (!metabolism) {
91
91
  return envelope({
92
92
  success: false,
93
- message: '治理服务未初始化(knowledgeMetabolism 未注册)',
93
+ message: 'Governance service not initialized (knowledgeMetabolism not registered)',
94
94
  meta: { tool: 'autosnippet_panorama' },
95
95
  });
96
96
  }
@@ -106,7 +106,7 @@ async function handleGovernanceOps(ctx, op) {
106
106
  if (!decayDetector) {
107
107
  return envelope({
108
108
  success: false,
109
- message: '衰退检测器未初始化(decayDetector 未注册)',
109
+ message: 'Decay detector not initialized (decayDetector not registered)',
110
110
  meta: { tool: 'autosnippet_panorama' },
111
111
  });
112
112
  }
@@ -122,7 +122,7 @@ async function handleGovernanceOps(ctx, op) {
122
122
  if (!stagingManager) {
123
123
  return envelope({
124
124
  success: false,
125
- message: 'staging 管理器未初始化(stagingManager 未注册)',
125
+ message: 'Staging manager not initialized (stagingManager not registered)',
126
126
  meta: { tool: 'autosnippet_panorama' },
127
127
  });
128
128
  }
@@ -139,7 +139,7 @@ async function handleGovernanceOps(ctx, op) {
139
139
  if (!suggester) {
140
140
  return envelope({
141
141
  success: false,
142
- message: '增强建议器未初始化(enhancementSuggester 未注册)',
142
+ message: 'Enhancement suggester not initialized (enhancementSuggester not registered)',
143
143
  meta: { tool: 'autosnippet_panorama' },
144
144
  });
145
145
  }
@@ -12,7 +12,7 @@ export declare function health(ctx: McpContext): Promise<{
12
12
  issues?: string[] | undefined;
13
13
  session?: {
14
14
  id: string;
15
- intentPhase: "idle" | "active" | "ended";
15
+ intentPhase: "active" | "idle" | "ended";
16
16
  toolCallCount: number;
17
17
  toolsUsed: string[];
18
18
  durationMs: number;
@@ -44,6 +44,10 @@ const _taskRules = {
44
44
  * Unified entry point
45
45
  */
46
46
  export async function taskHandler(ctx, args) {
47
+ // Normalize taskId → id (schema accepts both for convenience)
48
+ if (!args.id && typeof args.taskId === 'string') {
49
+ args.id = args.taskId;
50
+ }
47
51
  let result;
48
52
  switch (args.operation) {
49
53
  case 'prime':
@@ -88,11 +92,20 @@ async function _prime(ctx, args) {
88
92
  if (pipeline && extracted.queries[0]?.trim()) {
89
93
  try {
90
94
  searchResult = await pipeline.search(extracted);
95
+ if (!searchResult) {
96
+ process.stderr.write('[MCP/Task] prime: pipeline.search returned null (all filtered)\n');
97
+ }
91
98
  }
92
- catch {
93
- // search failure is non-fatal
99
+ catch (err) {
100
+ process.stderr.write(`[MCP/Task] prime search error: ${err instanceof Error ? err.stack || err.message : String(err)}\n`);
94
101
  }
95
102
  }
103
+ else if (!pipeline) {
104
+ process.stderr.write('[MCP/Task] prime: pipeline is null, skipping search\n');
105
+ }
106
+ else {
107
+ process.stderr.write(`[MCP/Task] prime: queries empty, skipping search. queries=${JSON.stringify(extracted.queries)}\n`);
108
+ }
96
109
  // ─── Lifecycle: initialize IntentState ───
97
110
  const freshIntent = createIdleIntent();
98
111
  freshIntent.phase = 'active';
@@ -124,7 +137,8 @@ async function _prime(ctx, args) {
124
137
  lines.push(`📋 Found ${relatedCount} recipe(s), ${ruleCount} guard rule(s).`);
125
138
  for (const r of searchResult.relatedKnowledge) {
126
139
  const hint = r.actionHint ? ` — ${r.actionHint}` : '';
127
- lines.push(` • ${r.trigger || r.title}${hint}`);
140
+ const refs = r.sourceRefs?.length ? `\n 📍 ${r.sourceRefs.join(', ')}` : '';
141
+ lines.push(` • ${r.trigger || r.title}${hint}${refs}`);
128
142
  }
129
143
  for (const r of searchResult.guardRules) {
130
144
  lines.push(` • [rule] ${r.trigger || r.title}`);
@@ -174,14 +188,16 @@ async function _create(ctx, args) {
174
188
  }
175
189
  // ═══ close ══════════════════════════════════════════════
176
190
  async function _close(ctx, args) {
177
- if (!args.id) {
191
+ const intent = ctx.session?.intent;
192
+ // Resolve id: explicit arg > session intent > fail
193
+ const id = args.id || (intent?.taskId ?? '');
194
+ if (!id) {
178
195
  return envelope({
179
196
  success: false,
180
- message: 'id is required',
197
+ message: 'id is required (pass id or ensure a task was created in this session)',
181
198
  meta: { tool: 'autosnippet_task' },
182
199
  });
183
200
  }
184
- const intent = ctx.session?.intent;
185
201
  const reason = args.reason || 'Completed';
186
202
  // Persist intent chain via SignalBus
187
203
  if (intent && intent.phase === 'active') {
@@ -191,13 +207,13 @@ async function _close(ctx, args) {
191
207
  if (ctx.session) {
192
208
  ctx.session.intent = createIdleIntent();
193
209
  }
194
- const lines = [`✅ Closed: ${args.id} — ${reason}`];
210
+ const lines = [`✅ Closed: ${id} — ${reason}`];
195
211
  lines.push('');
196
212
  lines.push('⚠️ REQUIRED: You MUST call autosnippet_guard (no args) NOW to review changed files for compliance violations.');
197
213
  return envelope({
198
214
  success: true,
199
215
  data: {
200
- closed: { id: args.id, reason, closedAt: Date.now() },
216
+ closed: { id, reason, closedAt: Date.now() },
201
217
  nextAction: {
202
218
  tool: 'autosnippet_guard',
203
219
  args: {},
@@ -211,14 +227,16 @@ async function _close(ctx, args) {
211
227
  }
212
228
  // ═══ fail ═══════════════════════════════════════════════
213
229
  async function _fail(ctx, args) {
214
- if (!args.id) {
230
+ const intent = ctx.session?.intent;
231
+ // Resolve id: explicit arg > session intent > fail
232
+ const id = args.id || (intent?.taskId ?? '');
233
+ if (!id) {
215
234
  return envelope({
216
235
  success: false,
217
- message: 'id is required',
236
+ message: 'id is required (pass id or ensure a task was created in this session)',
218
237
  meta: { tool: 'autosnippet_task' },
219
238
  });
220
239
  }
221
- const intent = ctx.session?.intent;
222
240
  const reason = args.reason || 'Agent execution failed';
223
241
  // Persist intent chain via SignalBus
224
242
  if (intent && intent.phase === 'active') {
@@ -231,9 +249,9 @@ async function _fail(ctx, args) {
231
249
  return envelope({
232
250
  success: true,
233
251
  data: {
234
- failed: { id: args.id, reason, failedAt: Date.now() },
252
+ failed: { id, reason, failedAt: Date.now() },
235
253
  },
236
- message: `❌ Failed: ${args.id} — ${reason}`,
254
+ message: `❌ Failed: ${id} — ${reason}`,
237
255
  meta: { tool: 'autosnippet_task' },
238
256
  });
239
257
  }
@@ -322,9 +340,14 @@ function _computeDriftScore(intent) {
322
340
  }
323
341
  function _getPipeline(container) {
324
342
  try {
325
- return container.get('primeSearchPipeline');
343
+ const p = container.get('primeSearchPipeline');
344
+ if (!p) {
345
+ process.stderr.write('[MCP/Task] _getPipeline: container returned null/undefined\n');
346
+ }
347
+ return p;
326
348
  }
327
- catch {
349
+ catch (err) {
350
+ process.stderr.write(`[MCP/Task] _getPipeline failed: ${err instanceof Error ? err.message : String(err)}\n`);
328
351
  return null;
329
352
  }
330
353
  }
@@ -1,19 +1,19 @@
1
1
  /**
2
- * MCP 工具定义 — V3 整合版 (14 agent + 2 admin = 16 工具)
2
+ * MCP Tool Definitions — V3 Consolidated (14 agent + 2 admin = 16 tools)
3
3
  *
4
- * 每个工具声明包含 nametieragent/admin)、description inputSchema
5
- * description Agent 选择工具的关键使用 bullet list 列出所有 operation 及其用途。
6
- * inputSchema Zod Schema 自动生成(zodToMcpSchema),参数的 .describe() 会转为 JSON Schema description
4
+ * Each tool declaration contains name, tier (agent/admin), description, and inputSchema.
5
+ * description is the key for Agent tool selection use bullet list to enumerate all operations and their purposes.
6
+ * inputSchema is auto-generated from Zod Schema (zodToMcpSchema); parameter .describe() translates to JSON Schema description.
7
7
  *
8
- * Agent 工具 (14):
9
- * 1-7: 查询工具 (health/search/knowledge/structure/graph/call_context/guard)
10
- * 8: 写入工具 (submit_knowledge — unified pipeline,单条/批量统一处理)
11
- * 9: Skill 管理 (skill)
12
- * 10-12: 冷启动 (bootstrap/dimension_complete/wiki)
13
- * 13: 项目全景 (panorama)
14
- * 14: 任务管理 (task — 5 ops: prime/create/close/fail/record_decision)
8
+ * Agent tools (14):
9
+ * 1-7: Query tools (health/search/knowledge/structure/graph/call_context/guard)
10
+ * 8: Write tool (submit_knowledge — unified pipeline, single/batch)
11
+ * 9: Skill management (skill)
12
+ * 10-12: Cold-start (bootstrap/dimension_complete/wiki)
13
+ * 13: Project panorama (panorama)
14
+ * 14: Task management (task — 5 ops: prime/create/close/fail/record_decision)
15
15
  *
16
- * Admin 工具 (2):
16
+ * Admin tools (2):
17
17
  * 15-16: enrich_candidates/knowledge_lifecycle
18
18
  */
19
19
  export declare const TIER_ORDER: {