autosnippet 3.3.0 → 3.3.3
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/dashboard/dist/assets/icons-BJ2mUBi8.js +1 -0
- package/dashboard/dist/assets/index-B659K9t5.js +128 -0
- package/dashboard/dist/assets/index-NCm40PMD.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +284 -142
- package/dist/lib/agent/context/ExplorationTracker.d.ts +2 -0
- package/dist/lib/agent/context/ExplorationTracker.js +21 -3
- package/dist/lib/agent/core/ToolExecutionPipeline.d.ts +3 -1
- package/dist/lib/agent/core/ToolExecutionPipeline.js +8 -1
- package/dist/lib/agent/forge/DynamicComposer.d.ts +58 -0
- package/dist/lib/agent/forge/DynamicComposer.js +99 -0
- package/dist/lib/agent/forge/SandboxRunner.d.ts +60 -0
- package/dist/lib/agent/forge/SandboxRunner.js +251 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.d.ts +76 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.js +154 -0
- package/dist/lib/agent/forge/ToolForge.d.ts +92 -0
- package/dist/lib/agent/forge/ToolForge.js +239 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.d.ts +44 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.js +119 -0
- package/dist/lib/agent/tools/ToolRegistry.d.ts +2 -0
- package/dist/lib/agent/tools/ToolRegistry.js +4 -0
- package/dist/lib/agent/tools/composite.js +0 -1
- package/dist/lib/agent/tools/index.d.ts +2 -50
- package/dist/lib/agent/tools/index.js +2 -3
- package/dist/lib/agent/tools/lifecycle.d.ts +1 -58
- package/dist/lib/agent/tools/lifecycle.js +2 -75
- package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
- package/dist/lib/cli/KnowledgeSyncService.js +33 -1
- package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
- package/dist/lib/cli/deploy/FileManifest.js +0 -11
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +10 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +2 -0
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +19 -2
- package/dist/lib/domain/knowledge/Lifecycle.js +32 -6
- package/dist/lib/domain/knowledge/UnifiedValidator.d.ts +1 -5
- package/dist/lib/domain/knowledge/UnifiedValidator.js +7 -44
- package/dist/lib/domain/knowledge/values/Stats.d.ts +29 -0
- package/dist/lib/domain/knowledge/values/Stats.js +41 -0
- package/dist/lib/external/mcp/McpServer.d.ts +19 -38
- package/dist/lib/external/mcp/McpServer.js +145 -117
- package/dist/lib/external/mcp/autoApproveInjector.js +0 -2
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +26 -1
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +41 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +3 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +27 -0
- package/dist/lib/external/mcp/handlers/bootstrap/skills.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/browse.js +2 -1
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +117 -6
- package/dist/lib/external/mcp/handlers/consolidated.js +251 -71
- package/dist/lib/external/mcp/handlers/guard.d.ts +150 -0
- package/dist/lib/external/mcp/handlers/guard.js +239 -5
- package/dist/lib/external/mcp/handlers/knowledge.d.ts +0 -29
- package/dist/lib/external/mcp/handlers/knowledge.js +1 -76
- package/dist/lib/external/mcp/handlers/panorama.d.ts +36 -0
- package/dist/lib/external/mcp/handlers/panorama.js +156 -0
- package/dist/lib/external/mcp/handlers/system.d.ts +2 -54
- package/dist/lib/external/mcp/handlers/system.js +3 -113
- package/dist/lib/external/mcp/handlers/task.d.ts +13 -24
- package/dist/lib/external/mcp/handlers/task.js +218 -557
- package/dist/lib/external/mcp/handlers/types.d.ts +91 -8
- package/dist/lib/external/mcp/handlers/types.js +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.d.ts +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.js +16 -1
- package/dist/lib/external/mcp/tools.d.ts +18 -24
- package/dist/lib/external/mcp/tools.js +132 -159
- package/dist/lib/http/HttpServer.js +52 -0
- package/dist/lib/http/middleware/validate.js +7 -3
- package/dist/lib/http/routes/audit.d.ts +8 -0
- package/dist/lib/http/routes/audit.js +51 -0
- package/dist/lib/http/routes/guardReport.d.ts +10 -0
- package/dist/lib/http/routes/guardReport.js +143 -0
- package/dist/lib/http/routes/knowledge.js +32 -1
- package/dist/lib/http/routes/panorama.d.ts +11 -0
- package/dist/lib/http/routes/panorama.js +322 -0
- package/dist/lib/http/routes/signals.d.ts +10 -0
- package/dist/lib/http/routes/signals.js +104 -0
- package/dist/lib/http/routes/task.d.ts +2 -3
- package/dist/lib/http/routes/task.js +17 -347
- package/dist/lib/http/routes/violations.js +1 -1
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +6 -1
- package/dist/lib/infrastructure/audit/AuditLogger.js +14 -1
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +202 -504
- package/dist/lib/infrastructure/database/drizzle/schema.js +38 -69
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.d.ts +8 -0
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.js +43 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
- package/dist/lib/infrastructure/logging/Logger.d.ts +2 -0
- package/dist/lib/infrastructure/logging/Logger.js +34 -7
- package/dist/lib/infrastructure/monitoring/ErrorTracker.js +3 -1
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.d.ts +2 -2
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -10
- package/dist/lib/infrastructure/notification/LarkNotifier.d.ts +24 -0
- package/dist/lib/infrastructure/notification/LarkNotifier.js +97 -0
- package/dist/lib/infrastructure/report/ReportStore.d.ts +45 -0
- package/dist/lib/infrastructure/report/ReportStore.js +133 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.d.ts +18 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.js +84 -0
- package/dist/lib/infrastructure/signal/SignalBridge.d.ts +13 -0
- package/dist/lib/infrastructure/signal/SignalBridge.js +20 -0
- package/dist/lib/infrastructure/signal/SignalBus.d.ts +63 -0
- package/dist/lib/infrastructure/signal/SignalBus.js +106 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.d.ts +36 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.js +130 -0
- package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
- package/dist/lib/injection/ServiceContainer.js +8 -0
- package/dist/lib/injection/ServiceMap.d.ts +16 -10
- package/dist/lib/injection/modules/AgentModule.d.ts +1 -1
- package/dist/lib/injection/modules/AgentModule.js +7 -1
- package/dist/lib/injection/modules/AppModule.d.ts +1 -1
- package/dist/lib/injection/modules/AppModule.js +4 -13
- package/dist/lib/injection/modules/GuardModule.js +27 -2
- package/dist/lib/injection/modules/InfraModule.d.ts +0 -1
- package/dist/lib/injection/modules/InfraModule.js +9 -7
- package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +131 -0
- package/dist/lib/injection/modules/PanoramaModule.d.ts +18 -0
- package/dist/lib/injection/modules/PanoramaModule.js +76 -0
- package/dist/lib/injection/modules/SignalModule.d.ts +10 -0
- package/dist/lib/injection/modules/SignalModule.js +84 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +1 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +6 -0
- package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +3 -1
- package/dist/lib/service/bootstrap/BootstrapTaskManager.js +20 -1
- package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
- package/dist/lib/service/delivery/AgentInstructionsGenerator.js +4 -5
- package/dist/lib/service/delivery/CursorDeliveryPipeline.d.ts +3 -1
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +13 -10
- package/dist/lib/service/delivery/RulesGenerator.js +3 -2
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +114 -0
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +542 -0
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +54 -0
- package/dist/lib/service/evolution/ContradictionDetector.js +253 -0
- package/dist/lib/service/evolution/DecayDetector.d.ts +71 -0
- package/dist/lib/service/evolution/DecayDetector.js +244 -0
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +38 -0
- package/dist/lib/service/evolution/EnhancementSuggester.js +220 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +82 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +167 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +53 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +210 -0
- package/dist/lib/service/evolution/StagingManager.d.ts +57 -0
- package/dist/lib/service/evolution/StagingManager.js +201 -0
- package/dist/lib/service/guard/ComplianceReporter.d.ts +42 -2
- package/dist/lib/service/guard/ComplianceReporter.js +43 -5
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +54 -0
- package/dist/lib/service/guard/CoverageAnalyzer.js +149 -0
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +42 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +465 -14
- package/dist/lib/service/guard/GuardFeedbackLoop.d.ts +3 -0
- package/dist/lib/service/guard/GuardFeedbackLoop.js +9 -0
- package/dist/lib/service/guard/ReverseGuard.d.ts +73 -0
- package/dist/lib/service/guard/ReverseGuard.js +256 -0
- package/dist/lib/service/guard/RuleLearner.d.ts +12 -0
- package/dist/lib/service/guard/RuleLearner.js +38 -0
- package/dist/lib/service/guard/UncertaintyCollector.d.ts +83 -0
- package/dist/lib/service/guard/UncertaintyCollector.js +149 -0
- package/dist/lib/service/guard/ViolationsStore.d.ts +1 -0
- package/dist/lib/service/guard/ViolationsStore.js +33 -3
- package/dist/lib/service/knowledge/ConfidenceRouter.d.ts +13 -0
- package/dist/lib/service/knowledge/ConfidenceRouter.js +14 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +22 -4
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
- package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +27 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.js +192 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +28 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.js +320 -0
- package/dist/lib/service/panorama/LayerInferrer.d.ts +19 -0
- package/dist/lib/service/panorama/LayerInferrer.js +182 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +24 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +185 -0
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +29 -0
- package/dist/lib/service/panorama/PanoramaAggregator.js +228 -0
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +52 -0
- package/dist/lib/service/panorama/PanoramaScanner.js +188 -0
- package/dist/lib/service/panorama/PanoramaService.d.ts +125 -0
- package/dist/lib/service/panorama/PanoramaService.js +363 -0
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +134 -0
- package/dist/lib/service/panorama/PanoramaTypes.js +6 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +48 -0
- package/dist/lib/service/panorama/RoleRefiner.js +535 -0
- package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
- package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
- package/dist/lib/service/search/CoarseRanker.js +11 -10
- package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
- package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
- package/dist/lib/service/search/MultiSignalRanker.d.ts +3 -2
- package/dist/lib/service/search/MultiSignalRanker.js +17 -1
- package/dist/lib/service/search/SearchEngine.d.ts +9 -7
- package/dist/lib/service/search/SearchEngine.js +67 -10
- package/dist/lib/service/search/SearchTypes.d.ts +25 -3
- package/dist/lib/service/search/SearchTypes.js +6 -1
- package/dist/lib/service/signal/HitRecorder.d.ts +68 -0
- package/dist/lib/service/signal/HitRecorder.js +173 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +3 -1
- package/dist/lib/service/skills/SignalCollector.js +31 -1
- package/dist/lib/service/task/IntentExtractor.d.ts +66 -0
- package/dist/lib/service/task/IntentExtractor.js +256 -0
- package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
- package/dist/lib/service/task/PrimeSearchPipeline.js +113 -0
- package/dist/lib/service/vector/VectorService.d.ts +3 -0
- package/dist/lib/service/vector/VectorService.js +38 -4
- package/dist/lib/shared/schemas/mcp-tools.d.ts +41 -96
- package/dist/lib/shared/schemas/mcp-tools.js +59 -119
- package/dist/scripts/analyze-signals.d.ts +20 -0
- package/dist/scripts/analyze-signals.js +155 -0
- package/dist/scripts/diagnose-mcp.js +1 -1
- package/package.json +1 -1
- package/skills/autosnippet-create/SKILL.md +98 -89
- package/skills/autosnippet-devdocs/SKILL.md +55 -57
- package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
- package/templates/cursor-hooks/hooks/session-start.sh +1 -1
- package/templates/guard-ci.yml +2 -2
- package/templates/instructions/agent-static.md +2 -1
- package/templates/instructions/conventions.md +5 -6
- package/templates/recipes-setup/README.md +1 -2
- package/templates/recipes-setup/_template.md +39 -39
- package/dashboard/dist/assets/icons-BofcEZ3f.js +0 -1
- package/dashboard/dist/assets/index-D0whuycy.css +0 -1
- package/dashboard/dist/assets/index-SiN1GChm.js +0 -128
- package/dist/lib/domain/task/Task.d.ts +0 -140
- package/dist/lib/domain/task/Task.js +0 -254
- package/dist/lib/domain/task/TaskDependency.d.ts +0 -23
- package/dist/lib/domain/task/TaskDependency.js +0 -34
- package/dist/lib/domain/task/TaskIdGenerator.d.ts +0 -40
- package/dist/lib/domain/task/TaskIdGenerator.js +0 -75
- package/dist/lib/domain/task/index.d.ts +0 -4
- package/dist/lib/domain/task/index.js +0 -4
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.d.ts +0 -11
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.js +0 -86
- package/dist/lib/repository/task/TaskRepository.impl.d.ts +0 -171
- package/dist/lib/repository/task/TaskRepository.impl.js +0 -347
- package/dist/lib/service/task/TaskGraphService.d.ts +0 -222
- package/dist/lib/service/task/TaskGraphService.js +0 -597
- package/dist/lib/service/task/TaskKnowledgeBridge.d.ts +0 -95
- package/dist/lib/service/task/TaskKnowledgeBridge.js +0 -298
- package/dist/lib/service/task/TaskReadyEngine.d.ts +0 -84
- package/dist/lib/service/task/TaskReadyEngine.js +0 -115
|
@@ -1,597 +0,0 @@
|
|
|
1
|
-
import { Task } from '../../domain/task/Task.js';
|
|
2
|
-
import { affectsReadyWork, DepType, isValidDepType } from '../../domain/task/TaskDependency.js';
|
|
3
|
-
import Logger from '../../infrastructure/logging/Logger.js';
|
|
4
|
-
/**
|
|
5
|
-
* TaskGraphService — 任务图核心服务
|
|
6
|
-
*
|
|
7
|
-
* 编排 TaskRepository / TaskReadyEngine / TaskKnowledgeBridge / AuditLog / IdGenerator。
|
|
8
|
-
* 对外提供完整的任务生命周期管理。
|
|
9
|
-
*
|
|
10
|
-
* 设计原则:
|
|
11
|
-
* - 所有写操作记录审计事件 (task_events 表)
|
|
12
|
-
* - claim 是原子操作 (status + assignee 一起更新)
|
|
13
|
-
* - close 时验证不变量 (closedAt 必须存在)
|
|
14
|
-
* - 子任务 ID 自动递增 (parent.1, parent.2, ...)
|
|
15
|
-
*
|
|
16
|
-
* AutoSnippet 增强:
|
|
17
|
-
* - ready 返回带知识上下文的任务
|
|
18
|
-
* - close 返回 newlyReady 列表(减少 Agent MCP 调用次数)
|
|
19
|
-
* - prime 支持会话恢复(幂等)
|
|
20
|
-
*/
|
|
21
|
-
export class TaskGraphService {
|
|
22
|
-
auditLogger;
|
|
23
|
-
bridge;
|
|
24
|
-
idGen;
|
|
25
|
-
logger;
|
|
26
|
-
readyEngine;
|
|
27
|
-
repo;
|
|
28
|
-
constructor(repository, readyEngine, knowledgeBridge, auditLogger, idGenerator) {
|
|
29
|
-
this.repo = repository;
|
|
30
|
-
this.readyEngine = readyEngine;
|
|
31
|
-
this.bridge = knowledgeBridge || null;
|
|
32
|
-
this.auditLogger = auditLogger || null;
|
|
33
|
-
this.idGen = idGenerator;
|
|
34
|
-
this.logger = Logger.getInstance();
|
|
35
|
-
}
|
|
36
|
-
// ═══ 创建 ═══════════════════════════════════════════
|
|
37
|
-
/**
|
|
38
|
-
* 创建任务
|
|
39
|
-
* @param data { title, description, design, acceptance, priority, taskType, parentId }
|
|
40
|
-
* @returns >}
|
|
41
|
-
*/
|
|
42
|
-
async create(data) {
|
|
43
|
-
const task = new Task(data);
|
|
44
|
-
task.computeContentHash();
|
|
45
|
-
task.validate();
|
|
46
|
-
// 去重检测(findByContentHash 已排除 closed 状态)
|
|
47
|
-
const duplicate = this.repo.findByContentHash(task.contentHash);
|
|
48
|
-
if (duplicate) {
|
|
49
|
-
return { task: duplicate, isDuplicate: true };
|
|
50
|
-
}
|
|
51
|
-
// 生成 ID
|
|
52
|
-
if (data.parentId) {
|
|
53
|
-
task.id = this.idGen.generateChild(data.parentId);
|
|
54
|
-
task.parentId = data.parentId;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
task.id = this.idGen.generate();
|
|
58
|
-
}
|
|
59
|
-
// 事务:创建任务 + 子任务自动依赖
|
|
60
|
-
const saved = this.repo.inTransaction(() => {
|
|
61
|
-
const created = this.repo.create(task);
|
|
62
|
-
if (data.parentId) {
|
|
63
|
-
this.repo.addDependency(created.id, data.parentId, DepType.PARENT_CHILD);
|
|
64
|
-
}
|
|
65
|
-
return created;
|
|
66
|
-
});
|
|
67
|
-
this._logEvent(saved.id, 'created', null, saved.title);
|
|
68
|
-
return { task: saved, isDuplicate: false };
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 批量拆解 Epic
|
|
72
|
-
* 一次性创建多个子任务 + 依赖关系,减少 Agent 的 MCP 调用次数
|
|
73
|
-
*
|
|
74
|
-
* @param subtasks [{ title, description, priority, taskType, blockedByIndex }]
|
|
75
|
-
*/
|
|
76
|
-
async decompose(epicId, subtasks) {
|
|
77
|
-
const epic = this.repo.findById(epicId);
|
|
78
|
-
if (!epic) {
|
|
79
|
-
throw new Error(`Epic not found: ${epicId}`);
|
|
80
|
-
}
|
|
81
|
-
// 决策不可拆解(C6)
|
|
82
|
-
if (epic.taskType === 'decision') {
|
|
83
|
-
throw new Error('Cannot decompose a decision. Decisions are atomic records.');
|
|
84
|
-
}
|
|
85
|
-
if (epic.status === 'pinned') {
|
|
86
|
-
throw new Error('Cannot decompose a pinned task.');
|
|
87
|
-
}
|
|
88
|
-
const results = this.repo.inTransaction(() => {
|
|
89
|
-
const created = [];
|
|
90
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
91
|
-
const sub = subtasks[i];
|
|
92
|
-
const task = new Task({
|
|
93
|
-
...sub,
|
|
94
|
-
parentId: epicId,
|
|
95
|
-
});
|
|
96
|
-
task.computeContentHash();
|
|
97
|
-
task.validate();
|
|
98
|
-
task.id = this.idGen.generateChild(epicId);
|
|
99
|
-
task.parentId = epicId;
|
|
100
|
-
const saved = this.repo.create(task);
|
|
101
|
-
this.repo.addDependency(saved.id, epicId, DepType.PARENT_CHILD);
|
|
102
|
-
created.push(saved);
|
|
103
|
-
}
|
|
104
|
-
// 子任务间的依赖(通过 index 引用,支持单个数字或数组)
|
|
105
|
-
for (let i = 0; i < subtasks.length; i++) {
|
|
106
|
-
const sub = subtasks[i];
|
|
107
|
-
if (sub.blockedByIndex == null) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
// 统一为数组处理
|
|
111
|
-
const indices = Array.isArray(sub.blockedByIndex)
|
|
112
|
-
? sub.blockedByIndex
|
|
113
|
-
: [sub.blockedByIndex];
|
|
114
|
-
for (const idx of indices) {
|
|
115
|
-
if (typeof idx === 'number' && idx >= 0 && idx < created.length && idx !== i) {
|
|
116
|
-
this.repo.addDependency(created[i].id, created[idx].id, DepType.BLOCKS);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
// Epic 等待所有子任务完成
|
|
121
|
-
for (const c of created) {
|
|
122
|
-
this.repo.addDependency(epicId, c.id, DepType.WAITS_FOR);
|
|
123
|
-
}
|
|
124
|
-
return created;
|
|
125
|
-
});
|
|
126
|
-
this._logEvent(epicId, 'decomposed', null, `${results.length} subtasks`);
|
|
127
|
-
return results;
|
|
128
|
-
}
|
|
129
|
-
// ═══ 工作流操作 ═══════════════════════════════════════
|
|
130
|
-
/**
|
|
131
|
-
* 认领任务
|
|
132
|
-
*
|
|
133
|
-
* P5: claim-time 知识刷新 — 编码开始时注入最新知识上下文,
|
|
134
|
-
* 减少 Agent 额外 MCP 调用。
|
|
135
|
-
*
|
|
136
|
-
* @param [knowledgeOptions] 上下文信号
|
|
137
|
-
*/
|
|
138
|
-
async claim(id, assignee = 'agent', knowledgeOptions) {
|
|
139
|
-
const task = this.repo.findById(id);
|
|
140
|
-
if (!task) {
|
|
141
|
-
throw new Error(`Task not found: ${id}`);
|
|
142
|
-
}
|
|
143
|
-
const oldStatus = task.status;
|
|
144
|
-
task.claim(assignee);
|
|
145
|
-
const saved = this.repo.update(id, {
|
|
146
|
-
status: 'in_progress',
|
|
147
|
-
assignee,
|
|
148
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
149
|
-
});
|
|
150
|
-
if (!saved) {
|
|
151
|
-
throw new Error(`Failed to update task: ${id}`);
|
|
152
|
-
}
|
|
153
|
-
this._logEvent(id, 'status_changed', oldStatus, 'in_progress');
|
|
154
|
-
// P5: claim-time 知识刷新 — 异步注入,失败不阻塞 claim 本身
|
|
155
|
-
if (this.bridge) {
|
|
156
|
-
try {
|
|
157
|
-
const [enriched] = await this.bridge.enrichWithKnowledge([saved], knowledgeOptions);
|
|
158
|
-
if (enriched?.knowledgeContext) {
|
|
159
|
-
saved.knowledgeContext = enriched.knowledgeContext;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
this.logger.debug('claim: knowledge enrichment failed (non-blocking)', {
|
|
164
|
-
taskId: id,
|
|
165
|
-
error: err.message,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return saved;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* 关闭任务
|
|
173
|
-
* 返回因此解除阻塞的新就绪任务列表
|
|
174
|
-
*
|
|
175
|
-
* @returns >}
|
|
176
|
-
*/
|
|
177
|
-
async close(id, reason = 'Completed') {
|
|
178
|
-
const task = this.repo.findById(id);
|
|
179
|
-
if (!task) {
|
|
180
|
-
throw new Error(`Task not found: ${id}`);
|
|
181
|
-
}
|
|
182
|
-
const oldStatus = task.status;
|
|
183
|
-
task.close(reason);
|
|
184
|
-
const saved = this.repo.update(id, {
|
|
185
|
-
status: 'closed',
|
|
186
|
-
closeReason: reason,
|
|
187
|
-
closedAt: Math.floor(Date.now() / 1000),
|
|
188
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
189
|
-
});
|
|
190
|
-
this._logEvent(id, 'closed', oldStatus, `closed: ${reason}`);
|
|
191
|
-
// 查找因此解除阻塞的任务
|
|
192
|
-
const newlyReady = this._checkNewlyUnblocked(id);
|
|
193
|
-
return { task: saved, newlyReady };
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* 标记任务失败
|
|
197
|
-
* 释放认领、递增失败计数、回退到 open
|
|
198
|
-
*/
|
|
199
|
-
async fail(id, reason) {
|
|
200
|
-
const task = this.repo.findById(id);
|
|
201
|
-
if (!task) {
|
|
202
|
-
throw new Error(`Task not found: ${id}`);
|
|
203
|
-
}
|
|
204
|
-
task.fail(reason);
|
|
205
|
-
const saved = this.repo.update(id, {
|
|
206
|
-
status: 'open',
|
|
207
|
-
assignee: '',
|
|
208
|
-
failCount: task.failCount,
|
|
209
|
-
lastFailReason: task.lastFailReason,
|
|
210
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
211
|
-
});
|
|
212
|
-
this._logEvent(id, 'failed', 'in_progress', reason);
|
|
213
|
-
return saved;
|
|
214
|
-
}
|
|
215
|
-
/** 推迟任务 */
|
|
216
|
-
async defer(id, reason = '') {
|
|
217
|
-
const task = this.repo.findById(id);
|
|
218
|
-
if (!task) {
|
|
219
|
-
throw new Error(`Task not found: ${id}`);
|
|
220
|
-
}
|
|
221
|
-
const oldStatus = task.status;
|
|
222
|
-
task.defer(reason);
|
|
223
|
-
const saved = this.repo.update(id, {
|
|
224
|
-
status: 'deferred',
|
|
225
|
-
notes: task.notes,
|
|
226
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
227
|
-
});
|
|
228
|
-
this._logEvent(id, 'deferred', oldStatus, reason);
|
|
229
|
-
return saved;
|
|
230
|
-
}
|
|
231
|
-
/** 上报进度(长任务的中间状态更新) */
|
|
232
|
-
async progress(id, note) {
|
|
233
|
-
const task = this.repo.findById(id);
|
|
234
|
-
if (!task) {
|
|
235
|
-
throw new Error(`Task not found: ${id}`);
|
|
236
|
-
}
|
|
237
|
-
if (task.status !== 'in_progress') {
|
|
238
|
-
throw new Error(`Cannot update progress: task ${id} is ${task.status}, expected in_progress`);
|
|
239
|
-
}
|
|
240
|
-
const saved = this.repo.update(id, {
|
|
241
|
-
notes: note,
|
|
242
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
243
|
-
});
|
|
244
|
-
this._logEvent(id, 'progress', null, note);
|
|
245
|
-
return saved;
|
|
246
|
-
}
|
|
247
|
-
// ═══ 依赖管理 ═══════════════════════════════════════
|
|
248
|
-
/** 添加依赖 */
|
|
249
|
-
async addDependency(taskId, dependsOnId, depType = 'blocks') {
|
|
250
|
-
if (taskId === dependsOnId) {
|
|
251
|
-
throw new Error('Self-dependency is not allowed');
|
|
252
|
-
}
|
|
253
|
-
if (!isValidDepType(depType)) {
|
|
254
|
-
throw new Error(`Invalid dependency type: ${depType}`);
|
|
255
|
-
}
|
|
256
|
-
// 阻塞型依赖需要环检测
|
|
257
|
-
if (affectsReadyWork(depType)) {
|
|
258
|
-
const hasCycle = this.repo.hasReachablePath(dependsOnId, taskId);
|
|
259
|
-
if (hasCycle) {
|
|
260
|
-
throw new Error(`Cycle detected: ${taskId} → ${dependsOnId}`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
this.repo.addDependency(taskId, dependsOnId, depType);
|
|
264
|
-
this._logEvent(taskId, 'dependency_added', null, `${depType}: ${dependsOnId}`);
|
|
265
|
-
}
|
|
266
|
-
// ═══ 查询操作 ═══════════════════════════════════════
|
|
267
|
-
/**
|
|
268
|
-
* 获取就绪任务 + 知识上下文
|
|
269
|
-
* @param [options] { limit, withKnowledge, userQuery, activeFile, language }
|
|
270
|
-
*/
|
|
271
|
-
async ready(options = {}) {
|
|
272
|
-
const tasks = this.readyEngine.getReadyWork(options);
|
|
273
|
-
if (this.bridge && options.withKnowledge !== false) {
|
|
274
|
-
const enrichOpts = {
|
|
275
|
-
userQuery: options.userQuery,
|
|
276
|
-
activeFile: options.activeFile,
|
|
277
|
-
language: options.language,
|
|
278
|
-
};
|
|
279
|
-
return this.bridge.enrichWithKnowledge(tasks, enrichOpts);
|
|
280
|
-
}
|
|
281
|
-
return tasks;
|
|
282
|
-
}
|
|
283
|
-
/** 获取被阻塞的任务 */
|
|
284
|
-
async blocked() {
|
|
285
|
-
return this.readyEngine.getBlockedWork();
|
|
286
|
-
}
|
|
287
|
-
/** 获取单个任务详情 */
|
|
288
|
-
async show(id) {
|
|
289
|
-
return this.repo.findById(id);
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* 列表查询
|
|
293
|
-
* @param filters { status, taskType, assignee, parentId }
|
|
294
|
-
* @param options { limit }
|
|
295
|
-
*/
|
|
296
|
-
async list(filters = {}, options = {}) {
|
|
297
|
-
return this.repo.findAll(filters, options);
|
|
298
|
-
}
|
|
299
|
-
/** 依赖树 */
|
|
300
|
-
async depTree(taskId) {
|
|
301
|
-
return this.readyEngine.getDependencyTree(taskId);
|
|
302
|
-
}
|
|
303
|
-
/** 统计信息 */
|
|
304
|
-
async stats() {
|
|
305
|
-
return this.repo.getStatistics();
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Prime — 会话恢复(幂等) + 用户输入感知知识注入
|
|
309
|
-
*
|
|
310
|
-
* 返回当前进行中的任务 + 就绪任务 + 统计信息。
|
|
311
|
-
* Agent 在新会话开始或上下文压缩后调用。
|
|
312
|
-
*
|
|
313
|
-
* P1: 新增 userQuery / activeFile / language 参数,
|
|
314
|
-
* 知识注入从「基于历史任务」升级为「基于历史任务 + 当前用户意图」。
|
|
315
|
-
*
|
|
316
|
-
* @param [options] { withKnowledge, userQuery, activeFile, language }
|
|
317
|
-
* @returns >}
|
|
318
|
-
*/
|
|
319
|
-
async prime(options = {}) {
|
|
320
|
-
const inProgress = this.repo
|
|
321
|
-
.findAll({ status: 'in_progress' }, { limit: 10 })
|
|
322
|
-
.filter((t) => t !== null);
|
|
323
|
-
const readyTasks = await this.ready({
|
|
324
|
-
limit: options.limit || 5,
|
|
325
|
-
withKnowledge: options.withKnowledge !== false,
|
|
326
|
-
userQuery: options.userQuery,
|
|
327
|
-
activeFile: options.activeFile,
|
|
328
|
-
language: options.language,
|
|
329
|
-
});
|
|
330
|
-
const statistics = await this.stats();
|
|
331
|
-
// 按创建时间降序,确保超出 limit 时保留最新决策(C5)
|
|
332
|
-
// 双重过滤 status+taskType,避免 pinned 语义过载(D1)
|
|
333
|
-
const pinnedDecisions = this.repo
|
|
334
|
-
.findAll({ status: 'pinned', taskType: 'decision' }, { limit: 50, orderBy: 'created_at DESC' })
|
|
335
|
-
.filter((t) => t !== null);
|
|
336
|
-
const result = {
|
|
337
|
-
inProgress: inProgress.map((t) => t.toJSON()),
|
|
338
|
-
ready: readyTasks.map((t) => (t.toJSON ? t.toJSON() : t)),
|
|
339
|
-
stats: statistics,
|
|
340
|
-
};
|
|
341
|
-
// P1: 用户输入感知 — 没有 ready tasks 时,直接基于 userQuery 搜索知识
|
|
342
|
-
if (options.userQuery && readyTasks.length === 0 && this.bridge) {
|
|
343
|
-
try {
|
|
344
|
-
const queryKnowledge = await this.bridge.searchForQuery(options.userQuery, {
|
|
345
|
-
language: options.language,
|
|
346
|
-
});
|
|
347
|
-
if (queryKnowledge) {
|
|
348
|
-
result.queryKnowledge = queryKnowledge;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
catch (err) {
|
|
352
|
-
this.logger.debug('prime: queryKnowledge search failed (non-blocking)', {
|
|
353
|
-
error: err.message,
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (pinnedDecisions.length > 0) {
|
|
358
|
-
// P2: Stale detection — 超过阈值的决策标记为 stale
|
|
359
|
-
const staleThresholdSec = this._getDecisionStaleThreshold();
|
|
360
|
-
const nowSec = Math.floor(Date.now() / 1000);
|
|
361
|
-
const activeDecisions = [];
|
|
362
|
-
const staleDecisions = [];
|
|
363
|
-
for (const t of pinnedDecisions) {
|
|
364
|
-
const isStale = t.metadata?.staleSince ||
|
|
365
|
-
(staleThresholdSec > 0 && t.createdAt && nowSec - t.createdAt > staleThresholdSec);
|
|
366
|
-
if (isStale) {
|
|
367
|
-
staleDecisions.push(t);
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
activeDecisions.push(t);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// P1 Result Compaction: compact 模式 — description 截断到 120 chars
|
|
374
|
-
// Agent 需要完整内容时调用 autosnippet_task({ operation: 'list_decisions' })
|
|
375
|
-
result.decisions = activeDecisions.map((t) => ({
|
|
376
|
-
id: t.id,
|
|
377
|
-
title: t.title,
|
|
378
|
-
summary: typeof t.description === 'string'
|
|
379
|
-
? t.description
|
|
380
|
-
.replace(/^## Decision\n/, '')
|
|
381
|
-
.split(/\n\n## /)[0]
|
|
382
|
-
.slice(0, 120)
|
|
383
|
-
: '',
|
|
384
|
-
createdAt: t.createdAt,
|
|
385
|
-
}));
|
|
386
|
-
// P2: stale decisions 单独返回(轻量格式,仅供提示)
|
|
387
|
-
if (staleDecisions.length > 0) {
|
|
388
|
-
result.staleDecisions = staleDecisions.map((t) => ({
|
|
389
|
-
id: t.id,
|
|
390
|
-
title: t.title,
|
|
391
|
-
createdAt: t.createdAt,
|
|
392
|
-
ageDays: Math.floor((nowSec - (t.createdAt || nowSec)) / 86400),
|
|
393
|
-
}));
|
|
394
|
-
}
|
|
395
|
-
result._decisionHint =
|
|
396
|
-
'These are team-agreed decisions (compact view). Respect them in your response. ' +
|
|
397
|
-
'Call autosnippet_task({ operation: "list_decisions" }) for full details. ' +
|
|
398
|
-
"If the user's request conflicts with a decision, point out the conflict and ask whether to revise_decision.";
|
|
399
|
-
if (staleDecisions.length > 0) {
|
|
400
|
-
result._staleHint =
|
|
401
|
-
`${staleDecisions.length} decision(s) are stale (>${Math.floor(staleThresholdSec / 86400)} days). ` +
|
|
402
|
-
'Consider reviewing with autosnippet_task({ operation: "list_decisions" }) and unpin outdated ones.';
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// ── 完整协议指令(从 copilot-instructions.md 移到 prime 返回值)──
|
|
406
|
-
result._protocol = [
|
|
407
|
-
'Respect decisions above. Record new decisions when user agrees/disagrees on something.',
|
|
408
|
-
'Use create/close to track multi-step work.',
|
|
409
|
-
].join('\n');
|
|
410
|
-
return result;
|
|
411
|
-
}
|
|
412
|
-
// ═══ 决策管理 ═══════════════════════════════════════
|
|
413
|
-
/**
|
|
414
|
-
* 记录决策 — 直接以 pinned 状态创建,避免 open→pinned 的幽灵窗口(C1)
|
|
415
|
-
* @param params { title, description, rationale, tags, relatedTaskId }
|
|
416
|
-
* @returns >}
|
|
417
|
-
*/
|
|
418
|
-
async recordDecision({ title, description, rationale, tags, relatedTaskId, }) {
|
|
419
|
-
if (!title) {
|
|
420
|
-
throw new Error('Decision title is required');
|
|
421
|
-
}
|
|
422
|
-
if (!description) {
|
|
423
|
-
throw new Error('Decision description is required');
|
|
424
|
-
}
|
|
425
|
-
let formattedDesc = `## Decision\n${description}`;
|
|
426
|
-
if (rationale) {
|
|
427
|
-
formattedDesc += `\n\n## Rationale\n${rationale}`;
|
|
428
|
-
}
|
|
429
|
-
// 直接以 pinned 状态构建 Task,避免 open→pinned 的幽灵窗口
|
|
430
|
-
const task = new Task({
|
|
431
|
-
title,
|
|
432
|
-
description: formattedDesc,
|
|
433
|
-
taskType: 'decision',
|
|
434
|
-
status: 'pinned',
|
|
435
|
-
priority: 0,
|
|
436
|
-
// C8: 传递普通对象,_entityToRow() 负责 JSON.stringify
|
|
437
|
-
metadata: {
|
|
438
|
-
tags: tags || [],
|
|
439
|
-
source: 'agent-user-agreement',
|
|
440
|
-
rationale: rationale || '',
|
|
441
|
-
recordedAt: new Date().toISOString(),
|
|
442
|
-
},
|
|
443
|
-
});
|
|
444
|
-
task.computeContentHash();
|
|
445
|
-
task.validate();
|
|
446
|
-
// 去重检测(复用 create 的逻辑)
|
|
447
|
-
const duplicate = this.repo.findByContentHash(task.contentHash);
|
|
448
|
-
if (duplicate) {
|
|
449
|
-
return { task: duplicate, isDuplicate: true };
|
|
450
|
-
}
|
|
451
|
-
task.id = this.idGen.generate();
|
|
452
|
-
// 单事务:创建 + 关联依赖
|
|
453
|
-
const saved = this.repo.inTransaction(() => {
|
|
454
|
-
const created = this.repo.create(task);
|
|
455
|
-
if (relatedTaskId) {
|
|
456
|
-
try {
|
|
457
|
-
this.repo.addDependency(created.id, relatedTaskId, 'related');
|
|
458
|
-
}
|
|
459
|
-
catch (err) {
|
|
460
|
-
this.logger.debug('recordDecision: dependency add failed', {
|
|
461
|
-
error: err.message,
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return created;
|
|
466
|
-
});
|
|
467
|
-
this._logEvent(saved.id, 'decision_recorded', null, title);
|
|
468
|
-
return { task: saved, isDuplicate: false };
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* 修订决策 — 原子事务:创建新决策 + 关闭旧决策 + 建立 supersedes 链(C2+C7)
|
|
472
|
-
* @param params { oldDecisionId, title, description, rationale, reason }
|
|
473
|
-
* @returns >}
|
|
474
|
-
*/
|
|
475
|
-
async reviseDecision({ oldDecisionId, title, description, rationale, reason, }) {
|
|
476
|
-
// 事务前验证
|
|
477
|
-
const oldDecision = this.repo.findById(oldDecisionId);
|
|
478
|
-
if (!oldDecision) {
|
|
479
|
-
throw new Error(`Decision not found: ${oldDecisionId}`);
|
|
480
|
-
}
|
|
481
|
-
if (oldDecision.status !== 'pinned') {
|
|
482
|
-
throw new Error(`Can only revise pinned decisions (current: ${oldDecision.status})`);
|
|
483
|
-
}
|
|
484
|
-
let formattedDesc = `## Decision\n${description}`;
|
|
485
|
-
if (rationale) {
|
|
486
|
-
formattedDesc += `\n\n## Rationale\n${rationale}`;
|
|
487
|
-
}
|
|
488
|
-
// 构建新决策 Task
|
|
489
|
-
const newTask = new Task({
|
|
490
|
-
title,
|
|
491
|
-
description: formattedDesc,
|
|
492
|
-
taskType: 'decision',
|
|
493
|
-
status: 'pinned',
|
|
494
|
-
priority: 0,
|
|
495
|
-
metadata: {
|
|
496
|
-
tags: [],
|
|
497
|
-
source: 'agent-user-agreement',
|
|
498
|
-
rationale: rationale || '',
|
|
499
|
-
recordedAt: new Date().toISOString(),
|
|
500
|
-
supersedes: oldDecisionId,
|
|
501
|
-
},
|
|
502
|
-
});
|
|
503
|
-
newTask.computeContentHash();
|
|
504
|
-
newTask.validate();
|
|
505
|
-
newTask.id = this.idGen.generate();
|
|
506
|
-
// 原子事务:创建新决策 + 关闭旧决策 + 建立 supersedes 链
|
|
507
|
-
const newDecision = this.repo.inTransaction(() => {
|
|
508
|
-
const created = this.repo.create(newTask);
|
|
509
|
-
this.repo.update(oldDecisionId, {
|
|
510
|
-
status: 'closed',
|
|
511
|
-
closeReason: `Superseded by ${created.id}: ${reason || 'Revised'}`,
|
|
512
|
-
closedAt: Math.floor(Date.now() / 1000),
|
|
513
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
514
|
-
});
|
|
515
|
-
this.repo.addDependency(created.id, oldDecisionId, 'supersedes');
|
|
516
|
-
return created;
|
|
517
|
-
});
|
|
518
|
-
this._logEvent(oldDecisionId, 'superseded', 'pinned', `by ${newDecision.id}`);
|
|
519
|
-
this._logEvent(newDecision.id, 'supersedes', null, oldDecisionId);
|
|
520
|
-
return { newDecision, oldDecisionId };
|
|
521
|
-
}
|
|
522
|
-
/** 取消固定决策 */
|
|
523
|
-
async unpinDecision(id, reason = '') {
|
|
524
|
-
const task = this.repo.findById(id);
|
|
525
|
-
if (!task) {
|
|
526
|
-
throw new Error(`Decision not found: ${id}`);
|
|
527
|
-
}
|
|
528
|
-
if (task.status !== 'pinned') {
|
|
529
|
-
throw new Error(`Can only unpin pinned decisions (current: ${task.status})`);
|
|
530
|
-
}
|
|
531
|
-
const saved = this.repo.update(id, {
|
|
532
|
-
status: 'closed',
|
|
533
|
-
closeReason: reason || 'Unpinned',
|
|
534
|
-
closedAt: Math.floor(Date.now() / 1000),
|
|
535
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
536
|
-
});
|
|
537
|
-
this._logEvent(id, 'unpinned', 'pinned', reason);
|
|
538
|
-
return saved;
|
|
539
|
-
}
|
|
540
|
-
// ═══ 私有方法 ═══════════════════════════════════════
|
|
541
|
-
/**
|
|
542
|
-
* P2: 获取决策过期阈值(秒)
|
|
543
|
-
* 默认 30 天 = 2592000 秒。可通过容器内 'config' 服务配置。
|
|
544
|
-
* 返回 0 表示禁用过期检测。
|
|
545
|
-
*/
|
|
546
|
-
_getDecisionStaleThreshold() {
|
|
547
|
-
try {
|
|
548
|
-
const _config = this.repo?.db
|
|
549
|
-
? null // 通过构造函数传入的 config 优先
|
|
550
|
-
: null;
|
|
551
|
-
// 暂无 config 注入路径,使用环境变量或硬编码默认值
|
|
552
|
-
const envDays = process.env.ASD_DECISION_STALE_DAYS;
|
|
553
|
-
if (envDays !== undefined) {
|
|
554
|
-
const days = Number.parseInt(envDays, 10);
|
|
555
|
-
if (Number.isFinite(days) && days >= 0) {
|
|
556
|
-
return days * 86400;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return 30 * 86400; // 默认 30 天
|
|
560
|
-
}
|
|
561
|
-
catch {
|
|
562
|
-
return 30 * 86400;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* 查找因 closedTaskId 完成而新解除阻塞的任务
|
|
567
|
-
*/
|
|
568
|
-
_checkNewlyUnblocked(closedTaskId) {
|
|
569
|
-
const dependents = this.repo.getDependents(closedTaskId);
|
|
570
|
-
const newlyReady = [];
|
|
571
|
-
for (const dep of dependents) {
|
|
572
|
-
// 只关注阻塞型依赖
|
|
573
|
-
if (dep.depType !== 'blocks' && dep.depType !== 'waits-for') {
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
// getBlockers 返回"尚未关闭的阻塞者",空 = 全部完成
|
|
577
|
-
const pendingBlockers = this.repo.getBlockers(dep.taskId);
|
|
578
|
-
if (pendingBlockers.length === 0) {
|
|
579
|
-
// 还要检查任务本身状态是 open
|
|
580
|
-
const task = this.repo.findById(dep.taskId);
|
|
581
|
-
if (task && task.status === 'open') {
|
|
582
|
-
newlyReady.push(dep.taskId);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
return newlyReady;
|
|
587
|
-
}
|
|
588
|
-
_logEvent(taskId, eventType, oldValue, newValue) {
|
|
589
|
-
try {
|
|
590
|
-
this.repo.logEvent(taskId, eventType, oldValue, newValue);
|
|
591
|
-
}
|
|
592
|
-
catch (err) {
|
|
593
|
-
this.logger.debug('TaskGraphService._logEvent error', { error: err.message });
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
export default TaskGraphService;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { Task } from '../../domain/task/Task.js';
|
|
2
|
-
import Logger from '../../infrastructure/logging/Logger.js';
|
|
3
|
-
/** 知识注入的上下文选项(从 prime / ready / claim 透传) */
|
|
4
|
-
export interface KnowledgeEnrichOptions {
|
|
5
|
-
/** 用户当前输入(IDE Agent 侧传入) */
|
|
6
|
-
userQuery?: string;
|
|
7
|
-
/** 当前活跃文件路径 */
|
|
8
|
-
activeFile?: string;
|
|
9
|
-
/** 当前编程语言 */
|
|
10
|
-
language?: string;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* TaskKnowledgeBridge — 任务 ↔ 知识桥接服务
|
|
14
|
-
*
|
|
15
|
-
* AutoSnippet 独有能力:返回「带知识上下文的任务」,而非裸任务。
|
|
16
|
-
*
|
|
17
|
-
* 桥接策略(v2 — 用户输入感知 + Multi-Query + 上下文透传 + 缓存):
|
|
18
|
-
* 1. 任务标题/描述 + 用户输入(userQuery) → Multi-Query 搜索知识库
|
|
19
|
-
* 2. 传递 language / intent 上下文信号 → SearchEngine ContextBoost 生效
|
|
20
|
-
* 3. 关联的 Guard 规则 → 优先嵌入任务上下文
|
|
21
|
-
* 4. 任务级缓存 → 避免重复搜索
|
|
22
|
-
*/
|
|
23
|
-
export declare class TaskKnowledgeBridge {
|
|
24
|
-
_search: {
|
|
25
|
-
search: (query: string, options: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
26
|
-
} | null;
|
|
27
|
-
logger: ReturnType<typeof Logger.getInstance>;
|
|
28
|
-
/** 任务级知识缓存 (taskId → CacheEntry) */
|
|
29
|
-
private _cache;
|
|
30
|
-
constructor(searchEngine: {
|
|
31
|
-
search: (query: string, options: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
32
|
-
});
|
|
33
|
-
/**
|
|
34
|
-
* 为就绪任务附加知识上下文
|
|
35
|
-
* 并行搜索,不阻塞主流程
|
|
36
|
-
*
|
|
37
|
-
* @param tasks 需要注入知识的任务列表
|
|
38
|
-
* @param options 上下文选项(userQuery / activeFile / language)
|
|
39
|
-
*/
|
|
40
|
-
enrichWithKnowledge(tasks: Task[], options?: KnowledgeEnrichOptions): Promise<Task[]>;
|
|
41
|
-
/**
|
|
42
|
-
* 独立搜索 — 仅基于 userQuery 搜索知识(不依赖任何 Task)
|
|
43
|
-
*
|
|
44
|
-
* 场景: prime() 时没有 ready tasks 但有用户输入,直接搜索知识库。
|
|
45
|
-
*
|
|
46
|
-
* @param userQuery 用户输入的原始文本
|
|
47
|
-
* @param options 可选的 language
|
|
48
|
-
*/
|
|
49
|
-
searchForQuery(userQuery: string, options?: {
|
|
50
|
-
language?: string;
|
|
51
|
-
}): Promise<Record<string, unknown> | null>;
|
|
52
|
-
/**
|
|
53
|
-
* 为单个任务构建知识上下文(v2 — multi-query + 上下文 + 缓存)
|
|
54
|
-
*/
|
|
55
|
-
private _buildContext;
|
|
56
|
-
/**
|
|
57
|
-
* P2: 构建多条互补搜索查询
|
|
58
|
-
*
|
|
59
|
-
* 策略:
|
|
60
|
-
* Q1 (精确): 任务标题 — 通常最精练
|
|
61
|
-
* Q2 (语义): 用户输入 — 包含更丰富的自然语义
|
|
62
|
-
* Q3 (关键词): 从描述/用户输入提取技术术语
|
|
63
|
-
*
|
|
64
|
-
*/
|
|
65
|
-
private _buildSearchQueries;
|
|
66
|
-
/**
|
|
67
|
-
* P2: 从文本中提取技术术语(类名、文件名、API 名等)
|
|
68
|
-
*/
|
|
69
|
-
private _extractTechTerms;
|
|
70
|
-
/**
|
|
71
|
-
* P2 + P3: Multi-Query 搜索 + 合并去重
|
|
72
|
-
*
|
|
73
|
-
* 对每个 query 执行搜索(并行),合并结果并按 score 去重保留最高分。
|
|
74
|
-
*/
|
|
75
|
-
private _multiQuerySearch;
|
|
76
|
-
/**
|
|
77
|
-
* 执行单次搜索(含 P3 上下文透传)
|
|
78
|
-
*/
|
|
79
|
-
private _singleSearch;
|
|
80
|
-
/**
|
|
81
|
-
* P4: 相关性阈值判断
|
|
82
|
-
*/
|
|
83
|
-
private _aboveThreshold;
|
|
84
|
-
/**
|
|
85
|
-
* P4: 增强投影 — 使用统一 slimSearchResult() 投影函数
|
|
86
|
-
*/
|
|
87
|
-
private _projectItem;
|
|
88
|
-
/**
|
|
89
|
-
* P6: 缓存键 — 基于 taskQuery + userQuery 的内容指纹
|
|
90
|
-
*/
|
|
91
|
-
private _contentKey;
|
|
92
|
-
/** 清除全部缓存(测试 / 索引重建后使用) */
|
|
93
|
-
clearCache(): void;
|
|
94
|
-
}
|
|
95
|
-
export default TaskKnowledgeBridge;
|