autosnippet 3.3.4 → 3.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/README.md +174 -83
  2. package/config/constitution.yaml +2 -0
  3. package/dashboard/dist/assets/icons-D1aVZYFW.js +1 -0
  4. package/dashboard/dist/assets/index-CxHOu8Hd.css +1 -0
  5. package/dashboard/dist/assets/index-DDdAOpYT.js +128 -0
  6. package/dashboard/dist/index.html +3 -3
  7. package/dist/bin/api-server.js +1 -0
  8. package/dist/bin/cli.d.ts +1 -0
  9. package/dist/bin/cli.js +136 -9
  10. package/dist/lib/agent/AgentFactory.d.ts +0 -17
  11. package/dist/lib/agent/AgentFactory.js +1 -25
  12. package/dist/lib/agent/capabilities.d.ts +11 -0
  13. package/dist/lib/agent/capabilities.js +29 -5
  14. package/dist/lib/agent/context/ExplorationTracker.js +10 -1
  15. package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
  16. package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
  17. package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
  18. package/dist/lib/agent/domain/insight-analyst.js +111 -11
  19. package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
  20. package/dist/lib/agent/domain/insight-evolver.js +230 -0
  21. package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
  22. package/dist/lib/agent/domain/insight-gate.js +41 -0
  23. package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
  24. package/dist/lib/agent/domain/insight-producer.js +60 -5
  25. package/dist/lib/agent/domain/scan-prompts.js +10 -7
  26. package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
  27. package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
  28. package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
  29. package/dist/lib/agent/memory/SessionStore.js +9 -15
  30. package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
  31. package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
  32. package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
  33. package/dist/lib/agent/memory/session-store-schema.js +41 -0
  34. package/dist/lib/agent/presets.d.ts +89 -1
  35. package/dist/lib/agent/presets.js +53 -5
  36. package/dist/lib/agent/tools/_shared.d.ts +7 -15
  37. package/dist/lib/agent/tools/_shared.js +20 -21
  38. package/dist/lib/agent/tools/composite.d.ts +25 -22
  39. package/dist/lib/agent/tools/composite.js +108 -109
  40. package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
  41. package/dist/lib/agent/tools/evolution-tools.js +161 -0
  42. package/dist/lib/agent/tools/index.d.ts +163 -92
  43. package/dist/lib/agent/tools/index.js +9 -1
  44. package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
  45. package/dist/lib/agent/tools/lifecycle.js +59 -75
  46. package/dist/lib/cli/AiScanService.js +1 -1
  47. package/dist/lib/cli/KnowledgeSyncService.d.ts +5 -1
  48. package/dist/lib/cli/KnowledgeSyncService.js +6 -3
  49. package/dist/lib/core/AstAnalyzer.d.ts +1 -0
  50. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
  51. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
  52. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
  53. package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
  54. package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
  55. package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
  56. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
  57. package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
  58. package/dist/lib/domain/dimension/index.d.ts +10 -0
  59. package/dist/lib/domain/dimension/index.js +9 -0
  60. package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
  61. package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
  62. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +33 -111
  63. package/dist/lib/domain/knowledge/KnowledgeEntry.js +27 -6
  64. package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
  65. package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
  66. package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
  67. package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
  68. package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
  69. package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
  70. package/dist/lib/domain/knowledge/values/Stats.d.ts +1 -1
  71. package/dist/lib/domain/knowledge/values/Stats.js +2 -2
  72. package/dist/lib/external/mcp/McpServer.js +4 -0
  73. package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
  74. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
  75. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
  76. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
  77. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
  78. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
  79. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
  80. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
  81. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
  82. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
  83. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
  84. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
  85. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
  86. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +172 -161
  87. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
  88. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
  89. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
  90. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
  91. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
  92. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
  93. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
  94. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
  95. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
  96. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
  97. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
  98. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
  99. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
  100. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
  101. package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
  102. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
  103. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
  104. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +14 -10
  105. package/dist/lib/external/mcp/handlers/bootstrap-external.js +39 -51
  106. package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
  107. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +115 -82
  108. package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
  109. package/dist/lib/external/mcp/handlers/consolidated.js +115 -162
  110. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +69 -1
  111. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
  112. package/dist/lib/external/mcp/handlers/evolve-external.js +226 -0
  113. package/dist/lib/external/mcp/handlers/knowledge.js +26 -2
  114. package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
  115. package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
  116. package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
  117. package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
  118. package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
  119. package/dist/lib/external/mcp/handlers/search.js +6 -5
  120. package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
  121. package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
  122. package/dist/lib/external/mcp/tools.d.ts +8 -18
  123. package/dist/lib/external/mcp/tools.js +60 -3
  124. package/dist/lib/http/routes/knowledge.js +122 -1
  125. package/dist/lib/http/routes/modules.js +25 -3
  126. package/dist/lib/http/routes/panorama.js +16 -4
  127. package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
  128. package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
  129. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
  130. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
  131. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
  132. package/dist/lib/injection/ServiceContainer.js +55 -0
  133. package/dist/lib/injection/ServiceMap.d.ts +8 -1
  134. package/dist/lib/injection/modules/InfraModule.js +4 -1
  135. package/dist/lib/injection/modules/KnowledgeModule.js +38 -1
  136. package/dist/lib/repository/evolution/ProposalRepository.d.ts +99 -0
  137. package/dist/lib/repository/evolution/ProposalRepository.js +255 -0
  138. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
  139. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
  140. package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
  141. package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
  142. package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
  143. package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
  144. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +22 -4
  145. package/dist/lib/service/bootstrap/UiStartupTasks.js +73 -5
  146. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
  147. package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
  148. package/dist/lib/service/cleanup/CleanupService.d.ts +85 -0
  149. package/dist/lib/service/cleanup/CleanupService.js +324 -0
  150. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
  151. package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
  152. package/dist/lib/service/delivery/FileProtection.js +54 -0
  153. package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
  154. package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
  155. package/dist/lib/service/evolution/ContentPatcher.js +310 -0
  156. package/dist/lib/service/evolution/DecayDetector.d.ts +4 -3
  157. package/dist/lib/service/evolution/DecayDetector.js +97 -22
  158. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -2
  159. package/dist/lib/service/evolution/KnowledgeMetabolism.js +29 -2
  160. package/dist/lib/service/evolution/ProposalExecutor.d.ts +66 -0
  161. package/dist/lib/service/evolution/ProposalExecutor.js +424 -0
  162. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
  163. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
  164. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
  165. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
  166. package/dist/lib/service/evolution/StagingManager.js +5 -3
  167. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
  168. package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
  169. package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
  170. package/dist/lib/service/guard/ComplianceReporter.js +51 -0
  171. package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
  172. package/dist/lib/service/guard/GuardCrossFileChecks.js +2 -0
  173. package/dist/lib/service/guard/ReverseGuard.d.ts +1 -1
  174. package/dist/lib/service/guard/ReverseGuard.js +32 -2
  175. package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
  176. package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
  177. package/dist/lib/service/knowledge/KnowledgeService.js +44 -4
  178. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
  179. package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
  180. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +2 -0
  181. package/dist/lib/service/knowledge/SourceRefReconciler.js +48 -0
  182. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +3 -2
  183. package/dist/lib/service/panorama/DimensionAnalyzer.js +15 -140
  184. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  185. package/dist/lib/service/search/SearchEngine.d.ts +11 -10
  186. package/dist/lib/service/search/SearchEngine.js +38 -36
  187. package/dist/lib/service/search/SearchTypes.d.ts +14 -8
  188. package/dist/lib/service/search/SearchTypes.js +1 -1
  189. package/dist/lib/service/search/tokenizer.d.ts +1 -1
  190. package/dist/lib/service/search/tokenizer.js +2 -2
  191. package/dist/lib/shared/schemas/common.d.ts +4 -4
  192. package/dist/lib/shared/schemas/http-requests.d.ts +12 -1
  193. package/dist/lib/shared/schemas/http-requests.js +8 -0
  194. package/dist/lib/shared/schemas/mcp-tools.d.ts +33 -2
  195. package/dist/lib/shared/schemas/mcp-tools.js +42 -0
  196. package/dist/lib/types/evolution.d.ts +135 -0
  197. package/dist/lib/types/evolution.js +6 -0
  198. package/dist/lib/types/graph-shared.d.ts +25 -0
  199. package/dist/lib/types/graph-shared.js +7 -0
  200. package/dist/lib/types/knowledge-wire.d.ts +131 -0
  201. package/dist/lib/types/knowledge-wire.js +7 -0
  202. package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
  203. package/dist/lib/types/project-snapshot-builder.js +189 -0
  204. package/dist/lib/types/project-snapshot.d.ts +399 -0
  205. package/dist/lib/types/project-snapshot.js +17 -0
  206. package/dist/lib/types/search-wire.d.ts +46 -0
  207. package/dist/lib/types/search-wire.js +7 -0
  208. package/dist/lib/types/snapshot-views.d.ts +58 -0
  209. package/dist/lib/types/snapshot-views.js +103 -0
  210. package/package.json +1 -1
  211. package/skills/autosnippet-recipes/SKILL.md +1 -1
  212. package/templates/instructions/agent-static.md +2 -0
  213. package/templates/instructions/conventions.md +3 -1
  214. package/templates/recipes-setup/README.md +2 -2
  215. package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
  216. package/dashboard/dist/assets/index-B659K9t5.js +0 -128
  217. package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
  218. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
  219. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
  220. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
  221. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +0 -821
@@ -0,0 +1,66 @@
1
+ /**
2
+ * ProposalExecutor — 到期自动执行引擎
3
+ *
4
+ * 核心职责:
5
+ * 1. 扫描所有 observing 状态的 Proposal,检查是否到期
6
+ * 2. 到期 → 收集观察期表现数据 → 评估执行判据
7
+ * 3. 通过 → 执行操作(merge/deprecate/enhance/...)
8
+ * 4. 不通过 → 拒绝 Proposal,Recipe 恢复原状态
9
+ *
10
+ * 触发时机:UiStartupTasks Stage 5
11
+ *
12
+ * 安全边界:
13
+ * - Agent 只做分析,ProposalExecutor 做执行
14
+ * - merge/enhance 执行后 Recipe → staging(走正常路径)
15
+ * - contradiction/reorganize 始终等开发者确认(不自动执行)
16
+ * - 到期无判据 → expired
17
+ */
18
+ import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
19
+ import type { ProposalRepository, ProposalType } from '../../repository/evolution/ProposalRepository.js';
20
+ import type { ContentPatcher } from './ContentPatcher.js';
21
+ import type { RecipeLifecycleSupervisor } from './RecipeLifecycleSupervisor.js';
22
+ interface DatabaseLike {
23
+ prepare(sql: string): {
24
+ all(...params: unknown[]): Record<string, unknown>[];
25
+ get(...params: unknown[]): Record<string, unknown> | undefined;
26
+ run(...params: unknown[]): {
27
+ changes: number;
28
+ };
29
+ };
30
+ }
31
+ export interface ProposalExecutionResult {
32
+ executed: {
33
+ id: string;
34
+ type: ProposalType;
35
+ targetRecipeId: string;
36
+ }[];
37
+ rejected: {
38
+ id: string;
39
+ type: ProposalType;
40
+ reason: string;
41
+ }[];
42
+ expired: {
43
+ id: string;
44
+ type: ProposalType;
45
+ }[];
46
+ skipped: {
47
+ id: string;
48
+ type: ProposalType;
49
+ reason: string;
50
+ }[];
51
+ }
52
+ export declare class ProposalExecutor {
53
+ #private;
54
+ constructor(db: DatabaseLike, repo: ProposalRepository, options?: {
55
+ signalBus?: SignalBus;
56
+ contentPatcher?: ContentPatcher;
57
+ supervisor?: RecipeLifecycleSupervisor;
58
+ });
59
+ /**
60
+ * 定期调用(UiStartupTasks Stage 5)
61
+ *
62
+ * 扫描所有到期 Proposal → 评估 → 执行/拒绝/过期
63
+ */
64
+ checkAndExecute(): ProposalExecutionResult;
65
+ }
66
+ export {};
@@ -0,0 +1,424 @@
1
+ /**
2
+ * ProposalExecutor — 到期自动执行引擎
3
+ *
4
+ * 核心职责:
5
+ * 1. 扫描所有 observing 状态的 Proposal,检查是否到期
6
+ * 2. 到期 → 收集观察期表现数据 → 评估执行判据
7
+ * 3. 通过 → 执行操作(merge/deprecate/enhance/...)
8
+ * 4. 不通过 → 拒绝 Proposal,Recipe 恢复原状态
9
+ *
10
+ * 触发时机:UiStartupTasks Stage 5
11
+ *
12
+ * 安全边界:
13
+ * - Agent 只做分析,ProposalExecutor 做执行
14
+ * - merge/enhance 执行后 Recipe → staging(走正常路径)
15
+ * - contradiction/reorganize 始终等开发者确认(不自动执行)
16
+ * - 到期无判据 → expired
17
+ */
18
+ import Logger from '../../infrastructure/logging/Logger.js';
19
+ /* ────────────────────── Constants ────────────────────── */
20
+ /** 高风险类型:需开发者确认,不自动执行 */
21
+ const HIGH_RISK_TYPES = new Set(['contradiction', 'reorganize']);
22
+ /** 超过此天数未操作的 pending Proposal 自动过期 */
23
+ const PENDING_EXPIRY_DAYS = 14;
24
+ /* ────────────────────── Class ────────────────────── */
25
+ export class ProposalExecutor {
26
+ #db;
27
+ #repo;
28
+ #signalBus;
29
+ #contentPatcher;
30
+ #supervisor;
31
+ #logger = Logger.getInstance();
32
+ constructor(db, repo, options = {}) {
33
+ this.#db = db;
34
+ this.#repo = repo;
35
+ this.#signalBus = options.signalBus ?? null;
36
+ this.#contentPatcher = options.contentPatcher ?? null;
37
+ this.#supervisor = options.supervisor ?? null;
38
+ }
39
+ /**
40
+ * 定期调用(UiStartupTasks Stage 5)
41
+ *
42
+ * 扫描所有到期 Proposal → 评估 → 执行/拒绝/过期
43
+ */
44
+ checkAndExecute() {
45
+ const result = {
46
+ executed: [],
47
+ rejected: [],
48
+ expired: [],
49
+ skipped: [],
50
+ };
51
+ // 1. 处理到期的 observing Proposal
52
+ const expiredObserving = this.#repo.findExpiredObserving();
53
+ for (const proposal of expiredObserving) {
54
+ if (HIGH_RISK_TYPES.has(proposal.type)) {
55
+ // 高风险类型跳过自动执行
56
+ result.skipped.push({
57
+ id: proposal.id,
58
+ type: proposal.type,
59
+ reason: 'high-risk type requires developer confirmation',
60
+ });
61
+ continue;
62
+ }
63
+ this.#processExpiredProposal(proposal, result);
64
+ }
65
+ // 2. 清理超期未操作的 pending Proposal
66
+ this.#expireOldPending(result);
67
+ if (result.executed.length > 0 || result.rejected.length > 0 || result.expired.length > 0) {
68
+ this.#logger.info(`[ProposalExecutor] checkAndExecute complete: ` +
69
+ `executed=${result.executed.length}, rejected=${result.rejected.length}, expired=${result.expired.length}`);
70
+ }
71
+ return result;
72
+ }
73
+ /* ═══════════════════ Internal ═══════════════════ */
74
+ #processExpiredProposal(proposal, result) {
75
+ const metrics = this.#collectRecipeMetrics(proposal.targetRecipeId);
76
+ const snapshot = this.#extractSnapshot(proposal);
77
+ switch (proposal.type) {
78
+ case 'merge':
79
+ case 'enhance':
80
+ this.#executeMergeOrEnhance(proposal, metrics, snapshot, result);
81
+ break;
82
+ case 'supersede':
83
+ this.#executeSupersede(proposal, metrics, snapshot, result);
84
+ break;
85
+ case 'deprecate':
86
+ this.#executeDeprecate(proposal, metrics, snapshot, result);
87
+ break;
88
+ case 'correction':
89
+ this.#executeCorrection(proposal, metrics, result);
90
+ break;
91
+ default:
92
+ result.skipped.push({
93
+ id: proposal.id,
94
+ type: proposal.type,
95
+ reason: `unhandled type: ${proposal.type}`,
96
+ });
97
+ }
98
+ }
99
+ /* ── merge / enhance ── */
100
+ #executeMergeOrEnhance(proposal, metrics, snapshot, result) {
101
+ // 执行判据:
102
+ // - 目标 Recipe 在观察期内无 FP rate 异常飙升
103
+ // - 目标 Recipe 在观察期内仍有使用
104
+ const fpOk = metrics.ruleFalsePositiveRate < 0.4;
105
+ const hasUsage = metrics.guardHits > 0 || metrics.searchHits > 0;
106
+ if (fpOk && hasUsage) {
107
+ // 通过 → evolving → ContentPatcher → staging(重走 Grace Period)
108
+ this.#transitionRecipe(proposal.targetRecipeId, 'evolving', 'proposal-attach', proposal.id);
109
+ const patchResult = this.#tryApplyPatch(proposal, 'agent-suggestion');
110
+ if (patchResult?.skipped || (!patchResult?.success && patchResult !== null)) {
111
+ // Patch 跳过或失败 → 回退到 active,避免无变更进入 staging 导致空进化循环
112
+ this.#transitionRecipe(proposal.targetRecipeId, 'active', 'content-patch-complete', proposal.id);
113
+ const skipInfo = patchResult?.skipReason ? `: ${patchResult.skipReason}` : '';
114
+ this.#repo.markExecuted(proposal.id, `观察期合格但 patch 未生效${skipInfo}, 回退 active`);
115
+ }
116
+ else {
117
+ this.#transitionRecipe(proposal.targetRecipeId, 'staging', 'content-patch-complete', proposal.id);
118
+ const patchInfo = patchResult?.success
119
+ ? `, patched=[${patchResult.fieldsPatched.join(',')}]`
120
+ : '';
121
+ this.#repo.markExecuted(proposal.id, `观察期表现合格: FP=${(metrics.ruleFalsePositiveRate * 100).toFixed(0)}%, hits=${metrics.guardHits + metrics.searchHits}${patchInfo}`);
122
+ }
123
+ result.executed.push({
124
+ id: proposal.id,
125
+ type: proposal.type,
126
+ targetRecipeId: proposal.targetRecipeId,
127
+ });
128
+ this.#emitSignal(proposal, 'executed');
129
+ }
130
+ else {
131
+ // 不通过 → Recipe 恢复原状态
132
+ this.#restoreRecipe(proposal.targetRecipeId);
133
+ this.#repo.markRejected(proposal.id, `观察期表现不达标: FP=${(metrics.ruleFalsePositiveRate * 100).toFixed(0)}%, hasUsage=${hasUsage}`);
134
+ result.rejected.push({
135
+ id: proposal.id,
136
+ type: proposal.type,
137
+ reason: fpOk ? 'no usage during observation' : 'FP rate too high',
138
+ });
139
+ this.#emitSignal(proposal, 'rejected');
140
+ }
141
+ }
142
+ /* ── supersede ── */
143
+ #executeSupersede(proposal, metrics, snapshot, result) {
144
+ // 新 Recipe 必须已到达 active
145
+ const newRecipeId = proposal.relatedRecipeIds[0];
146
+ if (!newRecipeId) {
147
+ this.#repo.markRejected(proposal.id, 'no related new recipe specified');
148
+ result.rejected.push({
149
+ id: proposal.id,
150
+ type: proposal.type,
151
+ reason: 'no related new recipe',
152
+ });
153
+ return;
154
+ }
155
+ const newRecipe = this.#getRecipeLifecycle(newRecipeId);
156
+ if (newRecipe?.lifecycle !== 'active') {
157
+ // 新 Recipe 尚未 active → 跳过,等下次检查
158
+ result.skipped.push({
159
+ id: proposal.id,
160
+ type: proposal.type,
161
+ reason: `new recipe ${newRecipeId} not yet active (lifecycle: ${newRecipe?.lifecycle ?? 'unknown'})`,
162
+ });
163
+ return;
164
+ }
165
+ // 对比新旧 Recipe 的使用数据
166
+ const newMetrics = this.#collectRecipeMetrics(newRecipeId);
167
+ const oldUsage = metrics.guardHits + metrics.searchHits;
168
+ const newUsage = newMetrics.guardHits + newMetrics.searchHits;
169
+ if (newUsage >= oldUsage * 0.5 || oldUsage === 0) {
170
+ // 新 Recipe 表现足够 → 旧 Recipe → decaying,建立 deprecated_by
171
+ this.#transitionRecipe(proposal.targetRecipeId, 'decaying', 'proposal-execution', proposal.id);
172
+ this.#createDeprecatedByEdge(newRecipeId, proposal.targetRecipeId);
173
+ this.#repo.markExecuted(proposal.id, `supersede executed: new usage=${newUsage}, old usage=${oldUsage}`);
174
+ result.executed.push({
175
+ id: proposal.id,
176
+ type: proposal.type,
177
+ targetRecipeId: proposal.targetRecipeId,
178
+ });
179
+ this.#emitSignal(proposal, 'executed');
180
+ }
181
+ else {
182
+ // 新 Recipe 表现不足 → 拒绝
183
+ this.#restoreRecipe(proposal.targetRecipeId);
184
+ this.#repo.markRejected(proposal.id, `new recipe usage (${newUsage}) < 50% of old (${oldUsage})`);
185
+ result.rejected.push({
186
+ id: proposal.id,
187
+ type: proposal.type,
188
+ reason: 'new recipe insufficient usage',
189
+ });
190
+ this.#emitSignal(proposal, 'rejected');
191
+ }
192
+ }
193
+ /* ── deprecate ── */
194
+ #executeDeprecate(proposal, metrics, snapshot, result) {
195
+ const currentDecay = metrics.decayScore;
196
+ const snapshotDecay = snapshot?.decayScore ?? currentDecay;
197
+ // 观察期内 decayScore 有回升 → 拒绝
198
+ if (currentDecay > snapshotDecay + 10) {
199
+ this.#restoreRecipe(proposal.targetRecipeId);
200
+ this.#repo.markRejected(proposal.id, `decayScore recovered: ${snapshotDecay} → ${currentDecay}`);
201
+ result.rejected.push({
202
+ id: proposal.id,
203
+ type: proposal.type,
204
+ reason: 'decay score recovered during observation',
205
+ });
206
+ this.#emitSignal(proposal, 'rejected');
207
+ return;
208
+ }
209
+ // 无回升 → 根据 decayScore 决定操作
210
+ if (currentDecay <= 19) {
211
+ // 死亡 → 直接 deprecated
212
+ this.#transitionRecipe(proposal.targetRecipeId, 'deprecated', 'proposal-execution', proposal.id);
213
+ this.#repo.markExecuted(proposal.id, `deprecated (dead): decayScore=${currentDecay}`);
214
+ }
215
+ else if (currentDecay <= 40) {
216
+ // 严重 → decaying
217
+ this.#transitionRecipe(proposal.targetRecipeId, 'decaying', 'proposal-execution', proposal.id);
218
+ this.#repo.markExecuted(proposal.id, `decaying (severe): decayScore=${currentDecay}`);
219
+ }
220
+ else {
221
+ // 衰退减缓 → 拒绝
222
+ this.#restoreRecipe(proposal.targetRecipeId);
223
+ this.#repo.markRejected(proposal.id, `decayScore above threshold (${currentDecay}), not critical enough`);
224
+ result.rejected.push({
225
+ id: proposal.id,
226
+ type: proposal.type,
227
+ reason: `decayScore (${currentDecay}) not critical`,
228
+ });
229
+ this.#emitSignal(proposal, 'rejected');
230
+ return;
231
+ }
232
+ result.executed.push({
233
+ id: proposal.id,
234
+ type: proposal.type,
235
+ targetRecipeId: proposal.targetRecipeId,
236
+ });
237
+ this.#emitSignal(proposal, 'executed');
238
+ }
239
+ /* ── correction ── */
240
+ #executeCorrection(proposal, metrics, result) {
241
+ // correction 低风险,到期直接执行(Recipe → evolving → patch → staging 重新审核)
242
+ const hasUsage = metrics.guardHits > 0 || metrics.searchHits > 0;
243
+ if (hasUsage) {
244
+ this.#transitionRecipe(proposal.targetRecipeId, 'evolving', 'proposal-attach', proposal.id);
245
+ const patchResult = this.#tryApplyPatch(proposal, 'correction');
246
+ if (patchResult?.skipped || (!patchResult?.success && patchResult !== null)) {
247
+ // Patch 跳过或失败 → 回退到 active
248
+ this.#transitionRecipe(proposal.targetRecipeId, 'active', 'content-patch-complete', proposal.id);
249
+ const skipInfo = patchResult?.skipReason ? `: ${patchResult.skipReason}` : '';
250
+ this.#repo.markExecuted(proposal.id, `correction patch 未生效${skipInfo}, 回退 active`);
251
+ }
252
+ else {
253
+ this.#transitionRecipe(proposal.targetRecipeId, 'staging', 'content-patch-complete', proposal.id);
254
+ const patchInfo = patchResult?.success
255
+ ? `, patched=[${patchResult.fieldsPatched.join(',')}]`
256
+ : '';
257
+ this.#repo.markExecuted(proposal.id, `correction applied, recipe → evolving → staging for re-review${patchInfo}`);
258
+ }
259
+ result.executed.push({
260
+ id: proposal.id,
261
+ type: proposal.type,
262
+ targetRecipeId: proposal.targetRecipeId,
263
+ });
264
+ this.#emitSignal(proposal, 'executed');
265
+ }
266
+ else {
267
+ this.#repo.markRejected(proposal.id, 'no usage during observation, correction unnecessary');
268
+ result.rejected.push({
269
+ id: proposal.id,
270
+ type: proposal.type,
271
+ reason: 'no usage',
272
+ });
273
+ this.#emitSignal(proposal, 'rejected');
274
+ }
275
+ }
276
+ /* ── expired pending cleanup ── */
277
+ #expireOldPending(result) {
278
+ const cutoff = Date.now() - PENDING_EXPIRY_DAYS * 24 * 60 * 60 * 1000;
279
+ const oldPending = this.#repo.find({
280
+ status: 'pending',
281
+ expiredBefore: cutoff,
282
+ });
283
+ for (const proposal of oldPending) {
284
+ this.#repo.markExpired(proposal.id);
285
+ result.expired.push({
286
+ id: proposal.id,
287
+ type: proposal.type,
288
+ });
289
+ }
290
+ }
291
+ /* ═══════════════════ DB Helpers ═══════════════════ */
292
+ #collectRecipeMetrics(recipeId) {
293
+ const row = this.#db
294
+ .prepare(`SELECT stats, quality FROM knowledge_entries WHERE id = ?`)
295
+ .get(recipeId);
296
+ if (!row) {
297
+ return {
298
+ guardHits: 0,
299
+ searchHits: 0,
300
+ hitsLast30d: 0,
301
+ decayScore: 0,
302
+ ruleFalsePositiveRate: 0,
303
+ quality: 0,
304
+ };
305
+ }
306
+ const stats = safeJsonParse(row.stats, {});
307
+ const quality = safeJsonParse(row.quality, {});
308
+ return {
309
+ guardHits: stats.guardHits ?? 0,
310
+ searchHits: stats.searchHits ?? 0,
311
+ hitsLast30d: stats.hitsLast30d ?? 0,
312
+ decayScore: stats.decayScore ?? 50,
313
+ ruleFalsePositiveRate: stats.ruleFalsePositiveRate ?? 0,
314
+ quality: quality.overall ?? 0,
315
+ };
316
+ }
317
+ #extractSnapshot(proposal) {
318
+ for (const ev of proposal.evidence) {
319
+ if (ev.snapshotAt && ev.metrics) {
320
+ const m = ev.metrics;
321
+ return {
322
+ guardHits: m.guardHits ?? 0,
323
+ searchHits: m.searchHits ?? 0,
324
+ hitsLast30d: m.hitsLast30d ?? 0,
325
+ decayScore: m.decayScore ?? 50,
326
+ ruleFalsePositiveRate: m.ruleFalsePositiveRate ?? 0,
327
+ quality: m.quality?.overall ?? 0,
328
+ };
329
+ }
330
+ }
331
+ return null;
332
+ }
333
+ #getRecipeLifecycle(recipeId) {
334
+ const row = this.#db
335
+ .prepare(`SELECT lifecycle FROM knowledge_entries WHERE id = ?`)
336
+ .get(recipeId);
337
+ return row ?? null;
338
+ }
339
+ #transitionRecipe(recipeId, newLifecycle, trigger = 'proposal-execution', proposalId) {
340
+ if (this.#supervisor) {
341
+ const result = this.#supervisor.transition({
342
+ recipeId,
343
+ targetState: newLifecycle,
344
+ trigger,
345
+ proposalId,
346
+ operatorId: 'system',
347
+ });
348
+ if (!result.success) {
349
+ this.#logger.warn(`[ProposalExecutor] Supervisor rejected transition ${recipeId} → ${newLifecycle}: ${result.error}`);
350
+ // Fallback to raw DB update for backward compatibility
351
+ this.#db
352
+ .prepare(`UPDATE knowledge_entries SET lifecycle = ?, updatedAt = ? WHERE id = ?`)
353
+ .run(newLifecycle, Date.now(), recipeId);
354
+ }
355
+ }
356
+ else {
357
+ this.#db
358
+ .prepare(`UPDATE knowledge_entries SET lifecycle = ?, updatedAt = ? WHERE id = ?`)
359
+ .run(newLifecycle, Date.now(), recipeId);
360
+ }
361
+ }
362
+ #restoreRecipe(recipeId) {
363
+ // 恢复到 active(evolving/decaying → active)
364
+ const current = this.#getRecipeLifecycle(recipeId);
365
+ if (current && (current.lifecycle === 'evolving' || current.lifecycle === 'decaying')) {
366
+ this.#transitionRecipe(recipeId, 'active');
367
+ }
368
+ }
369
+ /**
370
+ * 尝试通过 ContentPatcher 应用 Proposal 中的 suggestedChanges
371
+ * 降级容忍:无 ContentPatcher 或 patch 失败时返回 null/skipped,不阻塞状态转移
372
+ */
373
+ #tryApplyPatch(proposal, patchSource) {
374
+ if (!this.#contentPatcher) {
375
+ return null;
376
+ }
377
+ try {
378
+ return this.#contentPatcher.applyProposal(proposal, patchSource);
379
+ }
380
+ catch (err) {
381
+ this.#logger.warn(`[ProposalExecutor] ContentPatcher failed for proposal ${proposal.id}: ${err instanceof Error ? err.message : String(err)}`);
382
+ return null;
383
+ }
384
+ }
385
+ #createDeprecatedByEdge(newRecipeId, oldRecipeId) {
386
+ const now = Date.now();
387
+ try {
388
+ this.#db
389
+ .prepare(`INSERT OR IGNORE INTO knowledge_edges (from_id, from_type, to_id, to_type, relation, weight, metadata_json, created_at, updated_at)
390
+ VALUES (?, 'recipe', ?, 'recipe', 'deprecated_by', 1.0, '{}', ?, ?)`)
391
+ .run(newRecipeId, oldRecipeId, now, now);
392
+ }
393
+ catch {
394
+ // knowledge_edges 表可能不存在(降级容忍)
395
+ }
396
+ }
397
+ /* ═══════════════════ Signal ═══════════════════ */
398
+ #emitSignal(proposal, action) {
399
+ if (!this.#signalBus) {
400
+ return;
401
+ }
402
+ this.#signalBus.send('lifecycle', 'ProposalExecutor', proposal.confidence, {
403
+ target: proposal.targetRecipeId,
404
+ metadata: {
405
+ proposalId: proposal.id,
406
+ proposalType: proposal.type,
407
+ action,
408
+ source: proposal.source,
409
+ },
410
+ });
411
+ }
412
+ }
413
+ /* ────────────────────── Util ────────────────────── */
414
+ function safeJsonParse(json, fallback) {
415
+ if (!json) {
416
+ return fallback;
417
+ }
418
+ try {
419
+ return JSON.parse(json);
420
+ }
421
+ catch {
422
+ return fallback;
423
+ }
424
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * RecipeLifecycleSupervisor — 统一状态转移管理层
3
+ *
4
+ * 核心职责:
5
+ * 1. Guard 前置检查 — 验证转移是否合法(VALID_TRANSITIONS + 扩展条件)
6
+ * 2. Entry/Exit Actions — 进入/离开状态的固定副作用
7
+ * 3. Event 记录 — 每次转移记录为不可变 TransitionEvent
8
+ * 4. 超时监控 — 中间态超时自动处理
9
+ * 5. 健康摘要 — 全局状态分布与卡死检测
10
+ *
11
+ * 所有状态变更建议通过 Supervisor,目前作为可选增强层存在。
12
+ * 不改变现有 ProposalExecutor/StagingManager 的内部逻辑,
13
+ * 而是在它们之上提供审计、超时检查和健康监控。
14
+ *
15
+ * 触发时机:UiStartupTasks Stage 6(新增)
16
+ *
17
+ * @module service/evolution/RecipeLifecycleSupervisor
18
+ */
19
+ import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
20
+ import type { LifecycleHealthSummary, TimeoutCheckResult, TransitionEvent, TransitionRequest, TransitionResult } from '../../types/evolution.js';
21
+ interface DatabaseLike {
22
+ prepare(sql: string): {
23
+ all(...params: unknown[]): Record<string, unknown>[];
24
+ get(...params: unknown[]): Record<string, unknown> | undefined;
25
+ run(...params: unknown[]): {
26
+ changes: number;
27
+ };
28
+ };
29
+ }
30
+ export declare class RecipeLifecycleSupervisor {
31
+ #private;
32
+ constructor(db: DatabaseLike, options?: {
33
+ signalBus?: SignalBus;
34
+ });
35
+ /**
36
+ * 执行状态转移 — 统一入口
37
+ *
38
+ * 1. 获取当前状态
39
+ * 2. Guard 检查(合法转移 + 扩展条件)
40
+ * 3. Exit Action(离开旧状态)
41
+ * 4. 更新 lifecycle
42
+ * 5. Entry Action(进入新状态)
43
+ * 6. 记录 TransitionEvent
44
+ * 7. 发射信号
45
+ */
46
+ transition(request: TransitionRequest): TransitionResult;
47
+ /**
48
+ * 检查中间态超时 + 自动处理
49
+ *
50
+ * 处理范围:
51
+ * - evolving > 7d → active(回退)
52
+ * - decaying > 30d → deprecated
53
+ */
54
+ checkTimeouts(): TimeoutCheckResult;
55
+ /**
56
+ * 查询 Recipe 的转移历史
57
+ */
58
+ getTransitionHistory(recipeId: string, limit?: number): TransitionEvent[];
59
+ /**
60
+ * 获取全局状态健康摘要
61
+ */
62
+ getHealthSummary(): LifecycleHealthSummary;
63
+ }
64
+ export {};