autosnippet 3.2.8 → 3.2.9
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/bin/cli.js +6 -5
- package/dashboard/dist/assets/index-BTAsOZv2.js +128 -0
- package/dashboard/dist/assets/index-C_72Ct98.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/lib/cli/AiScanService.js +23 -26
- package/lib/cli/SetupService.js +1 -1
- package/lib/core/AstAnalyzer.js +1 -1
- package/lib/core/discovery/index.js +2 -2
- package/lib/external/ai/AiProvider.js +66 -172
- package/lib/external/ai/providers/GoogleGeminiProvider.js +23 -1
- package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +3 -3
- package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +8 -8
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +287 -204
- package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +7 -6
- package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
- package/lib/external/mcp/handlers/bootstrap-internal.js +2 -2
- package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
- package/lib/http/HttpServer.js +1 -1
- package/lib/http/middleware/requestLogger.js +1 -0
- package/lib/http/routes/ai.js +240 -35
- package/lib/http/routes/candidates.js +2 -3
- package/lib/http/routes/extract.js +13 -11
- package/lib/http/routes/modules.js +2 -2
- package/lib/http/routes/recipes.js +9 -5
- package/lib/http/routes/remote.js +134 -255
- package/lib/http/routes/violations.js +0 -54
- package/lib/http/utils/sse-sessions.js +1 -1
- package/lib/infrastructure/logging/Logger.js +5 -4
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +3 -2
- package/lib/injection/ServiceContainer.js +64 -17
- package/lib/platform/ScreenCaptureService.js +177 -0
- package/lib/platform/ios/routes/spm.js +2 -2
- package/lib/service/agent/AgentEventBus.js +207 -0
- package/lib/service/agent/AgentFactory.js +490 -0
- package/lib/service/agent/AgentMessage.js +240 -0
- package/lib/service/agent/AgentRouter.js +228 -0
- package/lib/service/agent/AgentRuntime.js +1016 -0
- package/lib/service/agent/AgentState.js +217 -0
- package/lib/service/agent/IntentClassifier.js +331 -0
- package/lib/service/agent/LarkTransport.js +389 -0
- package/lib/service/agent/capabilities.js +408 -0
- package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
- package/lib/service/{chat → agent/context}/ExplorationTracker.js +25 -14
- package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +1 -1
- package/lib/service/agent/core/LoopContext.js +170 -0
- package/lib/service/agent/core/MessageAdapter.js +223 -0
- package/lib/service/agent/core/ToolExecutionPipeline.js +376 -0
- package/lib/service/{chat → agent/domain}/ChatAgentTasks.js +19 -98
- package/lib/service/{chat → agent/domain}/EpisodicConsolidator.js +7 -7
- package/lib/service/{chat → agent/domain}/EvidenceCollector.js +4 -2
- package/lib/service/{chat/AnalystAgent.js → agent/domain/insight-analyst.js} +37 -172
- package/lib/service/{chat/HandoffProtocol.js → agent/domain/insight-gate.js} +85 -135
- package/lib/service/agent/domain/insight-producer.js +267 -0
- package/lib/service/agent/domain/scan-prompts.js +105 -0
- package/lib/service/agent/forced-summary.js +266 -0
- package/lib/service/agent/index.js +91 -0
- package/lib/service/{chat → agent}/memory/MemoryCoordinator.js +7 -7
- package/lib/service/{chat/ProjectSemanticMemory.js → agent/memory/PersistentMemory.js} +359 -89
- package/lib/service/{chat → agent}/memory/SessionStore.js +1 -1
- package/lib/service/{chat → agent}/memory/index.js +1 -1
- package/lib/service/agent/policies.js +442 -0
- package/lib/service/agent/presets.js +303 -0
- package/lib/service/agent/strategies.js +717 -0
- package/lib/service/{chat → agent/tools}/ToolRegistry.js +3 -3
- package/lib/service/agent/tools/ai-analysis.js +75 -0
- package/lib/service/{chat → agent}/tools/composite.js +2 -1
- package/lib/service/{chat → agent}/tools/guard.js +1 -121
- package/lib/service/{chat → agent}/tools/index.js +27 -21
- package/lib/service/{chat → agent}/tools/infrastructure.js +1 -1
- package/lib/service/agent/tools/knowledge-graph.js +112 -0
- package/lib/service/agent/tools/scan-recipe.js +189 -0
- package/lib/service/agent/tools/system-interaction.js +476 -0
- package/lib/service/automation/DirectiveDetector.js +0 -1
- package/lib/service/automation/FileWatcher.js +0 -8
- package/lib/service/automation/handlers/CreateHandler.js +7 -3
- package/lib/service/automation/handlers/DraftHandler.js +7 -6
- package/lib/service/module/ModuleService.js +40 -73
- package/lib/service/skills/SignalCollector.js +26 -19
- package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
- package/lib/shared/FieldSpec.js +1 -1
- package/lib/shared/StyleGuide.js +1 -1
- package/package.json +4 -1
- package/resources/native-ui/screenshot.swift +228 -0
- package/dashboard/dist/assets/index-D5jiDBQG.css +0 -1
- package/dashboard/dist/assets/index-e5OKj-Ni.js +0 -128
- package/lib/core/discovery/SpmDiscoverer.js +0 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -750
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +0 -277
- package/lib/http/routes/spm.js +0 -5
- package/lib/infrastructure/external/XcodeAutomation.js +0 -15
- package/lib/service/chat/ChatAgent.js +0 -1602
- package/lib/service/chat/Memory.js +0 -161
- package/lib/service/chat/ProducerAgent.js +0 -431
- package/lib/service/chat/ReasoningTrace.js +0 -523
- package/lib/service/chat/TaskPipeline.js +0 -357
- package/lib/service/chat/WorkingMemory.js +0 -359
- package/lib/service/chat/memory/PersistentMemory.js +0 -450
- package/lib/service/chat/tools/ai-analysis.js +0 -267
- package/lib/service/chat/tools/knowledge-graph.js +0 -234
- package/lib/service/chat/tools.js +0 -18
- package/lib/service/snippet/PlaceholderConverter.js +0 -5
- package/lib/service/snippet/codecs/XcodeCodec.js +0 -5
- /package/lib/service/{chat → agent}/ConversationStore.js +0 -0
- /package/lib/service/{chat → agent}/memory/ActiveContext.js +0 -0
- /package/lib/service/{chat → agent}/tools/_shared.js +0 -0
- /package/lib/service/{chat → agent}/tools/ast-graph.js +0 -0
- /package/lib/service/{chat → agent}/tools/lifecycle.js +0 -0
- /package/lib/service/{chat → agent}/tools/project-access.js +0 -0
- /package/lib/service/{chat → agent}/tools/query.js +0 -0
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* ⚠️ 本文件是「内部 Agent」专用 — 由 bootstrap.js Phase 5 调用。
|
|
5
5
|
* 外部 Agent (Cursor/Copilot) 不经过此管线,它们自行分析代码。
|
|
6
6
|
*
|
|
7
|
-
* 核心架构:
|
|
7
|
+
* 核心架构: PipelineStrategy 驱动 (Analyze → QualityGate → Produce → RejectionGate)
|
|
8
8
|
*
|
|
9
|
-
* 1.
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
9
|
+
* 1. Analyze 阶段: 自由探索代码 (AST 工具 + 文件搜索)
|
|
10
|
+
* 2. QualityGate: 质量门控 (insightGateEvaluator)
|
|
11
|
+
* 3. Produce 阶段: 格式化输出 (submit_knowledge)
|
|
12
12
|
* 4. TierScheduler 分层并行执行
|
|
13
13
|
*
|
|
14
14
|
* @module pipeline/orchestrator
|
|
@@ -17,12 +17,15 @@
|
|
|
17
17
|
import fs from 'node:fs/promises';
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
import Logger from '../../../../../infrastructure/logging/Logger.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
20
|
+
import { EpisodicConsolidator } from '../../../../../service/agent/domain/EpisodicConsolidator.js';
|
|
21
|
+
import { PersistentMemory } from '../../../../../service/agent/memory/PersistentMemory.js';
|
|
22
|
+
import { MemoryCoordinator } from '../../../../../service/agent/memory/MemoryCoordinator.js';
|
|
23
|
+
import { SessionStore } from '../../../../../service/agent/memory/SessionStore.js';
|
|
24
|
+
import { AgentMessage } from '../../../../../service/agent/AgentMessage.js';
|
|
25
|
+
import { BudgetPolicy } from '../../../../../service/agent/policies.js';
|
|
26
|
+
import { PRESETS } from '../../../../../service/agent/presets.js';
|
|
27
|
+
import { ContextWindow } from '../../../../../service/agent/context/ContextWindow.js';
|
|
28
|
+
import { ExplorationTracker } from '../../../../../service/agent/context/ExplorationTracker.js';
|
|
26
29
|
import { clearCheckpoints, loadCheckpoints, saveDimensionCheckpoint } from './checkpoint.js';
|
|
27
30
|
import { buildTierReflection, DIMENSION_CONFIGS_V3, getFullDimensionConfig } from './dimension-configs.js';
|
|
28
31
|
import { getDimensionFocusKeywords } from '../shared/dimension-sop.js';
|
|
@@ -61,30 +64,29 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
61
64
|
const isIncremental = incrementalPlan?.canIncremental && incrementalPlan?.mode === 'incremental';
|
|
62
65
|
const emitter = new BootstrapEventEmitter(ctx.container);
|
|
63
66
|
logger.info(
|
|
64
|
-
`[
|
|
67
|
+
`[Insight-v3] ═══ fillDimensionsV3 entered — ${isIncremental ? 'INCREMENTAL' : 'FULL'} pipeline`
|
|
65
68
|
);
|
|
66
69
|
|
|
67
70
|
let allFiles = fillContext.allFiles;
|
|
68
71
|
fillContext.allFiles = null;
|
|
69
72
|
|
|
70
73
|
// ═══════════════════════════════════════════════════════════
|
|
71
|
-
// Step 0: AI 可用性检查
|
|
74
|
+
// Step 0: AI 可用性检查 (v7.2: 使用 AgentFactory)
|
|
72
75
|
// ═══════════════════════════════════════════════════════════
|
|
73
|
-
let
|
|
76
|
+
let agentFactory = null;
|
|
74
77
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
chatAgent.resetGlobalSubmittedTitles();
|
|
78
|
+
agentFactory = ctx.container.get('agentFactory');
|
|
79
|
+
// 检查 AI Provider 是否可用
|
|
80
|
+
const aiProvider = ctx.container.singletons?.aiProvider;
|
|
81
|
+
if (!aiProvider || aiProvider.name === 'mock') {
|
|
82
|
+
agentFactory = null;
|
|
81
83
|
}
|
|
82
84
|
} catch {
|
|
83
85
|
/* not available */
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
if (!
|
|
87
|
-
logger.info('[
|
|
88
|
+
if (!agentFactory) {
|
|
89
|
+
logger.info('[Insight-v3] AI not available — entering rule-based fallback');
|
|
88
90
|
emitter.emitProgress('bootstrap:ai-unavailable', {
|
|
89
91
|
message: 'AI 不可用,将使用规则化降级提取基础知识。请配置 AI Provider 以获取完整分析。',
|
|
90
92
|
});
|
|
@@ -247,21 +249,20 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
247
249
|
if (projectGraph) {
|
|
248
250
|
const overview = projectGraph.getOverview();
|
|
249
251
|
logger.info(
|
|
250
|
-
`[
|
|
252
|
+
`[Insight-v3] ProjectGraph: ${overview.totalClasses} classes, ${overview.totalProtocols} protocols (${overview.buildTimeMs}ms)`
|
|
251
253
|
);
|
|
252
254
|
}
|
|
253
255
|
} catch (e) {
|
|
254
|
-
logger.warn(`[
|
|
256
|
+
logger.warn(`[Insight-v3] ProjectGraph build failed: ${e.message}`);
|
|
255
257
|
}
|
|
256
258
|
|
|
257
259
|
// ═══════════════════════════════════════════════════════════
|
|
258
260
|
// Step 1: 构建 Agents + 上下文
|
|
259
261
|
// ═══════════════════════════════════════════════════════════
|
|
260
|
-
|
|
261
|
-
const producerAgent = new ProducerAgent(chatAgent);
|
|
262
|
+
logger.info('[Insight-v7] Using unified AgentRuntime pipeline (no legacy Analyst/Producer wrappers)');
|
|
262
263
|
|
|
263
|
-
//
|
|
264
|
-
|
|
264
|
+
// 注入文件缓存到容器 (v7.2: 通过容器传递)
|
|
265
|
+
ctx.container.singletons._fileCache = allFiles;
|
|
265
266
|
|
|
266
267
|
// 项目信息
|
|
267
268
|
const projectInfo = {
|
|
@@ -289,7 +290,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
289
290
|
sessionStore = incrementalPlan.restoredEpisodic;
|
|
290
291
|
const restoredDims = sessionStore.getCompletedDimensions();
|
|
291
292
|
logger.info(
|
|
292
|
-
`[
|
|
293
|
+
`[Insight-v3] Restored SessionStore: ${restoredDims.length} dims [${restoredDims.join(', ')}]`
|
|
293
294
|
);
|
|
294
295
|
|
|
295
296
|
// 同步恢复 DimensionContext 的 digests (兼容)
|
|
@@ -308,23 +309,23 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
308
309
|
});
|
|
309
310
|
}
|
|
310
311
|
|
|
311
|
-
// v4.1:
|
|
312
|
-
// 加载历史 bootstrap 记忆 → 注入
|
|
312
|
+
// v4.1: PersistentMemory — 项目级永久语义记忆 (Tier 3)
|
|
313
|
+
// 加载历史 bootstrap 记忆 → 注入 Analyst promptBuilder
|
|
313
314
|
let semanticMemory = null;
|
|
314
315
|
try {
|
|
315
316
|
const db = ctx.container.get('database');
|
|
316
317
|
if (db) {
|
|
317
|
-
semanticMemory = new
|
|
318
|
+
semanticMemory = new PersistentMemory(db, { logger });
|
|
318
319
|
const smStats = semanticMemory.getStats();
|
|
319
320
|
if (smStats.total > 0) {
|
|
320
321
|
logger.info(
|
|
321
|
-
`[
|
|
322
|
+
`[Insight-v3] Loaded ${smStats.total} semantic memories from previous bootstrap ` +
|
|
322
323
|
`(fact: ${smStats.byType.fact || 0}, insight: ${smStats.byType.insight || 0}, preference: ${smStats.byType.preference || 0})`
|
|
323
324
|
);
|
|
324
325
|
}
|
|
325
326
|
}
|
|
326
327
|
} catch (smErr) {
|
|
327
|
-
logger.warn(`[
|
|
328
|
+
logger.warn(`[Insight-v3] SemanticMemory init failed (non-blocking): ${smErr.message}`);
|
|
328
329
|
}
|
|
329
330
|
|
|
330
331
|
// Phase E: CodeEntityGraph — 代码实体关系图谱 (供 Analyst prompt 注入)
|
|
@@ -337,12 +338,12 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
337
338
|
const topo = codeEntityGraphInst.getTopology();
|
|
338
339
|
if (topo.totalEntities > 0) {
|
|
339
340
|
logger.info(
|
|
340
|
-
`[
|
|
341
|
+
`[Insight-v3] CodeEntityGraph: ${topo.totalEntities} entities, ${topo.totalEdges} edges`
|
|
341
342
|
);
|
|
342
343
|
}
|
|
343
344
|
}
|
|
344
345
|
} catch (cegErr) {
|
|
345
|
-
logger.warn(`[
|
|
346
|
+
logger.warn(`[Insight-v3] CodeEntityGraph init failed (non-blocking): ${cegErr.message}`);
|
|
346
347
|
}
|
|
347
348
|
|
|
348
349
|
// v5.0: MemoryCoordinator — 统一记忆协调器 (会话级)
|
|
@@ -378,14 +379,14 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
378
379
|
}
|
|
379
380
|
if (incrementalSkippedDims.length > 0) {
|
|
380
381
|
logger.info(
|
|
381
|
-
`[
|
|
382
|
+
`[Insight-v3] ⏩ Incremental skip: [${incrementalSkippedDims.join(', ')}] ` +
|
|
382
383
|
`(using historical results)`
|
|
383
384
|
);
|
|
384
385
|
}
|
|
385
386
|
}
|
|
386
387
|
|
|
387
388
|
logger.info(
|
|
388
|
-
`[
|
|
389
|
+
`[Insight-v3] Active dimensions: [${activeDimIds.join(', ')}], concurrency=${enableParallel ? concurrency : 1}${isIncremental ? `, incremental skip: [${incrementalSkippedDims.join(', ')}]` : ''}`
|
|
389
390
|
);
|
|
390
391
|
|
|
391
392
|
// ── P3: 断点续传 — 加载有效 checkpoints ──
|
|
@@ -404,7 +405,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
404
405
|
...checkpoint,
|
|
405
406
|
});
|
|
406
407
|
skippedDims.push(dimId);
|
|
407
|
-
logger.info(`[
|
|
408
|
+
logger.info(`[Insight-v3] ⏩ 跳过已完成维度 (checkpoint): "${dimId}"`);
|
|
408
409
|
}
|
|
409
410
|
}
|
|
410
411
|
|
|
@@ -412,6 +413,10 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
412
413
|
const dimensionCandidates = {};
|
|
413
414
|
const dimensionStats = {}; // P4.2: 维度级统计
|
|
414
415
|
|
|
416
|
+
// ── 跨维度去重集合 (实例级持久化,等效旧 ChatAgent.#globalSubmittedTitles/Patterns) ──
|
|
417
|
+
const globalSubmittedTitles = new Set();
|
|
418
|
+
const globalSubmittedPatterns = new Set();
|
|
419
|
+
|
|
415
420
|
/**
|
|
416
421
|
* 执行单个维度: Analyst → Gate → Producer
|
|
417
422
|
*/
|
|
@@ -432,7 +437,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
432
437
|
restoredFromIncremental: true,
|
|
433
438
|
};
|
|
434
439
|
dimensionStats[dimId] = dimResult;
|
|
435
|
-
logger.info(`[
|
|
440
|
+
logger.info(`[Insight-v3] ⏩ "${dimId}" — incremental skip (historical result)`);
|
|
436
441
|
return dimResult;
|
|
437
442
|
}
|
|
438
443
|
|
|
@@ -472,7 +477,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
472
477
|
candidatesSummary: [],
|
|
473
478
|
});
|
|
474
479
|
logger.info(
|
|
475
|
-
`[
|
|
480
|
+
`[Insight-v3] ✅ Checkpoint "${dimId}": analysisText restored (${cp.analysisText.length} chars) — Skill generation enabled`
|
|
476
481
|
);
|
|
477
482
|
}
|
|
478
483
|
|
|
@@ -521,81 +526,226 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
521
526
|
|
|
522
527
|
// Session 有效性检查
|
|
523
528
|
if (taskManager && !taskManager.isSessionValid(sessionId)) {
|
|
524
|
-
logger.warn(`[
|
|
529
|
+
logger.warn(`[Insight-v3] Session superseded — skipping "${dimId}"`);
|
|
525
530
|
return { candidateCount: 0, error: 'session-superseded' };
|
|
526
531
|
}
|
|
527
532
|
|
|
528
533
|
emitter.emitDimensionStart(dimId);
|
|
529
|
-
logger.info(`[
|
|
534
|
+
logger.info(`[Insight-v3] ── Dimension "${dimId}" (${dimConfig.label}) ──`);
|
|
530
535
|
|
|
531
536
|
const dimStartTime = Date.now();
|
|
532
537
|
|
|
533
538
|
try {
|
|
534
|
-
//
|
|
539
|
+
// ═══ v3.0: 增强 PipelineStrategy 驱动 ═══
|
|
535
540
|
const analystScopeId = `${dimId}:analyst`;
|
|
536
541
|
memoryCoordinator.createDimensionScope(analystScopeId);
|
|
537
542
|
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
543
|
+
const v3OutputType = DIMENSION_CONFIGS_V3[dimId]?.outputType;
|
|
544
|
+
const needsCandidates = v3OutputType
|
|
545
|
+
? v3OutputType !== 'skill'
|
|
546
|
+
: !dimConfig.skillWorthy || dimConfig.dualOutput;
|
|
547
|
+
|
|
548
|
+
// ── 获取 Preset 的标准 stages 配置作为基础 ──
|
|
549
|
+
const presetStages = PRESETS.insight.strategy.stages;
|
|
550
|
+
|
|
551
|
+
// ── 构建 per-dimension 的 stages ──
|
|
552
|
+
// NOTE: onToolCall 不再注入 ac.recordToolCall — ToolExecutionPipeline 的
|
|
553
|
+
// traceRecord 中间件已通过 loopCtx.trace 统一记录,避免同一 AC 上双重记录。
|
|
554
|
+
const analyzeStage = {
|
|
555
|
+
...presetStages[0],
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
let stages;
|
|
559
|
+
if (needsCandidates) {
|
|
560
|
+
// 候选维度: Analyze→QualityGate→Produce→RejectionGate
|
|
561
|
+
const produceStage = {
|
|
562
|
+
...presetStages[2],
|
|
563
|
+
promptBuilder: (ctx) => {
|
|
564
|
+
memoryCoordinator.allocateBudget('producer');
|
|
565
|
+
return presetStages[2].promptBuilder(ctx);
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
stages = [
|
|
569
|
+
analyzeStage,
|
|
570
|
+
presetStages[1], // quality_gate
|
|
571
|
+
produceStage,
|
|
572
|
+
presetStages[3], // rejection_gate
|
|
573
|
+
];
|
|
574
|
+
} else {
|
|
575
|
+
// Skill-only 维度: 仅 Analyze
|
|
576
|
+
stages = [analyzeStage];
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ── 创建 Runtime (使用增强 PipelineStrategy) ──
|
|
580
|
+
const runtime = agentFactory.createRuntime('insight', {
|
|
581
|
+
lang: primaryLang || projectInfo.lang || null,
|
|
582
|
+
strategy: {
|
|
583
|
+
type: 'pipeline',
|
|
584
|
+
maxRetries: 1,
|
|
585
|
+
stages,
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
runtime.setFileCache(allFiles);
|
|
589
|
+
|
|
590
|
+
// ── 构建消息 + strategyContext ──
|
|
591
|
+
const message = AgentMessage.internal(`Bootstrap dimension: ${dimConfig.label}`, {
|
|
592
|
+
sessionId,
|
|
593
|
+
dimension: dimId,
|
|
594
|
+
phase: 'bootstrap',
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
const strategyContext = {
|
|
598
|
+
dimConfig,
|
|
599
|
+
projectInfo,
|
|
600
|
+
dimContext,
|
|
601
|
+
sessionStore,
|
|
602
|
+
semanticMemory,
|
|
603
|
+
codeEntityGraph: codeEntityGraphInst,
|
|
604
|
+
projectGraph: null, // ProjectGraph 在 orchestrator 级别可用时注入
|
|
605
|
+
dimId,
|
|
606
|
+
activeContext: memoryCoordinator.getActiveContext(analystScopeId),
|
|
607
|
+
outputType: dimConfig.outputType || 'analysis',
|
|
608
|
+
// ── 引擎增强参数 (PipelineStrategy → reactLoop 透传) ──
|
|
609
|
+
contextWindow: agentFactory.createContextWindow({ isSystem: true }),
|
|
610
|
+
tracker: ExplorationTracker.resolve(
|
|
611
|
+
{ source: 'system', dimensionMeta: dimConfig },
|
|
612
|
+
{ maxIterations: PRESETS.insight.strategy.stages[0].budget?.maxIterations || 24 },
|
|
613
|
+
),
|
|
614
|
+
trace: memoryCoordinator.getActiveContext(analystScopeId),
|
|
615
|
+
memoryCoordinator,
|
|
616
|
+
sharedState: {
|
|
617
|
+
submittedTitles: globalSubmittedTitles,
|
|
618
|
+
submittedPatterns: globalSubmittedPatterns,
|
|
619
|
+
_dimensionMeta: {
|
|
620
|
+
id: dimId,
|
|
621
|
+
outputType: dimConfig.outputType || 'candidate',
|
|
622
|
+
allowedKnowledgeTypes: dimConfig.allowedKnowledgeTypes || [],
|
|
623
|
+
},
|
|
624
|
+
_projectLanguage: primaryLang || projectInfo.lang || null,
|
|
625
|
+
_dimensionScopeId: analystScopeId,
|
|
626
|
+
},
|
|
627
|
+
source: 'system',
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// ── 执行 ──
|
|
631
|
+
// 外层超时 = 安全网 (各阶段已有独立超时: Analyst 300s + Producer 180s + 硬缓冲 60s)
|
|
632
|
+
const outerTimeoutMs = 600_000;
|
|
633
|
+
const runResult = await Promise.race([
|
|
634
|
+
runtime.execute(message, { strategyContext }),
|
|
550
635
|
new Promise((_, reject) =>
|
|
551
|
-
setTimeout(() => reject(new Error(`
|
|
636
|
+
setTimeout(() => reject(new Error(`Bootstrap runtime timeout for "${dimId}"`)), outerTimeoutMs),
|
|
552
637
|
),
|
|
553
638
|
]);
|
|
554
639
|
|
|
555
|
-
//
|
|
640
|
+
// ── 提取结果 ──
|
|
641
|
+
const analyzeResult = runResult?.phases?.analyze;
|
|
642
|
+
const gateResult = runResult?.phases?.quality_gate;
|
|
643
|
+
const produceResult = runResult?.phases?.produce;
|
|
644
|
+
const analysisText = (analyzeResult?.reply || runResult?.reply || '').trim();
|
|
645
|
+
const artifact = gateResult?.artifact || {
|
|
646
|
+
analysisText,
|
|
647
|
+
referencedFiles: [],
|
|
648
|
+
findings: [],
|
|
649
|
+
metadata: { toolCallCount: 0 },
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
const runtimeToolCalls = runResult?.toolCalls || [];
|
|
653
|
+
const combinedTokenUsage = runResult?.tokenUsage || { input: 0, output: 0 };
|
|
654
|
+
|
|
655
|
+
// 引用文件: 优先从 artifact 取, 回退从 toolCalls 提取
|
|
656
|
+
const referencedFiles = artifact.referencedFiles?.length > 0
|
|
657
|
+
? artifact.referencedFiles
|
|
658
|
+
: [...new Set(runtimeToolCalls.flatMap((tc) => {
|
|
659
|
+
const a = tc?.args || tc?.params || {};
|
|
660
|
+
const files = [];
|
|
661
|
+
if (typeof a.filePath === 'string' && a.filePath.trim()) files.push(a.filePath.trim());
|
|
662
|
+
if (Array.isArray(a.filePaths)) {
|
|
663
|
+
for (const f of a.filePaths) {
|
|
664
|
+
if (typeof f === 'string' && f.trim()) files.push(f.trim());
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return files;
|
|
668
|
+
}))];
|
|
669
|
+
|
|
670
|
+
const analysisReport = {
|
|
671
|
+
dimensionId: dimId,
|
|
672
|
+
analysisText: artifact.analysisText || analysisText,
|
|
673
|
+
findings: artifact.findings || [],
|
|
674
|
+
referencedFiles,
|
|
675
|
+
evidenceMap: artifact.evidenceMap || null,
|
|
676
|
+
negativeSignals: artifact.negativeSignals || [],
|
|
677
|
+
metadata: {
|
|
678
|
+
toolCallCount: runtimeToolCalls.length,
|
|
679
|
+
tokenUsage: combinedTokenUsage,
|
|
680
|
+
artifactVersion: artifact.metadata?.artifactVersion || 1,
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
// ── Producer 结果统计 ──
|
|
685
|
+
const submitCalls = runtimeToolCalls.filter(tc => {
|
|
686
|
+
const tool = tc?.tool || tc?.name;
|
|
687
|
+
return tool === 'submit_knowledge' || tool === 'submit_with_check';
|
|
688
|
+
});
|
|
689
|
+
const successCount = submitCalls.filter(tc => {
|
|
690
|
+
const res = tc?.result;
|
|
691
|
+
if (!res) return true;
|
|
692
|
+
if (typeof res === 'string') return !res.includes('rejected') && !res.includes('error');
|
|
693
|
+
return res.status !== 'rejected' && res.status !== 'error';
|
|
694
|
+
}).length;
|
|
695
|
+
const rejectedCount = submitCalls.length - successCount;
|
|
696
|
+
|
|
697
|
+
const producerResult = {
|
|
698
|
+
candidateCount: needsCandidates ? successCount : 0,
|
|
699
|
+
rejectedCount: needsCandidates ? rejectedCount : 0,
|
|
700
|
+
toolCalls: runtimeToolCalls,
|
|
701
|
+
reply: produceResult?.reply || analysisText,
|
|
702
|
+
tokenUsage: combinedTokenUsage,
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
candidateResults.created += producerResult.candidateCount;
|
|
706
|
+
dimensionCandidates[dimId] = { analysisReport, producerResult };
|
|
707
|
+
|
|
708
|
+
// ── Memory Update ──
|
|
556
709
|
const ac = memoryCoordinator.getActiveContext(analystScopeId);
|
|
557
710
|
const distilled = ac ? ac.distill() : { keyFindings: [], totalObservations: 0, toolCallSummary: [] };
|
|
558
711
|
sessionStore.storeDimensionReport(dimId, {
|
|
559
712
|
analysisText: analysisReport.analysisText,
|
|
560
|
-
findings: analysisReport.findings
|
|
713
|
+
findings: analysisReport.findings.length > 0 ? analysisReport.findings : distilled.keyFindings,
|
|
561
714
|
referencedFiles: analysisReport.referencedFiles || [],
|
|
562
715
|
candidatesSummary: [],
|
|
563
716
|
workingMemoryDistilled: distilled,
|
|
564
717
|
});
|
|
565
718
|
|
|
566
|
-
// v4.2: 记录 Artifact 增强数据 (如果使用了 v2 pipeline)
|
|
567
|
-
const isArtifact = !!analysisReport.evidenceMap;
|
|
568
|
-
const evidenceMapSize = isArtifact ? analysisReport.evidenceMap.size : 0;
|
|
569
|
-
const negativeSignalCount = isArtifact ? analysisReport.negativeSignals?.length || 0 : 0;
|
|
570
|
-
const qualityScore = isArtifact ? analysisReport.qualityReport?.totalScore : null;
|
|
571
|
-
|
|
572
719
|
logger.info(
|
|
573
|
-
`[
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
`${distilled.totalObservations} observations` +
|
|
577
|
-
(isArtifact
|
|
578
|
-
? `, evidence: ${evidenceMapSize} files, negative: ${negativeSignalCount}, quality: ${qualityScore}`
|
|
579
|
-
: '') +
|
|
580
|
-
` (${Date.now() - dimStartTime}ms)`
|
|
720
|
+
`[Insight-v3] Dimension "${dimId}": analysis=${analysisReport.analysisText.length} chars, ` +
|
|
721
|
+
`files=${analysisReport.referencedFiles.length}, findings=${(analysisReport.findings || distilled.keyFindings).length}, ` +
|
|
722
|
+
`toolCalls=${runtimeToolCalls.length}, degraded=${runResult?.degraded || false} (${Date.now() - dimStartTime}ms)`,
|
|
581
723
|
);
|
|
582
724
|
|
|
583
|
-
// ──
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
725
|
+
// ── Token 用量持久化 (fire-and-forget) ──
|
|
726
|
+
try {
|
|
727
|
+
const tokenStore = ctx.container?.get?.('tokenUsageStore');
|
|
728
|
+
if (tokenStore) {
|
|
729
|
+
const aiProv = runtime.aiProvider;
|
|
730
|
+
tokenStore.record({
|
|
731
|
+
source: 'system',
|
|
732
|
+
dimension: dimId,
|
|
733
|
+
provider: aiProv?.name || null,
|
|
734
|
+
model: aiProv?.model || null,
|
|
735
|
+
inputTokens: combinedTokenUsage.input || 0,
|
|
736
|
+
outputTokens: combinedTokenUsage.output || 0,
|
|
737
|
+
durationMs: Date.now() - dimStartTime,
|
|
738
|
+
toolCalls: runtimeToolCalls.length,
|
|
739
|
+
sessionId: sessionId || null,
|
|
740
|
+
});
|
|
741
|
+
try {
|
|
742
|
+
const realtime = ctx.container?.get?.('realtimeService');
|
|
743
|
+
realtime?.broadcastTokenUsageUpdated?.();
|
|
744
|
+
} catch { /* optional */ }
|
|
745
|
+
}
|
|
746
|
+
} catch { /* token logging should never break execution */ }
|
|
596
747
|
|
|
597
|
-
// v5.1:
|
|
598
|
-
// 但有足够的结构化发现时,从 findings 合成补充文本,避免 Producer 被 100 char 门控拦截
|
|
748
|
+
// ── v5.1: analysisText 过短补强 ──
|
|
599
749
|
if (needsCandidates && analysisReport.analysisText.length < 100) {
|
|
600
750
|
const findings = analysisReport.findings || [];
|
|
601
751
|
if (findings.length >= 3) {
|
|
@@ -612,9 +762,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
612
762
|
return `${i + 1}. ${text}`;
|
|
613
763
|
}),
|
|
614
764
|
];
|
|
615
|
-
|
|
616
|
-
const dimReport = sessionStore.getDimensionReport(dimId);
|
|
617
|
-
const memDistilled = dimReport?.workingMemoryDistilled;
|
|
765
|
+
const memDistilled = distilled;
|
|
618
766
|
if (memDistilled?.toolCallSummary?.length > 0) {
|
|
619
767
|
synthesized.push('', '### 探索记录', '');
|
|
620
768
|
for (const s of memDistilled.toolCallSummary.slice(0, 10)) {
|
|
@@ -624,71 +772,13 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
624
772
|
const originalLen = analysisReport.analysisText.length;
|
|
625
773
|
analysisReport.analysisText = synthesized.join('\n');
|
|
626
774
|
logger.info(
|
|
627
|
-
`[
|
|
628
|
-
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
if (needsCandidates && analysisReport.analysisText.length >= 100) {
|
|
634
|
-
try {
|
|
635
|
-
// v5.0: 为 Producer 创建独立作用域
|
|
636
|
-
const producerScopeId = `${dimId}:producer`;
|
|
637
|
-
memoryCoordinator.createDimensionScope(producerScopeId);
|
|
638
|
-
|
|
639
|
-
const producerPromise = producerAgent.produce(analysisReport, dimConfig, projectInfo, {
|
|
640
|
-
sessionId,
|
|
641
|
-
memoryCoordinator,
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
producerResult = await Promise.race([
|
|
645
|
-
producerPromise,
|
|
646
|
-
new Promise((_, reject) =>
|
|
647
|
-
setTimeout(() => reject(new Error(`Producer timeout for "${dimId}"`)), 180_000)
|
|
648
|
-
),
|
|
649
|
-
]);
|
|
650
|
-
|
|
651
|
-
candidateResults.created += producerResult.candidateCount;
|
|
652
|
-
// 更新 dimensionCandidates 以包含 Producer 结果
|
|
653
|
-
dimensionCandidates[dimId].producerResult = producerResult;
|
|
654
|
-
logger.info(
|
|
655
|
-
`[Bootstrap-v3] Producer "${dimId}": ${producerResult.candidateCount} candidates (${Date.now() - dimStartTime}ms total)`
|
|
656
|
-
);
|
|
657
|
-
} catch (producerErr) {
|
|
658
|
-
logger.error(
|
|
659
|
-
`[Bootstrap-v3] Producer "${dimId}" failed: ${producerErr.message} — Analyst result preserved for Skill generation`
|
|
775
|
+
`[Insight-v3] analysisText 补强 "${dimId}": ${originalLen} → ${analysisReport.analysisText.length} chars ` +
|
|
776
|
+
`(from ${findings.length} findings)`,
|
|
660
777
|
);
|
|
661
|
-
candidateResults.errors.push({ dimId, error: `Producer: ${producerErr.message}` });
|
|
662
|
-
|
|
663
|
-
// v5.1: 超时后异步监听实际结果,避免 ghost candidates 永远不被计数
|
|
664
|
-
if (producerErr.message.includes('timeout')) {
|
|
665
|
-
const dimIdRef = dimId;
|
|
666
|
-
// producerPromise 仍在后台执行 — 监听完成后更新统计
|
|
667
|
-
// biome-ignore lint: 故意 fire-and-forget
|
|
668
|
-
producerPromise
|
|
669
|
-
?.then((actualResult) => {
|
|
670
|
-
const count = actualResult?.candidateCount || 0;
|
|
671
|
-
if (count > 0) {
|
|
672
|
-
logger.info(
|
|
673
|
-
`[Bootstrap-v3] Producer "${dimIdRef}" completed post-timeout: ${count} candidates (ghost → reconciled)`
|
|
674
|
-
);
|
|
675
|
-
if (dimensionStats[dimIdRef]) {
|
|
676
|
-
dimensionStats[dimIdRef].candidateCount = count;
|
|
677
|
-
}
|
|
678
|
-
candidateResults.created += count;
|
|
679
|
-
dimensionCandidates[dimIdRef].producerResult = actualResult;
|
|
680
|
-
}
|
|
681
|
-
})
|
|
682
|
-
.catch((finalErr) => {
|
|
683
|
-
logger.warn(
|
|
684
|
-
`[Bootstrap-v3] Producer "${dimIdRef}" also failed post-timeout: ${finalErr.message}`
|
|
685
|
-
);
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
778
|
}
|
|
689
779
|
}
|
|
690
780
|
|
|
691
|
-
// ──
|
|
781
|
+
// ── DimensionDigest ──
|
|
692
782
|
const digest = parseDimensionDigest(producerResult.reply) || {
|
|
693
783
|
summary: `v3 分析: ${analysisReport.analysisText.substring(0, 200)}...`,
|
|
694
784
|
candidateCount: producerResult.candidateCount,
|
|
@@ -697,21 +787,19 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
697
787
|
gaps: [],
|
|
698
788
|
};
|
|
699
789
|
dimContext.addDimensionDigest(dimId, digest);
|
|
700
|
-
|
|
701
|
-
// v4.0: 同步 digest 到 SessionStore
|
|
702
790
|
sessionStore.addDimensionDigest(dimId, digest);
|
|
703
791
|
|
|
704
|
-
//
|
|
792
|
+
// 候选摘要记录到 DimensionContext + SessionStore
|
|
705
793
|
for (const tc of producerResult.toolCalls || []) {
|
|
706
794
|
const tool = tc.tool || tc.name;
|
|
707
795
|
if (tool === 'submit_knowledge' || tool === 'submit_with_check') {
|
|
796
|
+
const args = tc.params || tc.args || {};
|
|
708
797
|
const candidateSummary = {
|
|
709
|
-
title:
|
|
710
|
-
subTopic:
|
|
711
|
-
summary:
|
|
798
|
+
title: args.title || '',
|
|
799
|
+
subTopic: args.category || '',
|
|
800
|
+
summary: args.summary || '',
|
|
712
801
|
};
|
|
713
802
|
dimContext.addSubmittedCandidate(dimId, candidateSummary);
|
|
714
|
-
// v4.0: 同步到 SessionStore
|
|
715
803
|
sessionStore.addSubmittedCandidate(dimId, candidateSummary);
|
|
716
804
|
}
|
|
717
805
|
}
|
|
@@ -720,46 +808,41 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
720
808
|
type: needsCandidates ? 'candidate' : 'skill',
|
|
721
809
|
extracted: producerResult.candidateCount,
|
|
722
810
|
created: producerResult.candidateCount,
|
|
723
|
-
// v5.1: 标记 Skill 待生成,Dashboard 可据此避免显示 "无匹配内容"
|
|
724
811
|
skillPending: dimConfig.skillWorthy && producerResult.candidateCount === 0,
|
|
725
|
-
status: 'v3-complete',
|
|
812
|
+
status: 'v3-pipeline-complete',
|
|
813
|
+
degraded: runResult?.degraded || false,
|
|
726
814
|
durationMs: Date.now() - dimStartTime,
|
|
727
|
-
toolCallCount:
|
|
728
|
-
|
|
729
|
-
source: 'internal-agent',
|
|
815
|
+
toolCallCount: runtimeToolCalls.length,
|
|
816
|
+
source: 'enhanced-pipeline-strategy',
|
|
730
817
|
});
|
|
731
818
|
|
|
732
|
-
|
|
733
|
-
const analystTokens = analysisReport.metadata?.tokenUsage || { input: 0, output: 0 };
|
|
734
|
-
const producerTokens = producerResult.tokenUsage || { input: 0, output: 0 };
|
|
735
|
-
const dimTokenUsage = {
|
|
736
|
-
input: (analystTokens.input || 0) + (producerTokens.input || 0),
|
|
737
|
-
output: (analystTokens.output || 0) + (producerTokens.output || 0),
|
|
738
|
-
};
|
|
739
|
-
|
|
819
|
+
const dimTokenUsage = combinedTokenUsage;
|
|
740
820
|
const dimResult = {
|
|
741
821
|
candidateCount: producerResult.candidateCount,
|
|
742
822
|
rejectedCount: producerResult.rejectedCount || 0,
|
|
743
823
|
analysisChars: analysisReport.analysisText.length,
|
|
744
824
|
referencedFiles: analysisReport.referencedFiles.length,
|
|
745
825
|
durationMs: Date.now() - dimStartTime,
|
|
746
|
-
toolCallCount:
|
|
747
|
-
(analysisReport.metadata?.toolCallCount || 0) + (producerResult.toolCalls?.length || 0),
|
|
826
|
+
toolCallCount: runtimeToolCalls.length,
|
|
748
827
|
tokenUsage: dimTokenUsage,
|
|
749
|
-
// P3+: 保存 analysisText 供 checkpoint 恢复后 Skill 生成使用
|
|
750
828
|
analysisText: analysisReport.analysisText,
|
|
751
829
|
referencedFilesList: analysisReport.referencedFiles || [],
|
|
752
830
|
};
|
|
753
831
|
|
|
754
|
-
// P4.2: 记录维度统计
|
|
755
832
|
dimensionStats[dimId] = dimResult;
|
|
756
833
|
|
|
757
|
-
// P3: 保存 checkpoint
|
|
758
|
-
|
|
834
|
+
// P3: 保存 checkpoint — 仅当有实质分析内容时(避免 degraded/空结果污染后续 run)
|
|
835
|
+
if (analysisReport.analysisText.length >= 50) {
|
|
836
|
+
await saveDimensionCheckpoint(projectRoot, sessionId, dimId, dimResult, digest);
|
|
837
|
+
} else {
|
|
838
|
+
logger.warn(
|
|
839
|
+
`[Insight-v3] ⚠ 跳过 checkpoint 保存: "${dimId}" analysisText 过短 (${analysisReport.analysisText.length} chars)`
|
|
840
|
+
);
|
|
841
|
+
}
|
|
759
842
|
|
|
760
843
|
return dimResult;
|
|
761
844
|
} catch (err) {
|
|
762
|
-
logger.error(`[
|
|
845
|
+
logger.error(`[Insight-v3] Dimension "${dimId}" failed: ${err.message}`);
|
|
763
846
|
candidateResults.errors.push({ dimId, error: err.message });
|
|
764
847
|
emitter.emitDimensionComplete(dimId, { type: 'error', reason: err.message });
|
|
765
848
|
return { candidateCount: 0, error: err.message };
|
|
@@ -789,7 +872,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
789
872
|
const tierStats = [...tierResults.values()];
|
|
790
873
|
const totalCandidates = tierStats.reduce((s, r) => s + (r.candidateCount || 0), 0);
|
|
791
874
|
logger.info(
|
|
792
|
-
`[
|
|
875
|
+
`[Insight-v3] Tier ${tierIndex + 1} complete: ${tierResults.size} dimensions, ${totalCandidates} candidates`
|
|
793
876
|
);
|
|
794
877
|
|
|
795
878
|
// v4.0: Tier 级 Reflection — 综合本 Tier 所有维度的发现
|
|
@@ -797,29 +880,29 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
797
880
|
const reflection = buildTierReflection(tierIndex, tierResults, sessionStore);
|
|
798
881
|
sessionStore.addTierReflection(tierIndex, reflection);
|
|
799
882
|
logger.info(
|
|
800
|
-
`[
|
|
883
|
+
`[Insight-v3] Tier ${tierIndex + 1} reflection: ` +
|
|
801
884
|
`${reflection.topFindings.length} top findings, ` +
|
|
802
885
|
`${reflection.crossDimensionPatterns.length} patterns`
|
|
803
886
|
);
|
|
804
887
|
} catch (refErr) {
|
|
805
|
-
logger.warn(`[
|
|
888
|
+
logger.warn(`[Insight-v3] Tier ${tierIndex + 1} reflection failed: ${refErr.message}`);
|
|
806
889
|
}
|
|
807
890
|
},
|
|
808
891
|
});
|
|
809
892
|
|
|
810
893
|
logger.info(
|
|
811
|
-
`[
|
|
894
|
+
`[Insight-v3] All tiers complete: ${results.size} dimensions in ${Date.now() - t0}ms`
|
|
812
895
|
);
|
|
813
896
|
// v4.0: 记录 SessionStore 统计
|
|
814
897
|
const emStats = sessionStore.getStats();
|
|
815
898
|
logger.info(
|
|
816
|
-
`[
|
|
899
|
+
`[Insight-v3] Memory stats: ${emStats.completedDimensions} dims, ` +
|
|
817
900
|
`${emStats.totalFindings} findings, ${emStats.referencedFiles} files, ` +
|
|
818
901
|
`${emStats.crossReferences} cross-refs, ${emStats.tierReflections} reflections`
|
|
819
902
|
);
|
|
820
903
|
if (emStats.cacheStats) {
|
|
821
904
|
logger.info(
|
|
822
|
-
`[
|
|
905
|
+
`[Insight-v3] Cache stats: ${emStats.cacheStats.hitRate} hit rate, ` +
|
|
823
906
|
`${emStats.cacheStats.searchCacheSize} searches, ${emStats.cacheStats.fileCacheSize} files`
|
|
824
907
|
);
|
|
825
908
|
}
|
|
@@ -836,7 +919,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
836
919
|
await executeDimension(dimId);
|
|
837
920
|
}
|
|
838
921
|
}
|
|
839
|
-
logger.info(`[
|
|
922
|
+
logger.info(`[Insight-v3] Serial execution complete in ${Date.now() - t0}ms`);
|
|
840
923
|
}
|
|
841
924
|
|
|
842
925
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -893,7 +976,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
893
976
|
}
|
|
894
977
|
effectiveText = synthesized.join('\n');
|
|
895
978
|
logger.info(
|
|
896
|
-
`[
|
|
979
|
+
`[Insight-v3] Skill "${dim.id}": analysisText too short (${analysisText.trim().length} chars), ` +
|
|
897
980
|
`synthesized from ${keyFindings.length} findings → ${effectiveText.length} chars`
|
|
898
981
|
);
|
|
899
982
|
}
|
|
@@ -917,14 +1000,14 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
917
1000
|
emitter.emitDimensionFailed(dim.id, new Error(result.error));
|
|
918
1001
|
}
|
|
919
1002
|
} catch (err) {
|
|
920
|
-
logger.warn(`[
|
|
1003
|
+
logger.warn(`[Insight-v3] Skill generation failed for "${dim.id}": ${err.message}`);
|
|
921
1004
|
skillResults.failed++;
|
|
922
1005
|
skillResults.errors.push({ dimId: dim.id, error: err.message });
|
|
923
1006
|
emitter.emitDimensionFailed(dim.id, err);
|
|
924
1007
|
}
|
|
925
1008
|
}
|
|
926
1009
|
} catch (e) {
|
|
927
|
-
logger.warn(`[
|
|
1010
|
+
logger.warn(`[Insight-v3] Skill generation module import failed: ${e.message}`);
|
|
928
1011
|
}
|
|
929
1012
|
|
|
930
1013
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -958,13 +1041,13 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
958
1041
|
if (allCandidates.length > 0) {
|
|
959
1042
|
const relResult = ceg.populateFromCandidateRelations(allCandidates);
|
|
960
1043
|
logger.info(
|
|
961
|
-
`[
|
|
1044
|
+
`[Insight-v3] Code Entity Graph relations: ${relResult.edgesCreated} edges from ${allCandidates.length} candidates (${relResult.durationMs}ms)`
|
|
962
1045
|
);
|
|
963
1046
|
}
|
|
964
1047
|
}
|
|
965
1048
|
} catch (cegErr) {
|
|
966
1049
|
logger.warn(
|
|
967
|
-
`[
|
|
1050
|
+
`[Insight-v3] Code Entity Graph relations failed (non-blocking): ${cegErr.message}`
|
|
968
1051
|
);
|
|
969
1052
|
}
|
|
970
1053
|
|
|
@@ -978,7 +1061,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
978
1061
|
try {
|
|
979
1062
|
const db = ctx.container.get('database');
|
|
980
1063
|
if (db) {
|
|
981
|
-
const semanticMemory = new
|
|
1064
|
+
const semanticMemory = new PersistentMemory(db, { logger });
|
|
982
1065
|
const consolidator = new EpisodicConsolidator(semanticMemory, { logger });
|
|
983
1066
|
|
|
984
1067
|
consolidationResult = consolidator.consolidate(sessionStore, {
|
|
@@ -988,18 +1071,18 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
988
1071
|
|
|
989
1072
|
const smStats = semanticMemory.getStats();
|
|
990
1073
|
logger.info(
|
|
991
|
-
`[
|
|
1074
|
+
`[Insight-v3] Semantic Memory consolidation: ` +
|
|
992
1075
|
`+${consolidationResult.total.added} ADD, ` +
|
|
993
1076
|
`~${consolidationResult.total.updated} UPDATE, ` +
|
|
994
1077
|
`⊕${consolidationResult.total.merged} MERGE | ` +
|
|
995
1078
|
`Total: ${smStats.total} memories (avg importance: ${smStats.avgImportance})`
|
|
996
1079
|
);
|
|
997
1080
|
} else {
|
|
998
|
-
logger.warn('[
|
|
1081
|
+
logger.warn('[Insight-v3] Database not available — skipping Semantic Memory consolidation');
|
|
999
1082
|
}
|
|
1000
1083
|
} catch (consolidateErr) {
|
|
1001
1084
|
logger.warn(
|
|
1002
|
-
`[
|
|
1085
|
+
`[Insight-v3] Semantic Memory consolidation failed (non-blocking): ${consolidateErr.message}`
|
|
1003
1086
|
);
|
|
1004
1087
|
}
|
|
1005
1088
|
|
|
@@ -1023,7 +1106,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1023
1106
|
|
|
1024
1107
|
logger.info(
|
|
1025
1108
|
[
|
|
1026
|
-
`[
|
|
1109
|
+
`[Insight-v3] ═══ Pipeline complete ═══`,
|
|
1027
1110
|
isIncremental
|
|
1028
1111
|
? ` Mode: INCREMENTAL (${incrementalPlan.affectedDimensions.length} affected, ${incrementalSkippedDims.length} skipped)`
|
|
1029
1112
|
: '',
|
|
@@ -1136,9 +1219,9 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1136
1219
|
path.join(reportDir, 'bootstrap-report.json'),
|
|
1137
1220
|
JSON.stringify(report, null, 2)
|
|
1138
1221
|
);
|
|
1139
|
-
logger.info(`[
|
|
1222
|
+
logger.info(`[Insight-v3] 📊 Bootstrap report saved to .autosnippet/bootstrap-report.json`);
|
|
1140
1223
|
} catch (reportErr) {
|
|
1141
|
-
logger.warn(`[
|
|
1224
|
+
logger.warn(`[Insight-v3] Bootstrap report generation failed: ${reportErr.message}`);
|
|
1142
1225
|
}
|
|
1143
1226
|
|
|
1144
1227
|
// P3: 成功完成后清理 checkpoints
|
|
@@ -1161,15 +1244,15 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1161
1244
|
},
|
|
1162
1245
|
plan: isIncremental ? incrementalPlan : null,
|
|
1163
1246
|
});
|
|
1164
|
-
logger.info(`[
|
|
1247
|
+
logger.info(`[Insight-v3] 📸 Snapshot saved: ${snapshotId}`);
|
|
1165
1248
|
}
|
|
1166
1249
|
} catch (snapErr) {
|
|
1167
|
-
logger.warn(`[
|
|
1250
|
+
logger.warn(`[Insight-v3] Snapshot save failed (non-blocking): ${snapErr.message}`);
|
|
1168
1251
|
}
|
|
1169
1252
|
|
|
1170
1253
|
// 释放文件缓存
|
|
1171
1254
|
allFiles = null;
|
|
1172
|
-
|
|
1255
|
+
ctx.container.singletons._fileCache = null;
|
|
1173
1256
|
|
|
1174
1257
|
// ── Cursor Delivery: 生成 4 通道交付物料 ──
|
|
1175
1258
|
try {
|
|
@@ -1179,7 +1262,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1179
1262
|
const pipeline = container.get('cursorDeliveryPipeline');
|
|
1180
1263
|
const deliveryResult = await pipeline.deliver();
|
|
1181
1264
|
logger.info(
|
|
1182
|
-
`[
|
|
1265
|
+
`[Insight-v3] 🚀 Cursor Delivery complete — ` +
|
|
1183
1266
|
`A: ${deliveryResult.channelA.rulesCount} rules, ` +
|
|
1184
1267
|
`B: ${deliveryResult.channelB.topicCount} topics, ` +
|
|
1185
1268
|
`C: ${deliveryResult.channelC.synced} skills, ` +
|
|
@@ -1188,7 +1271,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1188
1271
|
);
|
|
1189
1272
|
}
|
|
1190
1273
|
} catch (deliveryErr) {
|
|
1191
|
-
logger.warn(`[
|
|
1274
|
+
logger.warn(`[Insight-v3] Cursor Delivery failed (non-blocking): ${deliveryErr.message}`);
|
|
1192
1275
|
}
|
|
1193
1276
|
|
|
1194
1277
|
// ── Repo Wiki: 自动生成项目文档 Wiki ──
|
|
@@ -1265,7 +1348,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1265
1348
|
const wikiResult = await wiki.generate();
|
|
1266
1349
|
if (wikiResult.success) {
|
|
1267
1350
|
logger.info(
|
|
1268
|
-
`[
|
|
1351
|
+
`[Insight-v3] 📖 Wiki generated — ${wikiResult.filesGenerated} files, ` +
|
|
1269
1352
|
`AI: ${wikiResult.aiComposed || 0}, Synced: ${wikiResult.syncedDocs || 0}, ` +
|
|
1270
1353
|
`Dedup removed: ${wikiResult.dedup?.removed?.length || 0}`
|
|
1271
1354
|
);
|
|
@@ -1289,7 +1372,7 @@ export async function fillDimensionsV3(fillContext) {
|
|
|
1289
1372
|
} catch { /* non-critical */ }
|
|
1290
1373
|
}
|
|
1291
1374
|
} catch (wikiErr) {
|
|
1292
|
-
logger.warn(`[
|
|
1375
|
+
logger.warn(`[Insight-v3] Wiki generation failed (non-blocking): ${wikiErr.message}`);
|
|
1293
1376
|
try {
|
|
1294
1377
|
const wikiRoute = await import('../../../../../http/routes/wiki.js');
|
|
1295
1378
|
wikiRoute.patchWikiTask?.({
|