autosnippet 3.2.21 → 3.3.2
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 -1
- package/dist/bin/cli.js +244 -261
- 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/SetupService.d.ts +46 -2
- package/dist/lib/cli/SetupService.js +2 -27
- package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
- package/dist/lib/cli/deploy/FileManifest.js +0 -11
- package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.d.ts +2 -5
- package/dist/lib/{platform/ios/spm → core/discovery}/SpmDiscoverer.js +159 -44
- package/dist/lib/core/discovery/index.d.ts +1 -1
- package/dist/lib/core/discovery/index.js +2 -2
- 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/consolidated.d.ts +116 -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 +245 -8
- 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 +217 -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 +14 -20
- package/dist/lib/external/mcp/tools.js +62 -91
- package/dist/lib/http/HttpServer.js +52 -6
- package/dist/lib/http/routes/{snippets.d.ts → audit.d.ts} +4 -2
- package/dist/lib/http/routes/audit.js +51 -0
- package/dist/lib/http/routes/commands.d.ts +1 -1
- package/dist/lib/http/routes/commands.js +1 -66
- 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/remote.js +0 -5
- 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 +181 -583
- package/dist/lib/infrastructure/database/drizzle/schema.js +28 -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/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/injection/ServiceContainer.js +6 -0
- package/dist/lib/injection/ServiceMap.d.ts +16 -19
- 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 +3 -4
- package/dist/lib/injection/modules/AppModule.js +7 -43
- package/dist/lib/injection/modules/GuardModule.js +59 -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.js +51 -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/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 +55 -1
- package/dist/lib/service/guard/GuardCheckEngine.js +508 -15
- 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/module/ModuleService.js +3 -13
- 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 +108 -0
- package/dist/lib/service/panorama/PanoramaService.js +220 -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/MultiSignalRanker.d.ts +1 -0
- package/dist/lib/service/search/MultiSignalRanker.js +16 -0
- package/dist/lib/service/search/SearchEngine.d.ts +1 -0
- package/dist/lib/service/search/SearchEngine.js +9 -1
- package/dist/lib/service/search/SearchTypes.d.ts +2 -0
- 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 +58 -0
- package/dist/lib/service/task/IntentExtractor.js +142 -0
- package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
- package/dist/lib/service/task/PrimeSearchPipeline.js +98 -0
- package/dist/lib/shared/constants.d.ts +0 -15
- package/dist/lib/shared/constants.js +0 -10
- package/dist/lib/shared/schemas/config.d.ts +4 -1
- package/dist/lib/shared/schemas/config.js +8 -1
- 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/dist/scripts/release.js +2 -10
- package/package.json +4 -19
- package/skills/autosnippet-devdocs/SKILL.md +11 -8
- package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
- package/templates/cursor-hooks/hooks/session-start.sh +1 -1
- package/templates/instructions/agent-static.md +2 -1
- package/templates/instructions/conventions.md +5 -6
- package/templates/recipes-setup/README.md +1 -2
- package/dashboard/dist/assets/icons-C1dUryS-.js +0 -1
- package/dashboard/dist/assets/index-D0whuycy.css +0 -1
- package/dashboard/dist/assets/index-DdvZE4Yd.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/http/routes/snippets.js +0 -49
- 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/platform/ClipboardManager.d.ts +0 -24
- package/dist/lib/platform/ClipboardManager.js +0 -142
- package/dist/lib/platform/NativeUi.d.ts +0 -53
- package/dist/lib/platform/NativeUi.js +0 -284
- package/dist/lib/platform/ios/index.d.ts +0 -38
- package/dist/lib/platform/ios/index.js +0 -42
- package/dist/lib/platform/ios/routes/spm.d.ts +0 -9
- package/dist/lib/platform/ios/routes/spm.js +0 -371
- package/dist/lib/platform/ios/snippet/PlaceholderConverter.d.ts +0 -21
- package/dist/lib/platform/ios/snippet/PlaceholderConverter.js +0 -48
- package/dist/lib/platform/ios/snippet/XcodeCodec.d.ts +0 -23
- package/dist/lib/platform/ios/snippet/XcodeCodec.js +0 -96
- package/dist/lib/platform/ios/spm/DependencyGraph.d.ts +0 -56
- package/dist/lib/platform/ios/spm/DependencyGraph.js +0 -195
- package/dist/lib/platform/ios/spm/PackageSwiftParser.d.ts +0 -69
- package/dist/lib/platform/ios/spm/PackageSwiftParser.js +0 -231
- package/dist/lib/platform/ios/spm/PathFinder.d.ts +0 -28
- package/dist/lib/platform/ios/spm/PathFinder.js +0 -117
- package/dist/lib/platform/ios/spm/PolicyEngine.d.ts +0 -44
- package/dist/lib/platform/ios/spm/PolicyEngine.js +0 -79
- package/dist/lib/platform/ios/spm/SpmHelper.d.ts +0 -102
- package/dist/lib/platform/ios/spm/SpmHelper.js +0 -464
- package/dist/lib/platform/ios/xcode/HeaderResolver.d.ts +0 -33
- package/dist/lib/platform/ios/xcode/HeaderResolver.js +0 -90
- package/dist/lib/platform/ios/xcode/SaveEventFilter.d.ts +0 -66
- package/dist/lib/platform/ios/xcode/SaveEventFilter.js +0 -142
- package/dist/lib/platform/ios/xcode/XcodeAutomation.d.ts +0 -71
- package/dist/lib/platform/ios/xcode/XcodeAutomation.js +0 -327
- package/dist/lib/platform/ios/xcode/XcodeImportResolver.d.ts +0 -130
- package/dist/lib/platform/ios/xcode/XcodeImportResolver.js +0 -404
- package/dist/lib/platform/ios/xcode/XcodeIntegration.d.ts +0 -89
- package/dist/lib/platform/ios/xcode/XcodeIntegration.js +0 -588
- package/dist/lib/platform/ios/xcode/XcodeWriteUtils.d.ts +0 -99
- package/dist/lib/platform/ios/xcode/XcodeWriteUtils.js +0 -190
- 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/automation/ActionPipeline.d.ts +0 -34
- package/dist/lib/service/automation/ActionPipeline.js +0 -53
- package/dist/lib/service/automation/AutomationOrchestrator.d.ts +0 -86
- package/dist/lib/service/automation/AutomationOrchestrator.js +0 -57
- package/dist/lib/service/automation/ContextCollector.d.ts +0 -24
- package/dist/lib/service/automation/ContextCollector.js +0 -35
- package/dist/lib/service/automation/DirectiveDetector.d.ts +0 -51
- package/dist/lib/service/automation/DirectiveDetector.js +0 -112
- package/dist/lib/service/automation/FileWatcher.d.ts +0 -51
- package/dist/lib/service/automation/FileWatcher.js +0 -366
- package/dist/lib/service/automation/TriggerResolver.d.ts +0 -36
- package/dist/lib/service/automation/TriggerResolver.js +0 -62
- package/dist/lib/service/automation/handlers/AlinkHandler.d.ts +0 -7
- package/dist/lib/service/automation/handlers/AlinkHandler.js +0 -80
- package/dist/lib/service/automation/handlers/CreateHandler.d.ts +0 -11
- package/dist/lib/service/automation/handlers/CreateHandler.js +0 -170
- package/dist/lib/service/automation/handlers/GuardHandler.d.ts +0 -17
- package/dist/lib/service/automation/handlers/GuardHandler.js +0 -218
- package/dist/lib/service/automation/handlers/HeaderHandler.d.ts +0 -2
- package/dist/lib/service/automation/handlers/HeaderHandler.js +0 -32
- package/dist/lib/service/automation/handlers/SearchHandler.d.ts +0 -11
- package/dist/lib/service/automation/handlers/SearchHandler.js +0 -278
- package/dist/lib/service/snippet/SnippetFactory.d.ts +0 -101
- package/dist/lib/service/snippet/SnippetFactory.js +0 -145
- package/dist/lib/service/snippet/SnippetInstaller.d.ts +0 -91
- package/dist/lib/service/snippet/SnippetInstaller.js +0 -276
- package/dist/lib/service/snippet/codecs/SnippetCodec.d.ts +0 -44
- package/dist/lib/service/snippet/codecs/SnippetCodec.js +0 -35
- package/dist/lib/service/snippet/codecs/VSCodeCodec.d.ts +0 -27
- package/dist/lib/service/snippet/codecs/VSCodeCodec.js +0 -82
- 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
- package/dist/scripts/build-native-ui.d.ts +0 -3
- package/dist/scripts/build-native-ui.js +0 -62
- package/dist/scripts/init-snippets.d.ts +0 -30
- package/dist/scripts/init-snippets.js +0 -298
- package/dist/scripts/install-full.d.ts +0 -7
- package/dist/scripts/install-full.js +0 -38
- package/resources/native-ui/README.md +0 -29
- package/resources/native-ui/combined-window.swift +0 -494
- package/resources/native-ui/main.swift +0 -598
- package/scripts/postinstall-safe.mjs +0 -89
|
@@ -1,151 +1,179 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Handler — autosnippet_task (
|
|
2
|
+
* MCP Handler — autosnippet_task (Intent Lifecycle + Signal Collection)
|
|
3
3
|
*
|
|
4
|
-
* Operations:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* 5 Operations:
|
|
5
|
+
* prime — Load knowledge context + initialize intent
|
|
6
|
+
* create — Create in-memory task anchor (generates ID)
|
|
7
|
+
* close — Complete task + persist intent chain + trigger Guard
|
|
8
|
+
* fail — Abandon task + persist intent chain
|
|
9
|
+
* record_decision — Record user preference signal
|
|
10
|
+
*
|
|
11
|
+
* Architecture: Zero DB. Pure memory (IntentState) + SignalBus → JSONL signals.
|
|
9
12
|
*/
|
|
13
|
+
import { notifyTaskProgress } from '#infra/notification/LarkNotifier.js';
|
|
14
|
+
import { extract as extractIntent } from '#service/task/IntentExtractor.js';
|
|
10
15
|
import { envelope } from '../envelope.js';
|
|
16
|
+
import { createIdleIntent } from './types.js';
|
|
17
|
+
// ─── In-memory task ID counter ───────────────────────────
|
|
18
|
+
let _taskCounter = 0;
|
|
19
|
+
function _generateTaskId() {
|
|
20
|
+
_taskCounter++;
|
|
21
|
+
return `asd-${Date.now().toString(36)}-${_taskCounter}`;
|
|
22
|
+
}
|
|
23
|
+
// ─── Task Rules Reminder ─────────────────────────────────
|
|
24
|
+
const _taskRules = {
|
|
25
|
+
reminder: [
|
|
26
|
+
'📋 TASK RULES (MANDATORY):',
|
|
27
|
+
'🔑 YOU are the task operator — user speaks naturally, you translate to task operations.',
|
|
28
|
+
'• MUST prime on EVERY message BEFORE anything else',
|
|
29
|
+
'• MUST create task for non-trivial work (≥2 files OR ≥10 lines)',
|
|
30
|
+
'• MUST close when done with meaningful reason',
|
|
31
|
+
'• When user agrees/disagrees → record_decision immediately',
|
|
32
|
+
'• NEVER tell user to run task commands',
|
|
33
|
+
].join('\n'),
|
|
34
|
+
translationHint: [
|
|
35
|
+
'User Says → You Run:',
|
|
36
|
+
'"fix bug"/"implement" → create→code→close',
|
|
37
|
+
'"continue" → resume in-progress→close',
|
|
38
|
+
'"pause"/"abandon" → fail(id, reason)',
|
|
39
|
+
'"agreed"/"disagree" → record_decision',
|
|
40
|
+
'Quick question → No task. Just answer.',
|
|
41
|
+
].join('\n'),
|
|
42
|
+
};
|
|
11
43
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @param ctx { container }
|
|
14
|
-
* @param args { operation, ...params }
|
|
44
|
+
* Unified entry point
|
|
15
45
|
*/
|
|
16
46
|
export async function taskHandler(ctx, args) {
|
|
17
|
-
const taskService = ctx.container.get('taskGraphService');
|
|
18
47
|
let result;
|
|
19
48
|
switch (args.operation) {
|
|
20
|
-
// ── Session ──
|
|
21
49
|
case 'prime':
|
|
22
|
-
return _prime(
|
|
23
|
-
// ── Task CRUD ──
|
|
50
|
+
return _prime(ctx, args);
|
|
24
51
|
case 'create':
|
|
25
|
-
result = await _create(
|
|
26
|
-
break;
|
|
27
|
-
case 'ready':
|
|
28
|
-
return _ready(taskService, args);
|
|
29
|
-
case 'claim':
|
|
30
|
-
result = await _claim(taskService, args);
|
|
52
|
+
result = await _create(ctx, args);
|
|
31
53
|
break;
|
|
32
54
|
case 'close':
|
|
33
|
-
result = await _close(ctx,
|
|
55
|
+
result = await _close(ctx, args);
|
|
34
56
|
break;
|
|
35
57
|
case 'fail':
|
|
36
|
-
result = await _fail(
|
|
37
|
-
break;
|
|
38
|
-
case 'defer':
|
|
39
|
-
result = await _defer(taskService, args);
|
|
58
|
+
result = await _fail(ctx, args);
|
|
40
59
|
break;
|
|
41
|
-
case 'progress':
|
|
42
|
-
result = await _progress(taskService, args);
|
|
43
|
-
break;
|
|
44
|
-
case 'decompose':
|
|
45
|
-
result = await _decompose(taskService, args);
|
|
46
|
-
break;
|
|
47
|
-
case 'show':
|
|
48
|
-
return _show(taskService, args);
|
|
49
|
-
case 'list':
|
|
50
|
-
return _list(taskService, args);
|
|
51
|
-
case 'blocked':
|
|
52
|
-
return _blocked(taskService);
|
|
53
|
-
case 'dep_add':
|
|
54
|
-
return _depAdd(taskService, args);
|
|
55
|
-
case 'dep_tree':
|
|
56
|
-
return _depTree(taskService, args);
|
|
57
|
-
case 'stats':
|
|
58
|
-
return _stats(taskService);
|
|
59
|
-
// ── Decisions ──
|
|
60
60
|
case 'record_decision':
|
|
61
|
-
result = await _recordDecision(
|
|
62
|
-
break;
|
|
63
|
-
case 'revise_decision':
|
|
64
|
-
result = await _reviseDecision(taskService, args);
|
|
65
|
-
break;
|
|
66
|
-
case 'unpin_decision':
|
|
67
|
-
result = await _unpinDecision(taskService, args);
|
|
61
|
+
result = await _recordDecision(ctx, args);
|
|
68
62
|
break;
|
|
69
|
-
case 'list_decisions':
|
|
70
|
-
return _listDecisions(taskService);
|
|
71
63
|
default:
|
|
72
64
|
return envelope({
|
|
73
65
|
success: false,
|
|
74
|
-
message: `Unknown operation: ${args.operation}. Valid: prime,
|
|
66
|
+
message: `Unknown operation: ${args.operation}. Valid: prime, create, close, fail, record_decision.`,
|
|
75
67
|
meta: { tool: 'autosnippet_task' },
|
|
76
68
|
});
|
|
77
69
|
}
|
|
78
|
-
// ──
|
|
79
|
-
|
|
80
|
-
process.stderr.write(`[MCP/Task] Notify error: ${err
|
|
70
|
+
// ── Lark notification (async, non-blocking) ──
|
|
71
|
+
notifyTaskProgress(args.operation, args, result).catch((err) => {
|
|
72
|
+
process.stderr.write(`[MCP/Task] Notify error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
81
73
|
});
|
|
82
74
|
return result;
|
|
83
75
|
}
|
|
84
|
-
//
|
|
85
|
-
async function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
76
|
+
// ═══ prime ═══════════════════════════════════════════════
|
|
77
|
+
async function _prime(ctx, args) {
|
|
78
|
+
const intent = ctx.session?.intent;
|
|
79
|
+
// If there is an active intent, persist it as abandoned before starting fresh
|
|
80
|
+
if (intent && intent.phase === 'active') {
|
|
81
|
+
_persistIntentChain(ctx, intent, 'abandoned', 'New prime received');
|
|
82
|
+
}
|
|
83
|
+
// ─── Intake: extract intent signals ───
|
|
84
|
+
const extracted = extractIntent(args.userQuery || '', args.activeFile, args.language);
|
|
85
|
+
// ─── Enrichment: multi-query search via PrimeSearchPipeline ───
|
|
86
|
+
const pipeline = _getPipeline(ctx.container);
|
|
87
|
+
let searchResult = null;
|
|
88
|
+
if (pipeline && extracted.queries[0]?.trim()) {
|
|
89
|
+
try {
|
|
90
|
+
searchResult = await pipeline.search(extracted);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// search failure is non-fatal
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ─── Lifecycle: initialize IntentState ───
|
|
97
|
+
const freshIntent = createIdleIntent();
|
|
98
|
+
freshIntent.phase = 'active';
|
|
99
|
+
freshIntent.primeQuery = args.userQuery || '';
|
|
100
|
+
freshIntent.primeActiveFile = args.activeFile;
|
|
101
|
+
freshIntent.primeLanguage = extracted.language;
|
|
102
|
+
freshIntent.primeModule = extracted.module;
|
|
103
|
+
freshIntent.primeScenario = extracted.scenario;
|
|
104
|
+
freshIntent.primeAt = Date.now();
|
|
105
|
+
if (searchResult) {
|
|
106
|
+
freshIntent.primeRecipeIds = [...searchResult.relatedKnowledge, ...searchResult.guardRules]
|
|
107
|
+
.map((r) => r.id)
|
|
108
|
+
.filter(Boolean);
|
|
109
|
+
freshIntent.searchMeta = {
|
|
110
|
+
queries: searchResult.searchMeta.queries,
|
|
111
|
+
resultCount: searchResult.searchMeta.resultCount,
|
|
112
|
+
filteredCount: searchResult.searchMeta.filteredCount,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Bind intent to session
|
|
116
|
+
if (ctx.session) {
|
|
117
|
+
ctx.session.intent = freshIntent;
|
|
118
|
+
}
|
|
119
|
+
// ─── Delivery: build response ───
|
|
120
|
+
const relatedCount = searchResult?.relatedKnowledge.length ?? 0;
|
|
121
|
+
const ruleCount = searchResult?.guardRules.length ?? 0;
|
|
122
|
+
const lines = [];
|
|
123
|
+
if (relatedCount > 0 || ruleCount > 0) {
|
|
124
|
+
lines.push(`📋 Found ${relatedCount} recipe(s), ${ruleCount} guard rule(s).`);
|
|
125
|
+
for (const r of searchResult.relatedKnowledge) {
|
|
126
|
+
const hint = r.actionHint ? ` — ${r.actionHint}` : '';
|
|
127
|
+
lines.push(` • ${r.trigger || r.title}${hint}`);
|
|
128
|
+
}
|
|
129
|
+
for (const r of searchResult.guardRules) {
|
|
130
|
+
lines.push(` • [rule] ${r.trigger || r.title}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
lines.push('No matching recipes found.');
|
|
92
135
|
}
|
|
93
|
-
const { task, isDuplicate } = await svc.create({
|
|
94
|
-
title: args.title,
|
|
95
|
-
description: args.description || '',
|
|
96
|
-
design: args.design || '',
|
|
97
|
-
acceptance: args.acceptance || '',
|
|
98
|
-
priority: args.priority ?? 2,
|
|
99
|
-
taskType: args.taskType || 'task',
|
|
100
|
-
parentId: args.parentId || null,
|
|
101
|
-
});
|
|
102
|
-
return envelope({
|
|
103
|
-
success: true,
|
|
104
|
-
data: task.toJSON(),
|
|
105
|
-
message: isDuplicate
|
|
106
|
-
? `⚠ Duplicate detected: ${task.id} already exists`
|
|
107
|
-
: `Created ${task.id}: ${task.title}`,
|
|
108
|
-
meta: { tool: 'autosnippet_task' },
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
// ── ready ──
|
|
112
|
-
async function _ready(svc, args) {
|
|
113
|
-
const tasks = await svc.ready({
|
|
114
|
-
limit: args.limit || 10,
|
|
115
|
-
withKnowledge: args.withKnowledge !== false,
|
|
116
|
-
userQuery: args.userQuery,
|
|
117
|
-
activeFile: args.activeFile,
|
|
118
|
-
language: args.language,
|
|
119
|
-
});
|
|
120
136
|
return envelope({
|
|
121
137
|
success: true,
|
|
122
|
-
data:
|
|
123
|
-
|
|
138
|
+
data: {
|
|
139
|
+
knowledge: searchResult
|
|
140
|
+
? {
|
|
141
|
+
relatedKnowledge: searchResult.relatedKnowledge,
|
|
142
|
+
guardRules: searchResult.guardRules,
|
|
143
|
+
}
|
|
144
|
+
: null,
|
|
145
|
+
searchMeta: searchResult?.searchMeta ?? null,
|
|
146
|
+
_taskRules,
|
|
147
|
+
},
|
|
148
|
+
message: lines.join('\n'),
|
|
124
149
|
meta: { tool: 'autosnippet_task' },
|
|
125
150
|
});
|
|
126
151
|
}
|
|
127
|
-
//
|
|
128
|
-
async function
|
|
129
|
-
if (!args.
|
|
152
|
+
// ═══ create ═════════════════════════════════════════════
|
|
153
|
+
async function _create(ctx, args) {
|
|
154
|
+
if (!args.title) {
|
|
130
155
|
return envelope({
|
|
131
156
|
success: false,
|
|
132
|
-
message: '
|
|
157
|
+
message: 'title is required',
|
|
133
158
|
meta: { tool: 'autosnippet_task' },
|
|
134
159
|
});
|
|
135
160
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
161
|
+
const taskId = _generateTaskId();
|
|
162
|
+
const intent = ctx.session?.intent;
|
|
163
|
+
// Bind task ID to current intent
|
|
164
|
+
if (intent && intent.phase === 'active') {
|
|
165
|
+
intent.taskId = taskId;
|
|
166
|
+
intent.taskTitle = args.title;
|
|
167
|
+
}
|
|
140
168
|
return envelope({
|
|
141
169
|
success: true,
|
|
142
|
-
data:
|
|
143
|
-
message:
|
|
170
|
+
data: { id: taskId, title: args.title },
|
|
171
|
+
message: `📌 Created: ${taskId} — ${args.title}`,
|
|
144
172
|
meta: { tool: 'autosnippet_task' },
|
|
145
173
|
});
|
|
146
174
|
}
|
|
147
|
-
//
|
|
148
|
-
async function _close(ctx,
|
|
175
|
+
// ═══ close ══════════════════════════════════════════════
|
|
176
|
+
async function _close(ctx, args) {
|
|
149
177
|
if (!args.id) {
|
|
150
178
|
return envelope({
|
|
151
179
|
success: false,
|
|
@@ -153,21 +181,23 @@ async function _close(ctx, svc, args) {
|
|
|
153
181
|
meta: { tool: 'autosnippet_task' },
|
|
154
182
|
});
|
|
155
183
|
}
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
184
|
+
const intent = ctx.session?.intent;
|
|
185
|
+
const reason = args.reason || 'Completed';
|
|
186
|
+
// Persist intent chain via SignalBus
|
|
187
|
+
if (intent && intent.phase === 'active') {
|
|
188
|
+
_persistIntentChain(ctx, intent, 'completed', reason);
|
|
160
189
|
}
|
|
161
|
-
|
|
162
|
-
|
|
190
|
+
// Reset intent to idle
|
|
191
|
+
if (ctx.session) {
|
|
192
|
+
ctx.session.intent = createIdleIntent();
|
|
163
193
|
}
|
|
194
|
+
const lines = [`✅ Closed: ${args.id} — ${reason}`];
|
|
164
195
|
lines.push('');
|
|
165
|
-
lines.push('⚠️ REQUIRED: You MUST call autosnippet_guard (no args) NOW to review changed files for compliance violations.
|
|
196
|
+
lines.push('⚠️ REQUIRED: You MUST call autosnippet_guard (no args) NOW to review changed files for compliance violations.');
|
|
166
197
|
return envelope({
|
|
167
198
|
success: true,
|
|
168
199
|
data: {
|
|
169
|
-
closed:
|
|
170
|
-
newlyReady,
|
|
200
|
+
closed: { id: args.id, reason, closedAt: Date.now() },
|
|
171
201
|
nextAction: {
|
|
172
202
|
tool: 'autosnippet_guard',
|
|
173
203
|
args: {},
|
|
@@ -179,150 +209,8 @@ async function _close(ctx, svc, args) {
|
|
|
179
209
|
meta: { tool: 'autosnippet_task' },
|
|
180
210
|
});
|
|
181
211
|
}
|
|
182
|
-
//
|
|
183
|
-
async function _fail(
|
|
184
|
-
if (!args.id) {
|
|
185
|
-
return envelope({
|
|
186
|
-
success: false,
|
|
187
|
-
message: 'id is required',
|
|
188
|
-
meta: { tool: 'autosnippet_task' },
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
const task = await svc.fail(args.id, args.reason || 'Agent execution failed');
|
|
192
|
-
return envelope({
|
|
193
|
-
success: true,
|
|
194
|
-
data: task.toJSON(),
|
|
195
|
-
message: `Failed ${args.id} (attempt #${task.failCount}): ${task.lastFailReason}`,
|
|
196
|
-
meta: { tool: 'autosnippet_task' },
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
// ── defer ──
|
|
200
|
-
async function _defer(svc, args) {
|
|
201
|
-
if (!args.id) {
|
|
202
|
-
return envelope({
|
|
203
|
-
success: false,
|
|
204
|
-
message: 'id is required',
|
|
205
|
-
meta: { tool: 'autosnippet_task' },
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
const task = await svc.defer(args.id, args.reason || '');
|
|
209
|
-
return envelope({
|
|
210
|
-
success: true,
|
|
211
|
-
data: task.toJSON(),
|
|
212
|
-
message: `Deferred ${args.id}`,
|
|
213
|
-
meta: { tool: 'autosnippet_task' },
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
// ── progress ──
|
|
217
|
-
async function _progress(svc, args) {
|
|
218
|
-
if (!args.id) {
|
|
219
|
-
return envelope({
|
|
220
|
-
success: false,
|
|
221
|
-
message: 'id is required',
|
|
222
|
-
meta: { tool: 'autosnippet_task' },
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
const note = args.reason || args.description || '';
|
|
226
|
-
const task = await svc.progress(args.id, note);
|
|
227
|
-
return envelope({
|
|
228
|
-
success: true,
|
|
229
|
-
data: task.toJSON(),
|
|
230
|
-
message: `Progress updated for ${args.id}`,
|
|
231
|
-
meta: { tool: 'autosnippet_task' },
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
// ── decompose ──
|
|
235
|
-
async function _decompose(svc, args) {
|
|
236
|
-
if (!args.id) {
|
|
237
|
-
return envelope({
|
|
238
|
-
success: false,
|
|
239
|
-
message: 'Epic id is required',
|
|
240
|
-
meta: { tool: 'autosnippet_task' },
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
if (!args.subtasks || !Array.isArray(args.subtasks) || args.subtasks.length === 0) {
|
|
244
|
-
return envelope({
|
|
245
|
-
success: false,
|
|
246
|
-
message: 'subtasks array is required',
|
|
247
|
-
meta: { tool: 'autosnippet_task' },
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
const tasks = await svc.decompose(args.id, args.subtasks);
|
|
251
|
-
return envelope({
|
|
252
|
-
success: true,
|
|
253
|
-
data: tasks.map((t) => (t.toJSON ? t.toJSON() : t)),
|
|
254
|
-
message: `Decomposed ${args.id} into ${tasks.length} subtasks`,
|
|
255
|
-
meta: { tool: 'autosnippet_task' },
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
// ── show ──
|
|
259
|
-
async function _show(svc, args) {
|
|
260
|
-
if (!args.id) {
|
|
261
|
-
return envelope({
|
|
262
|
-
success: false,
|
|
263
|
-
message: 'id is required',
|
|
264
|
-
meta: { tool: 'autosnippet_task' },
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
const task = await svc.show(args.id);
|
|
268
|
-
if (!task) {
|
|
269
|
-
return envelope({
|
|
270
|
-
success: false,
|
|
271
|
-
message: `Task not found: ${args.id}`,
|
|
272
|
-
meta: { tool: 'autosnippet_task' },
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
return envelope({
|
|
276
|
-
success: true,
|
|
277
|
-
data: task.toJSON(),
|
|
278
|
-
meta: { tool: 'autosnippet_task' },
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
// ── list ──
|
|
282
|
-
async function _list(svc, args) {
|
|
283
|
-
const filters = {};
|
|
284
|
-
if (args.status) {
|
|
285
|
-
filters.status = args.status;
|
|
286
|
-
}
|
|
287
|
-
if (args.taskType) {
|
|
288
|
-
filters.taskType = args.taskType;
|
|
289
|
-
}
|
|
290
|
-
const tasks = await svc.list(filters, { limit: args.limit || 20 });
|
|
291
|
-
return envelope({
|
|
292
|
-
success: true,
|
|
293
|
-
data: tasks.map((t) => t.toJSON()),
|
|
294
|
-
message: `${tasks.length} task(s)`,
|
|
295
|
-
meta: { tool: 'autosnippet_task' },
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
// ── blocked ──
|
|
299
|
-
async function _blocked(svc) {
|
|
300
|
-
const tasks = await svc.blocked();
|
|
301
|
-
return envelope({
|
|
302
|
-
success: true,
|
|
303
|
-
data: tasks,
|
|
304
|
-
message: `${tasks.length} blocked task(s)`,
|
|
305
|
-
meta: { tool: 'autosnippet_task' },
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
// ── dep_add ──
|
|
309
|
-
async function _depAdd(svc, args) {
|
|
310
|
-
if (!args.id || !args.dependsOn) {
|
|
311
|
-
return envelope({
|
|
312
|
-
success: false,
|
|
313
|
-
message: 'id and dependsOn are required',
|
|
314
|
-
meta: { tool: 'autosnippet_task' },
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
await svc.addDependency(args.id, args.dependsOn, args.depType || 'blocks');
|
|
318
|
-
return envelope({
|
|
319
|
-
success: true,
|
|
320
|
-
message: `${args.id} ${args.depType || 'blocks'} ${args.dependsOn}`,
|
|
321
|
-
meta: { tool: 'autosnippet_task' },
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
// ── dep_tree ──
|
|
325
|
-
async function _depTree(svc, args) {
|
|
212
|
+
// ═══ fail ═══════════════════════════════════════════════
|
|
213
|
+
async function _fail(ctx, args) {
|
|
326
214
|
if (!args.id) {
|
|
327
215
|
return envelope({
|
|
328
216
|
success: false,
|
|
@@ -330,104 +218,27 @@ async function _depTree(svc, args) {
|
|
|
330
218
|
meta: { tool: 'autosnippet_task' },
|
|
331
219
|
});
|
|
332
220
|
}
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
meta: { tool: 'autosnippet_task' },
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
// ── stats ──
|
|
342
|
-
async function _stats(svc) {
|
|
343
|
-
const stats = await svc.stats();
|
|
344
|
-
return envelope({
|
|
345
|
-
success: true,
|
|
346
|
-
data: stats,
|
|
347
|
-
meta: { tool: 'autosnippet_task' },
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
// ═══ Session (prime) ═══════════════════════════════════
|
|
351
|
-
async function _prime(svc, args) {
|
|
352
|
-
const result = await svc.prime({
|
|
353
|
-
limit: args.limit || 10,
|
|
354
|
-
withKnowledge: args.withKnowledge !== false,
|
|
355
|
-
userQuery: args.userQuery,
|
|
356
|
-
activeFile: args.activeFile,
|
|
357
|
-
language: args.language,
|
|
358
|
-
});
|
|
359
|
-
const decisionCount = (result.decisions || []).length;
|
|
360
|
-
const staleCount = (result.staleDecisions || []).length;
|
|
361
|
-
const decisionTitles = (result.decisions || []).map((d) => d.title).join('; ');
|
|
362
|
-
const statsLine = `${result.inProgress.length} in-progress, ${result.ready.length} ready, ${result.stats.total} total`;
|
|
363
|
-
// ── Behavioral Rules Reminder (survives compaction) ──
|
|
364
|
-
result._taskRules = {
|
|
365
|
-
reminder: [
|
|
366
|
-
'📋 TASK RULES (MANDATORY):',
|
|
367
|
-
'🔑 YOU are the task operator — user speaks naturally, you translate to task operations. NEVER tell user to run task commands.',
|
|
368
|
-
'• MUST prime on EVERY message BEFORE anything else',
|
|
369
|
-
'• MUST create task for non-trivial work (≥2 files OR ≥10 lines)',
|
|
370
|
-
'• MUST claim before coding, close when done with meaningful reason',
|
|
371
|
-
'• MUST handle unfinished tasks before starting new work (ask user: Continue/Defer/Abandon)',
|
|
372
|
-
'• NEVER skip prime, NEVER start new work with open in_progress tasks',
|
|
373
|
-
'• NEVER leave tasks in in_progress when session ends — close or defer ALL',
|
|
374
|
-
'• When in doubt → create a task. When idle → ready()',
|
|
375
|
-
'• Session end → close all tasks, defer incomplete, verify zero in_progress',
|
|
376
|
-
].join('\n'),
|
|
377
|
-
translationHint: [
|
|
378
|
-
'User Says → You Run:',
|
|
379
|
-
'"fix bug"/"implement" → create→claim→code→close',
|
|
380
|
-
'"continue" → resume in-progress→close',
|
|
381
|
-
'"pause" → defer | "abandon" → fail | "break down" → decompose',
|
|
382
|
-
'"what\'s next" → ready() | "agreed" → record_decision',
|
|
383
|
-
'Quick question → No task. Just answer.',
|
|
384
|
-
].join('\n'),
|
|
385
|
-
};
|
|
386
|
-
let message;
|
|
387
|
-
if (decisionCount > 0) {
|
|
388
|
-
const stalePart = staleCount > 0 ? ` ${staleCount} stale.` : '';
|
|
389
|
-
message = `⚠️ ${decisionCount} ACTIVE DECISION(S): [${decisionTitles}].${stalePart} ${statsLine}.`;
|
|
221
|
+
const intent = ctx.session?.intent;
|
|
222
|
+
const reason = args.reason || 'Agent execution failed';
|
|
223
|
+
// Persist intent chain via SignalBus
|
|
224
|
+
if (intent && intent.phase === 'active') {
|
|
225
|
+
_persistIntentChain(ctx, intent, 'failed', reason);
|
|
390
226
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
// ── Resume Prompt: 有 inProgress 任务时,提示 Agent 让用户选择 ──
|
|
395
|
-
if (result.inProgress.length > 0) {
|
|
396
|
-
const taskList = result.inProgress
|
|
397
|
-
.map((t) => {
|
|
398
|
-
const age = t.updatedAt
|
|
399
|
-
? `${Math.floor((Date.now() / 1000 - t.updatedAt) / 86400)}d ago`
|
|
400
|
-
: '';
|
|
401
|
-
return `• **${t.id}** — ${t.title}${age ? ` (${age})` : ''}`;
|
|
402
|
-
})
|
|
403
|
-
.join('\n');
|
|
404
|
-
result._resumePrompt = {
|
|
405
|
-
instruction: [
|
|
406
|
-
'There are unfinished tasks. You MUST present these options to the user BEFORE doing anything else:',
|
|
407
|
-
'',
|
|
408
|
-
'**Unfinished tasks:**',
|
|
409
|
-
taskList,
|
|
410
|
-
'',
|
|
411
|
-
'Ask the user to choose:',
|
|
412
|
-
'1. **Continue** — resume the unfinished task(s)',
|
|
413
|
-
'2. **Defer** — pause it and work on something else',
|
|
414
|
-
'3. **Abandon** — close/fail it and start fresh',
|
|
415
|
-
'',
|
|
416
|
-
"Wait for the user's answer. Do NOT auto-resume.",
|
|
417
|
-
].join('\n'),
|
|
418
|
-
taskIds: result.inProgress.map((t) => t.id),
|
|
419
|
-
};
|
|
420
|
-
message += ` ⏸️ ${result.inProgress.length} unfinished task(s) — ask user before resuming.`;
|
|
227
|
+
// Reset intent to idle
|
|
228
|
+
if (ctx.session) {
|
|
229
|
+
ctx.session.intent = createIdleIntent();
|
|
421
230
|
}
|
|
422
231
|
return envelope({
|
|
423
232
|
success: true,
|
|
424
|
-
data:
|
|
425
|
-
|
|
233
|
+
data: {
|
|
234
|
+
failed: { id: args.id, reason, failedAt: Date.now() },
|
|
235
|
+
},
|
|
236
|
+
message: `❌ Failed: ${args.id} — ${reason}`,
|
|
426
237
|
meta: { tool: 'autosnippet_task' },
|
|
427
238
|
});
|
|
428
239
|
}
|
|
429
|
-
// ═══
|
|
430
|
-
async function _recordDecision(
|
|
240
|
+
// ═══ record_decision ════════════════════════════════════
|
|
241
|
+
async function _recordDecision(ctx, args) {
|
|
431
242
|
if (!args.title) {
|
|
432
243
|
return envelope({
|
|
433
244
|
success: false,
|
|
@@ -442,229 +253,78 @@ async function _recordDecision(svc, args) {
|
|
|
442
253
|
meta: { tool: 'autosnippet_task' },
|
|
443
254
|
});
|
|
444
255
|
}
|
|
445
|
-
const
|
|
256
|
+
const decisionId = `dec-${Date.now().toString(36)}`;
|
|
257
|
+
const decision = {
|
|
258
|
+
id: decisionId,
|
|
446
259
|
title: args.title,
|
|
447
260
|
description: args.description,
|
|
448
|
-
rationale: args.rationale
|
|
449
|
-
tags: args.tags
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
? `⚠ Decision already recorded: ${task.id}`
|
|
457
|
-
: `✅ Decision pinned: ${task.id} — "${args.title}"`,
|
|
458
|
-
meta: { tool: 'autosnippet_task' },
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
async function _reviseDecision(svc, args) {
|
|
462
|
-
if (!args.id) {
|
|
463
|
-
return envelope({
|
|
464
|
-
success: false,
|
|
465
|
-
message: 'id of old decision is required',
|
|
466
|
-
meta: { tool: 'autosnippet_task' },
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
if (!args.title) {
|
|
470
|
-
return envelope({
|
|
471
|
-
success: false,
|
|
472
|
-
message: 'title of new decision is required',
|
|
473
|
-
meta: { tool: 'autosnippet_task' },
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
if (!args.description) {
|
|
477
|
-
return envelope({
|
|
478
|
-
success: false,
|
|
479
|
-
message: 'description of new decision is required',
|
|
480
|
-
meta: { tool: 'autosnippet_task' },
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
const result = await svc.reviseDecision({
|
|
484
|
-
oldDecisionId: args.id,
|
|
485
|
-
title: args.title,
|
|
486
|
-
description: args.description,
|
|
487
|
-
rationale: args.rationale || '',
|
|
488
|
-
reason: args.reason || '',
|
|
489
|
-
});
|
|
490
|
-
return envelope({
|
|
491
|
-
success: true,
|
|
492
|
-
data: {
|
|
493
|
-
newDecision: result.newDecision.toJSON(),
|
|
494
|
-
superseded: result.oldDecisionId,
|
|
495
|
-
},
|
|
496
|
-
message: `✅ Decision revised: ${result.oldDecisionId} → ${result.newDecision.id}`,
|
|
497
|
-
meta: { tool: 'autosnippet_task' },
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
async function _unpinDecision(svc, args) {
|
|
501
|
-
if (!args.id) {
|
|
502
|
-
return envelope({
|
|
503
|
-
success: false,
|
|
504
|
-
message: 'id is required',
|
|
505
|
-
meta: { tool: 'autosnippet_task' },
|
|
506
|
-
});
|
|
261
|
+
rationale: args.rationale,
|
|
262
|
+
tags: args.tags,
|
|
263
|
+
recordedAt: Date.now(),
|
|
264
|
+
};
|
|
265
|
+
// Push to current intent's decisions
|
|
266
|
+
const intent = ctx.session?.intent;
|
|
267
|
+
if (intent && intent.phase === 'active') {
|
|
268
|
+
intent.decisions.push(decision);
|
|
507
269
|
}
|
|
508
|
-
const task = await svc.unpinDecision(args.id, args.reason || '');
|
|
509
|
-
return envelope({
|
|
510
|
-
success: true,
|
|
511
|
-
data: task.toJSON(),
|
|
512
|
-
message: `Decision ${args.id} unpinned and closed`,
|
|
513
|
-
meta: { tool: 'autosnippet_task' },
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
async function _listDecisions(svc) {
|
|
517
|
-
const decisions = await svc.list({ status: 'pinned', taskType: 'decision' }, { limit: 50 });
|
|
518
270
|
return envelope({
|
|
519
271
|
success: true,
|
|
520
|
-
data:
|
|
521
|
-
message:
|
|
272
|
+
data: { decision: { id: decisionId, title: args.title } },
|
|
273
|
+
message: `📌 Decision recorded: ${args.title}`,
|
|
522
274
|
meta: { tool: 'autosnippet_task' },
|
|
523
275
|
});
|
|
524
276
|
}
|
|
525
|
-
// ═══
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
277
|
+
// ═══ Intent Chain Persistence (via SignalBus) ═══════════
|
|
278
|
+
function _persistIntentChain(ctx, intent, outcome, reason) {
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
const chain = {
|
|
281
|
+
sessionId: ctx.session?.id || 'unknown',
|
|
282
|
+
taskId: intent.taskId,
|
|
283
|
+
outcome,
|
|
284
|
+
primeQuery: intent.primeQuery,
|
|
285
|
+
primeActiveFile: intent.primeActiveFile,
|
|
286
|
+
primeRecipeIds: intent.primeRecipeIds,
|
|
287
|
+
primeAt: intent.primeAt || now,
|
|
288
|
+
primeLanguage: intent.primeLanguage ?? null,
|
|
289
|
+
primeModule: intent.primeModule ?? null,
|
|
290
|
+
primeScenario: intent.primeScenario ?? 'search',
|
|
291
|
+
searchMeta: intent.searchMeta,
|
|
292
|
+
toolCalls: intent.toolCalls,
|
|
293
|
+
searchQueries: intent.searchQueries,
|
|
294
|
+
mentionedFiles: intent.mentionedFiles,
|
|
295
|
+
decisions: intent.decisions,
|
|
296
|
+
driftEvents: intent.driftEvents,
|
|
297
|
+
driftScore: _computeDriftScore(intent),
|
|
298
|
+
closeReason: outcome === 'completed' ? reason : undefined,
|
|
299
|
+
failReason: outcome !== 'completed' ? reason : undefined,
|
|
300
|
+
startedAt: intent.primeAt || now,
|
|
301
|
+
endedAt: now,
|
|
302
|
+
duration: now - (intent.primeAt || now),
|
|
303
|
+
};
|
|
304
|
+
// Emit via SignalBus — subscribers handle JSONL persistence
|
|
533
305
|
try {
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
body: JSON.stringify({ text }),
|
|
539
|
-
signal: AbortSignal.timeout(5000),
|
|
306
|
+
const signalBus = ctx.container.get('signalBus');
|
|
307
|
+
signalBus.send('intent', 'TaskHandler', _computeDriftScore(intent), {
|
|
308
|
+
target: intent.taskId ?? null,
|
|
309
|
+
metadata: { chain },
|
|
540
310
|
});
|
|
541
|
-
if (!resp.ok) {
|
|
542
|
-
process.stderr.write(`[MCP/Task] Lark notify HTTP ${resp.status}\n`);
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
545
|
-
const body = (await resp.json());
|
|
546
|
-
return body.success === true;
|
|
547
311
|
}
|
|
548
|
-
catch
|
|
549
|
-
|
|
550
|
-
return false;
|
|
312
|
+
catch {
|
|
313
|
+
// signalBus unavailable — silent failure, non-blocking
|
|
551
314
|
}
|
|
552
315
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
*/
|
|
557
|
-
async function _sendScreenshotViaApi(caption = '') {
|
|
558
|
-
try {
|
|
559
|
-
const port = process.env.PORT || 3000;
|
|
560
|
-
const resp = await fetch(`http://localhost:${port}/api/v1/remote/screenshot`, {
|
|
561
|
-
method: 'POST',
|
|
562
|
-
headers: { 'Content-Type': 'application/json' },
|
|
563
|
-
body: JSON.stringify({ caption }),
|
|
564
|
-
signal: AbortSignal.timeout(15000),
|
|
565
|
-
});
|
|
566
|
-
if (!resp.ok) {
|
|
567
|
-
process.stderr.write(`[MCP/Task] Screenshot HTTP ${resp.status}\n`);
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
|
-
const body = (await resp.json());
|
|
571
|
-
return body.success === true;
|
|
572
|
-
}
|
|
573
|
-
catch (err) {
|
|
574
|
-
process.stderr.write(`[MCP/Task] Screenshot failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
575
|
-
return false;
|
|
316
|
+
function _computeDriftScore(intent) {
|
|
317
|
+
if (intent.driftEvents.length === 0) {
|
|
318
|
+
return 0;
|
|
576
319
|
}
|
|
320
|
+
const sum = intent.driftEvents.reduce((acc, d) => acc + (1 - d.primeOverlap), 0);
|
|
321
|
+
return sum / intent.driftEvents.length;
|
|
577
322
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
*/
|
|
582
|
-
async function _notifyTaskProgress(operation, args, result) {
|
|
583
|
-
if (!result || result.success === false) {
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
const data = result.data;
|
|
587
|
-
let text = '';
|
|
588
|
-
switch (operation) {
|
|
589
|
-
case 'create': {
|
|
590
|
-
const title = data?.title || args.title || '';
|
|
591
|
-
const id = data?.id || '';
|
|
592
|
-
const type = data?.taskType || args.taskType || 'task';
|
|
593
|
-
const pri = PRIORITY_LABELS[(data?.priority ?? args.priority ?? 2)] || 'P2';
|
|
594
|
-
const dup = result.message?.includes('Duplicate') || result.message?.startsWith('⚠') ? ' (重复)' : '';
|
|
595
|
-
text = `📋 新任务${dup}: ${id}\n${title}\n类型: ${type} | ${pri}`;
|
|
596
|
-
break;
|
|
597
|
-
}
|
|
598
|
-
case 'claim': {
|
|
599
|
-
const id = data?.id || args.id;
|
|
600
|
-
const title = data?.title || '';
|
|
601
|
-
text = `🔨 开始执行: ${id}\n${title}`;
|
|
602
|
-
break;
|
|
603
|
-
}
|
|
604
|
-
case 'close': {
|
|
605
|
-
const closed = (data?.closed || data);
|
|
606
|
-
const title = closed?.title || '';
|
|
607
|
-
const id = closed?.id || args.id;
|
|
608
|
-
const reason = closed?.closeReason || args.reason || '';
|
|
609
|
-
const readyCount = Array.isArray(data?.newlyReady) ? data.newlyReady.length : 0;
|
|
610
|
-
const readyInfo = readyCount > 0 ? `\n→ ${readyCount} 个任务新就绪` : '';
|
|
611
|
-
text = `✅ 完成: ${id}\n${title}\n原因: ${reason}${readyInfo}`;
|
|
612
|
-
break;
|
|
613
|
-
}
|
|
614
|
-
case 'fail': {
|
|
615
|
-
const title = data?.title || '';
|
|
616
|
-
const id = data?.id || args.id;
|
|
617
|
-
const reason = data?.lastFailReason || args.reason || '未知';
|
|
618
|
-
const count = Number(data?.failCount || 0);
|
|
619
|
-
text = `❌ 失败: ${id}\n${title}\n原因: ${reason}${count > 1 ? ` (第${count}次)` : ''}`;
|
|
620
|
-
break;
|
|
621
|
-
}
|
|
622
|
-
case 'defer': {
|
|
623
|
-
const id = data?.id || args.id;
|
|
624
|
-
const title = data?.title || '';
|
|
625
|
-
text = `⏸️ 暂缓: ${id} — ${title}`;
|
|
626
|
-
break;
|
|
627
|
-
}
|
|
628
|
-
case 'progress': {
|
|
629
|
-
const id = data?.id || args.id;
|
|
630
|
-
const note = args.reason || args.description || '';
|
|
631
|
-
text = note ? `📝 进度: ${id}\n${note.slice(0, 200)}` : `📝 进度: ${id}`;
|
|
632
|
-
break;
|
|
633
|
-
}
|
|
634
|
-
case 'decompose': {
|
|
635
|
-
const epicId = args.id;
|
|
636
|
-
const count = Array.isArray(data) ? data.length : 0;
|
|
637
|
-
const subTitles = Array.isArray(data)
|
|
638
|
-
? data
|
|
639
|
-
.slice(0, 5)
|
|
640
|
-
.map((t, i) => ` ${i + 1}. ${t.title || t.id}`)
|
|
641
|
-
.join('\n')
|
|
642
|
-
: '';
|
|
643
|
-
text = `📂 拆解: ${epicId} → ${count} 个子任务${subTitles ? `\n${subTitles}` : ''}`;
|
|
644
|
-
break;
|
|
645
|
-
}
|
|
646
|
-
case 'record_decision': {
|
|
647
|
-
const title = data?.title || args.title || '';
|
|
648
|
-
text = `📌 决策: ${title}`;
|
|
649
|
-
break;
|
|
650
|
-
}
|
|
651
|
-
case 'revise_decision': {
|
|
652
|
-
const oldId = data?.superseded || args.id;
|
|
653
|
-
const newTitle = data?.newDecision?.title || args.title;
|
|
654
|
-
text = `🔄 决策更新: ${oldId} → ${newTitle}`;
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
case 'unpin_decision': {
|
|
658
|
-
const id = data?.id || args.id;
|
|
659
|
-
text = `🔓 决策取消: ${id}`;
|
|
660
|
-
break;
|
|
661
|
-
}
|
|
662
|
-
default:
|
|
663
|
-
return;
|
|
323
|
+
function _getPipeline(container) {
|
|
324
|
+
try {
|
|
325
|
+
return container.get('primeSearchPipeline');
|
|
664
326
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
// 发送文字通知后,附带 IDE 窗口截图
|
|
668
|
-
await _sendScreenshotViaApi();
|
|
327
|
+
catch {
|
|
328
|
+
return null;
|
|
669
329
|
}
|
|
670
330
|
}
|