principles-disciple 1.72.0 → 1.73.0

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 (309) hide show
  1. package/openclaw.plugin.json +10 -5
  2. package/package.json +17 -19
  3. package/scripts/acceptance-test.mjs +16 -73
  4. package/scripts/sync-plugin.mjs +382 -77
  5. package/src/commands/archive-impl.ts +2 -1
  6. package/src/commands/capabilities.ts +2 -2
  7. package/src/commands/context.ts +2 -2
  8. package/src/commands/disable-impl.ts +2 -1
  9. package/src/commands/evolution-status.ts +16 -16
  10. package/src/commands/export.ts +12 -67
  11. package/src/commands/pain.ts +91 -1
  12. package/src/commands/principle-rollback.ts +2 -1
  13. package/src/commands/promote-impl.ts +7 -43
  14. package/src/commands/rollback-impl.ts +2 -1
  15. package/src/commands/rollback.ts +2 -1
  16. package/src/commands/samples.ts +2 -1
  17. package/src/commands/thinking-os.ts +2 -1
  18. package/src/config/errors.ts +18 -2
  19. package/src/constants/diagnostician.ts +2 -2
  20. package/src/constants/tools.ts +2 -1
  21. package/src/core/__tests__/focus-history.test.ts +210 -0
  22. package/src/core/config.ts +1 -1
  23. package/src/core/confirm-first-gate.ts +255 -0
  24. package/src/core/correction-cue-learner.ts +2 -136
  25. package/src/core/correction-types.ts +16 -88
  26. package/src/core/dictionary.ts +19 -20
  27. package/src/core/empathy-keyword-matcher.ts +17 -289
  28. package/src/core/empathy-types.ts +18 -229
  29. package/src/core/event-log.ts +38 -132
  30. package/src/core/evolution-reducer.ts +21 -2
  31. package/src/core/evolution-types.ts +76 -464
  32. package/src/core/file-store.ts +80 -0
  33. package/src/core/focus-history.ts +228 -955
  34. package/src/core/local-worker-routing.ts +34 -314
  35. package/src/core/merge-gate-audit.ts +0 -195
  36. package/src/core/pain-diagnostic-gate.ts +154 -0
  37. package/src/core/pain-signal.ts +21 -138
  38. package/src/core/pain.ts +15 -88
  39. package/src/core/pd-task-reconciler.ts +26 -115
  40. package/src/core/pd-task-service.ts +9 -9
  41. package/src/core/pd-task-types.ts +23 -127
  42. package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
  43. package/src/core/principle-compiler/code-validator.ts +15 -42
  44. package/src/core/principle-compiler/compiler.ts +100 -15
  45. package/src/core/principle-compiler/index.ts +5 -2
  46. package/src/core/principle-compiler/template-generator.ts +4 -104
  47. package/src/core/principle-injection.ts +10 -202
  48. package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
  49. package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
  50. package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
  51. package/src/core/principle-tree-ledger-adapter.ts +145 -0
  52. package/src/core/principle-tree-ledger.ts +8 -6
  53. package/src/core/reflection/reflection-context.ts +14 -109
  54. package/src/core/replay-engine.ts +8 -500
  55. package/src/core/rule-host-helpers.ts +5 -35
  56. package/src/core/rule-host-types.ts +10 -82
  57. package/src/core/rule-host.ts +6 -63
  58. package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
  59. package/src/core/session-tracker.ts +87 -101
  60. package/src/core/shadow-observation-registry.ts +19 -48
  61. package/src/core/trajectory.ts +3 -1
  62. package/src/core/workflow-funnel-loader.ts +62 -68
  63. package/src/core/workspace-context.ts +46 -0
  64. package/src/core/workspace-dir-service.ts +1 -1
  65. package/src/core/workspace-dir-validation.ts +18 -9
  66. package/src/hooks/AGENTS.md +1 -1
  67. package/src/hooks/gate-block-helper.ts +46 -44
  68. package/src/hooks/gate.ts +207 -7
  69. package/src/hooks/lifecycle.ts +30 -32
  70. package/src/hooks/llm.ts +60 -32
  71. package/src/hooks/pain.ts +297 -103
  72. package/src/hooks/prompt.ts +459 -439
  73. package/src/hooks/subagent.ts +2 -29
  74. package/src/i18n/commands.ts +2 -10
  75. package/src/index.ts +95 -85
  76. package/src/openclaw-sdk.ts +311 -0
  77. package/src/service/central-database.ts +8 -4
  78. package/src/service/evolution-queue-migration.ts +2 -1
  79. package/src/service/evolution-worker.ts +163 -1786
  80. package/src/service/internalization-trigger-adapter.ts +302 -0
  81. package/src/service/keyword-optimization-service.ts +4 -4
  82. package/src/service/monitoring-query-service.ts +1 -215
  83. package/src/service/queue-io.ts +60 -331
  84. package/src/service/runtime-summary-service.ts +59 -16
  85. package/src/service/subagent-workflow/index.ts +0 -41
  86. package/src/service/subagent-workflow/types.ts +9 -120
  87. package/src/service/subagent-workflow/workflow-store.ts +2 -119
  88. package/src/service/workflow-watchdog.ts +0 -43
  89. package/src/types/event-payload.ts +16 -74
  90. package/src/types/event-types.ts +39 -547
  91. package/src/types/hygiene-types.ts +7 -30
  92. package/src/types/principle-tree-schema.ts +20 -222
  93. package/src/types/queue.ts +15 -70
  94. package/src/types/runtime-summary.ts +5 -49
  95. package/src/utils/io.ts +10 -0
  96. package/src/utils/retry.ts +1 -1
  97. package/src/utils/shadow-fingerprint.ts +2 -2
  98. package/src/utils/workspace-resolver.ts +50 -0
  99. package/templates/langs/en/core/AGENTS.md +2 -2
  100. package/templates/langs/en/core/BOOT.md +1 -1
  101. package/templates/langs/en/core/HEARTBEAT.md +2 -2
  102. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  103. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  104. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  105. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  106. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  107. package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
  108. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  109. package/templates/langs/en/skills/evolve-task/SKILL.md +1 -1
  110. package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
  111. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
  112. package/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
  113. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
  114. package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
  115. package/templates/langs/zh/core/AGENTS.md +2 -2
  116. package/templates/langs/zh/core/BOOT.md +1 -1
  117. package/templates/langs/zh/core/HEARTBEAT.md +2 -2
  118. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  119. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  120. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  121. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
  122. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  123. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  124. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
  125. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  126. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
  127. package/templates/langs/zh/skills/evolve-task/SKILL.md +2 -2
  128. package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
  129. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
  130. package/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
  131. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
  132. package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
  133. package/tests/build-artifacts.test.ts +1 -3
  134. package/tests/commands/evolution-status.test.ts +0 -118
  135. package/tests/core/bootstrap-rules.test.ts +1 -1
  136. package/tests/core/config.test.ts +1 -1
  137. package/tests/core/event-log.test.ts +35 -0
  138. package/tests/core/evolution-engine.test.ts +610 -0
  139. package/tests/core/file-store.test.ts +102 -0
  140. package/tests/core/focus-history.test.ts +203 -11
  141. package/tests/core/merge-gate-audit.test.ts +2 -169
  142. package/tests/core/model-deployment-registry.test.ts +7 -1
  143. package/tests/core/model-training-registry.test.ts +19 -0
  144. package/tests/core/observability.test.ts +0 -1
  145. package/tests/core/pain-diagnostic-gate.test.ts +498 -0
  146. package/tests/core/pain.test.ts +0 -1
  147. package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
  148. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
  149. package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
  150. package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
  151. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
  152. package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
  153. package/tests/core/reflection-context.test.ts +0 -14
  154. package/tests/core/replay-engine.test.ts +127 -215
  155. package/tests/core/rule-host-helpers.test.ts +2 -2
  156. package/tests/core/rule-implementation-runtime.test.ts +0 -27
  157. package/tests/core/workflow-funnel-loader.test.ts +162 -0
  158. package/tests/core/workspace-dir-validation.test.ts +8 -1
  159. package/tests/core-anti-growth.test.ts +192 -0
  160. package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
  161. package/tests/hooks/confirm-first-gate.test.ts +333 -0
  162. package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
  163. package/tests/hooks/gate-auto-correct.test.ts +665 -0
  164. package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
  165. package/tests/hooks/pain.test.ts +269 -12
  166. package/tests/hooks/prompt-characterization.test.ts +500 -0
  167. package/tests/hooks/prompt-size-guard.test.ts +32 -17
  168. package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
  169. package/tests/index.test.ts +94 -1
  170. package/tests/integration/auto-entry-gate.test.ts +248 -0
  171. package/tests/integration/internalization-trigger-guard.test.ts +69 -0
  172. package/tests/integration/m8-legacy-paths.test.ts +63 -0
  173. package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
  174. package/tests/plugin-config-resolution-cutover.test.ts +359 -0
  175. package/tests/runtime-v2-discovery-guard.test.ts +154 -0
  176. package/tests/service/central-database.test.ts +457 -0
  177. package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
  178. package/tests/service/evolution-worker.timeout.test.ts +11 -129
  179. package/tests/service/internalization-trigger-adapter.test.ts +251 -0
  180. package/tests/service/monitoring-query-service.test.ts +1 -47
  181. package/tests/service/queue-io.test.ts +1 -62
  182. package/tests/service/runtime-summary-service.test.ts +3 -1
  183. package/tests/service/workflow-watchdog.test.ts +0 -91
  184. package/tests/utils/file-lock.test.ts +5 -3
  185. package/tests/utils/session-key.test.ts +52 -0
  186. package/tests/utils/subagent-probe.test.ts +48 -1
  187. package/vitest.config.ts +4 -11
  188. package/.planning/codebase/ARCHITECTURE.md +0 -157
  189. package/.planning/codebase/CONCERNS.md +0 -145
  190. package/.planning/codebase/CONVENTIONS.md +0 -148
  191. package/.planning/codebase/INTEGRATIONS.md +0 -81
  192. package/.planning/codebase/STACK.md +0 -87
  193. package/.planning/codebase/STRUCTURE.md +0 -193
  194. package/.planning/codebase/TESTING.md +0 -243
  195. package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
  196. package/docs/COMMAND_REFERENCE.md +0 -76
  197. package/docs/COMMAND_REFERENCE_EN.md +0 -79
  198. package/scripts/build-web.mjs +0 -46
  199. package/scripts/diagnose-nocturnal.mjs +0 -537
  200. package/scripts/seed-nocturnal-scenarios.mjs +0 -384
  201. package/src/commands/nocturnal-review.ts +0 -322
  202. package/src/commands/nocturnal-rollout.ts +0 -790
  203. package/src/commands/nocturnal-train.ts +0 -986
  204. package/src/commands/pd-reflect.ts +0 -88
  205. package/src/core/adaptive-thresholds.ts +0 -478
  206. package/src/core/diagnostician-task-store.ts +0 -192
  207. package/src/core/nocturnal-arbiter.ts +0 -715
  208. package/src/core/nocturnal-artifact-lineage.ts +0 -116
  209. package/src/core/nocturnal-artificer.ts +0 -257
  210. package/src/core/nocturnal-candidate-scoring.ts +0 -530
  211. package/src/core/nocturnal-compliance.ts +0 -1146
  212. package/src/core/nocturnal-dataset.ts +0 -763
  213. package/src/core/nocturnal-executability.ts +0 -428
  214. package/src/core/nocturnal-export.ts +0 -499
  215. package/src/core/nocturnal-paths.ts +0 -240
  216. package/src/core/nocturnal-reasoning-deriver.ts +0 -343
  217. package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
  218. package/src/core/nocturnal-snapshot-contract.ts +0 -99
  219. package/src/core/nocturnal-trajectory-extractor.ts +0 -512
  220. package/src/core/nocturnal-trinity-types.ts +0 -218
  221. package/src/core/nocturnal-trinity.ts +0 -2680
  222. package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
  223. package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
  224. package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
  225. package/src/http/principles-console-route.ts +0 -709
  226. package/src/service/central-health-service.ts +0 -49
  227. package/src/service/central-overview-service.ts +0 -138
  228. package/src/service/control-ui-query-service.ts +0 -900
  229. package/src/service/cooldown-strategy.ts +0 -97
  230. package/src/service/evolution-pain-context.ts +0 -79
  231. package/src/service/evolution-query-service.ts +0 -407
  232. package/src/service/health-query-service.ts +0 -1038
  233. package/src/service/nocturnal-config.ts +0 -214
  234. package/src/service/nocturnal-runtime.ts +0 -734
  235. package/src/service/nocturnal-service.ts +0 -1605
  236. package/src/service/nocturnal-target-selector.ts +0 -545
  237. package/src/service/sleep-cycle.ts +0 -157
  238. package/src/service/startup-reconciler.ts +0 -112
  239. package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
  240. package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
  241. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
  242. package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
  243. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
  244. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
  245. package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
  246. package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
  247. package/src/tools/write-pain-flag.ts +0 -215
  248. package/tests/commands/nocturnal-review.test.ts +0 -448
  249. package/tests/commands/nocturnal-train.test.ts +0 -97
  250. package/tests/commands/pd-reflect.test.ts +0 -49
  251. package/tests/core/adaptive-thresholds.test.ts +0 -261
  252. package/tests/core/nocturnal-arbiter.test.ts +0 -559
  253. package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
  254. package/tests/core/nocturnal-artificer.test.ts +0 -241
  255. package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
  256. package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
  257. package/tests/core/nocturnal-compliance.test.ts +0 -646
  258. package/tests/core/nocturnal-dataset.test.ts +0 -892
  259. package/tests/core/nocturnal-e2e.test.ts +0 -234
  260. package/tests/core/nocturnal-executability.test.ts +0 -357
  261. package/tests/core/nocturnal-export.test.ts +0 -517
  262. package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
  263. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
  264. package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
  265. package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
  266. package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
  267. package/tests/core/nocturnal-trinity.test.ts +0 -2053
  268. package/tests/core/pain-auto-repair.test.ts +0 -96
  269. package/tests/core/pain-integration.test.ts +0 -510
  270. package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
  271. package/tests/http/principles-console-route.test.ts +0 -162
  272. package/tests/integration/chaos-resilience.test.ts +0 -348
  273. package/tests/integration/empathy-workflow-integration.test.ts +0 -626
  274. package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
  275. package/tests/service/control-ui-query-service.test.ts +0 -121
  276. package/tests/service/cooldown-strategy.test.ts +0 -164
  277. package/tests/service/data-endpoints-regression.test.ts +0 -834
  278. package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
  279. package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
  280. package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
  281. package/tests/service/nocturnal-runtime.test.ts +0 -473
  282. package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
  283. package/tests/service/nocturnal-target-selector.test.ts +0 -615
  284. package/tests/service/startup-reconciler.test.ts +0 -148
  285. package/tests/tools/write-pain-flag.test.ts +0 -358
  286. package/ui/src/App.tsx +0 -45
  287. package/ui/src/api.ts +0 -220
  288. package/ui/src/charts.tsx +0 -955
  289. package/ui/src/components/ErrorState.tsx +0 -6
  290. package/ui/src/components/Loading.tsx +0 -13
  291. package/ui/src/components/ProtectedRoute.tsx +0 -12
  292. package/ui/src/components/Shell.tsx +0 -91
  293. package/ui/src/components/WorkspaceConfig.tsx +0 -178
  294. package/ui/src/components/index.ts +0 -5
  295. package/ui/src/context/auth.tsx +0 -80
  296. package/ui/src/context/theme.tsx +0 -66
  297. package/ui/src/hooks/useAutoRefresh.ts +0 -39
  298. package/ui/src/i18n/ui.ts +0 -473
  299. package/ui/src/main.tsx +0 -16
  300. package/ui/src/pages/EvolutionPage.tsx +0 -333
  301. package/ui/src/pages/FeedbackPage.tsx +0 -138
  302. package/ui/src/pages/GateMonitorPage.tsx +0 -136
  303. package/ui/src/pages/LoginPage.tsx +0 -89
  304. package/ui/src/pages/OverviewPage.tsx +0 -599
  305. package/ui/src/pages/SamplesPage.tsx +0 -174
  306. package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
  307. package/ui/src/styles.css +0 -2020
  308. package/ui/src/types.ts +0 -384
  309. package/ui/src/utils/format.ts +0 -15
@@ -1,108 +1,8 @@
1
1
  /**
2
- * Template Generator for Principle Compiler
2
+ * Template Generator Re-export from @principles/core
3
3
  *
4
- * Generates RuleHost sandbox code from PainPattern descriptors.
5
- * Produces self-contained JS modules with `export const meta` and
6
- * `export function evaluate(input)` that can be loaded at runtime.
7
- *
8
- * SECURITY: All interpolated values use JSON.stringify or safe helpers
9
- * to prevent code injection through principleId, coversCondition, or regex patterns.
10
- */
11
-
12
- export interface PainPattern {
13
- toolName: string;
14
- pathRegex?: string;
15
- commandRegex?: string;
16
- contentRegex?: string;
17
- errorType?: string;
18
- }
19
-
20
- /**
21
- * Derives the auto-rule display name from a principle ID.
22
- */
23
- function toAutoName(principleId: string): string {
24
- return `Auto_${principleId}`;
25
- }
26
-
27
- /**
28
- * Derives the auto-rule ID from a principle ID.
29
- * Must match ledger-registrar convention: "P_066" => "R_P_066_auto"
30
- */
31
- function toAutoRuleId(principleId: string): string {
32
- return `R_${principleId}_auto`;
33
- }
34
-
35
- /**
36
- * Builds a single `if` branch for a pain pattern.
37
- *
38
- * SECURITY: Uses `new RegExp(JSON.stringify(...))` instead of regex literals
39
- * to prevent code injection through pathRegex/commandRegex/contentRegex values.
40
- * principleId in reason uses JSON.stringify to prevent string breakout.
4
+ * PRI-44: Pure template generation logic moved to core.
5
+ * This file re-exports for backward compatibility.
41
6
  */
42
- function buildBranch(principleId: string, pattern: PainPattern): string {
43
- const conditions: string[] = [];
44
-
45
- conditions.push(`input.action.toolName === ${JSON.stringify(pattern.toolName)}`);
46
-
47
- if (pattern.pathRegex) {
48
- conditions.push(`new RegExp(${JSON.stringify(pattern.pathRegex)}).test(input.action.normalizedPath || '')`);
49
- }
50
-
51
- if (pattern.commandRegex) {
52
- conditions.push(`new RegExp(${JSON.stringify(pattern.commandRegex)}).test(input.action.paramsSummary.command || '')`);
53
- }
54
-
55
- if (pattern.contentRegex) {
56
- conditions.push(
57
- `new RegExp(${JSON.stringify(pattern.contentRegex)}).test(input.action.paramsSummary.content || input.action.paramsSummary.new_string || '')`,
58
- );
59
- }
60
-
61
- const guard = conditions.join(' && ');
62
- const reason = `[${principleId}] Blocked by auto-generated rule`;
63
-
64
- return (
65
- ` if (${guard}) {\n` +
66
- ` return { decision: 'block', matched: true, reason: ${JSON.stringify(reason)} };\n` +
67
- ` }`
68
- );
69
- }
70
-
71
- /**
72
- * Generates sandbox-ready JS code from a principle ID and pain patterns.
73
- *
74
- * Returns `null` when `patterns` is empty.
75
- */
76
- export function generateFromTemplate(
77
- principleId: string,
78
- coversCondition: string,
79
- patterns: PainPattern[],
80
- ): string | null {
81
- if (patterns.length === 0) {
82
- return null;
83
- }
84
-
85
- const name = toAutoName(principleId);
86
- const ruleId = toAutoRuleId(principleId);
87
- const compiledAt = new Date().toISOString();
88
-
89
- const branches = patterns
90
- .map((p) => buildBranch(principleId, p))
91
- .join('\n');
92
7
 
93
- return (
94
- `// Auto-generated by Principle Compiler\n` +
95
- `export const meta = {\n` +
96
- ` name: ${JSON.stringify(name)},\n` +
97
- ` version: '1.0.0',\n` +
98
- ` ruleId: ${JSON.stringify(ruleId)},\n` +
99
- ` coversCondition: ${JSON.stringify(coversCondition)},\n` +
100
- ` compiledAt: ${JSON.stringify(compiledAt)},\n` +
101
- ` sourcePrincipleId: ${JSON.stringify(principleId)},\n` +
102
- `};\n\n` +
103
- `export function evaluate(input) {\n` +
104
- `${branches}\n` +
105
- ` return { matched: false };\n` +
106
- `}\n`
107
- );
108
- }
8
+ export { generateFromTemplate, type PainPattern } from '@principles/core/runtime-v2';
@@ -1,208 +1,16 @@
1
1
  /**
2
2
  * Principle Injection — Budget-Aware Principle Selection
3
- * ========================================================
4
3
  *
5
- * PURPOSE: Select principles for prompt injection within a character budget,
6
- * prioritizing by priority tier (P0 > P1 > P2) and recency, while ensuring
7
- * at least one P0 principle is included when available.
4
+ * Phase: PRI-75 Prompt Injection SDK Migration Phase 2
8
5
  *
9
- * DESIGN:
10
- * - Sorts principles by priority (P0 first, then P1, then P2)
11
- * - Within same priority, sorts by recency (createdAt descending)
12
- * - Selects principles until the cumulative character budget is exceeded
13
- * - Guarantees at least one P0 principle is included if any exist
14
- * - Returns the selected principles and total character usage
15
- *
16
- * This replaces the previous hardcoded slice(-3)/slice(0,5) approach in
17
- * prompt.ts with a budget-aware, priority-respecting selection algorithm.
18
- */
19
-
20
- import type { PrinciplePriority } from '../types/principle-tree-schema.js';
21
-
22
- // ---------------------------------------------------------------------------
23
- // Types
24
- // ---------------------------------------------------------------------------
25
-
26
- /**
27
- * Minimal principle shape required for injection selection.
28
- * Accepts both evolution-types.Principle and principle-tree-schema.Principle.
29
- */
30
- export interface InjectablePrinciple {
31
- id: string;
32
- text: string;
33
- /** Priority level. Defaults to 'P1' if not set by the source. */
34
- priority?: PrinciplePriority;
35
- createdAt: string;
36
- }
37
-
38
- /**
39
- * Result of principle selection for injection.
40
- */
41
- export interface PrincipleSelectionResult {
42
- /** Selected principles in injection order (priority-first, then recency) */
43
- selected: InjectablePrinciple[];
44
- /** Total character count of selected principles' formatted output */
45
- totalChars: number;
46
- /** Number of principles by priority tier */
47
- breakdown: {
48
- p0: number;
49
- p1: number;
50
- p2: number;
51
- };
52
- /** Whether at least one P0 principle was included */
53
- hasP0: boolean;
54
- /** Whether the selection was truncated due to budget */
55
- wasTruncated: boolean;
56
- }
57
-
58
- // ---------------------------------------------------------------------------
59
- // Priority Ordering
60
- // ---------------------------------------------------------------------------
61
-
62
- const PRIORITY_ORDER: Record<PrinciplePriority, number> = {
63
- P0: 0,
64
- P1: 1,
65
- P2: 2,
66
- };
67
-
68
- /**
69
- * Compare two principles for sorting.
70
- * Primary: priority (P0 < P1 < P2 — lower is higher priority).
71
- * Secondary: recency (newer createdAt first).
72
- */
73
- function comparePrinciples(a: InjectablePrinciple, b: InjectablePrinciple): number {
74
- const priorityA = PRIORITY_ORDER[a.priority ?? 'P1'] ?? 99;
75
- const priorityB = PRIORITY_ORDER[b.priority ?? 'P1'] ?? 99;
76
-
77
- if (priorityA !== priorityB) {
78
- return priorityA - priorityB;
79
- }
80
-
81
- // Same priority: sort by recency (newer first)
82
- return b.createdAt.localeCompare(a.createdAt);
83
- }
84
-
85
- // ---------------------------------------------------------------------------
86
- // Formatting
87
- // ---------------------------------------------------------------------------
88
-
89
- /**
90
- * Format a single principle for injection.
91
- * Returns the formatted string including ID and text.
92
- *
93
- * Format: "- [ID] text" (matches existing prompt.ts format)
6
+ * This file is now a thin re-export layer.
7
+ * All pure logic lives in @principles/core/prompt-builder/principle-selection.ts.
94
8
  */
95
- export function formatPrinciple(p: InjectablePrinciple): string {
96
- return `- [${p.id}] ${p.text}`;
97
- }
98
9
 
99
- /**
100
- * Calculate the character length of a formatted principle, including newline.
101
- */
102
- function formattedLength(p: InjectablePrinciple): number {
103
- return formatPrinciple(p).length + 1; // +1 for newline separator
104
- }
105
-
106
- // ---------------------------------------------------------------------------
107
- // Selection Algorithm
108
- // ---------------------------------------------------------------------------
109
-
110
- /**
111
- * Select principles for prompt injection within a character budget.
112
- *
113
- * Algorithm:
114
- * 1. Sort all principles by priority (P0 > P1 > P2), then by recency
115
- * 2. Iterate through sorted principles, accumulating character count
116
- * 3. Stop when adding the next principle would exceed budgetChars
117
- * 4. Ensure at least one P0 principle is included (even if it exceeds budget)
118
- *
119
- * @param principles - All available principles to select from
120
- * @param budgetChars - Maximum character budget for formatted output
121
- * @returns Selection result with chosen principles and metadata
122
- */
123
- export function selectPrinciplesForInjection(
124
- principles: InjectablePrinciple[],
125
- budgetChars: number,
126
- ): PrincipleSelectionResult {
127
- if (principles.length === 0) {
128
- return {
129
- selected: [],
130
- totalChars: 0,
131
- breakdown: { p0: 0, p1: 0, p2: 0 },
132
- hasP0: false,
133
- wasTruncated: false,
134
- };
135
- }
136
-
137
- // Sort by priority then recency
138
- const sorted = [...principles].sort(comparePrinciples);
139
-
140
- const selected: InjectablePrinciple[] = [];
141
- let totalChars = 0;
142
- let p0Included = false;
143
- let wasTruncated = false;
144
-
145
- for (const principle of sorted) {
146
- const cost = formattedLength(principle);
147
-
148
- // Check if adding this principle would exceed budget
149
- if (totalChars + cost > budgetChars) {
150
- // Special case: if no P0 has been included yet, force-include the first P0
151
- // even if it exceeds the budget (P0 principles are critical)
152
- if (!p0Included && principle.priority === 'P0') {
153
- selected.push(principle);
154
- totalChars += cost;
155
- p0Included = true;
156
- wasTruncated = true;
157
- // Continue to try to fit more principles after this forced inclusion
158
- continue;
159
- }
160
-
161
- wasTruncated = true;
162
- break;
163
- }
164
-
165
- selected.push(principle);
166
- totalChars += cost;
167
- if (principle.priority === 'P0') {
168
- p0Included = true;
169
- }
170
- }
171
-
172
- // Safety net: if we went through all principles and still no P0 included
173
- // (because P0 was beyond budget threshold), force-include the first P0
174
- if (!p0Included) {
175
- const firstP0 = sorted.find(p => p.priority === 'P0');
176
- if (firstP0 && !selected.includes(firstP0)) {
177
- // Insert P0 at the beginning of selected (highest priority)
178
- selected.unshift(firstP0);
179
- totalChars += formattedLength(firstP0);
180
- p0Included = true;
181
- }
182
- }
183
-
184
- const breakdown = {
185
- p0: selected.filter(p => (p.priority ?? 'P1') === 'P0').length,
186
- p1: selected.filter(p => (p.priority ?? 'P1') === 'P1').length,
187
- p2: selected.filter(p => (p.priority ?? 'P1') === 'P2').length,
188
- };
189
-
190
- return {
191
- selected,
192
- totalChars,
193
- breakdown,
194
- hasP0: p0Included,
195
- wasTruncated,
196
- };
197
- }
198
-
199
- // ---------------------------------------------------------------------------
200
- // Default Budget
201
- // ---------------------------------------------------------------------------
202
-
203
- /**
204
- * Default character budget for principle injection.
205
- * 4000 characters is ~800 tokens, leaving ample room for other prompt sections
206
- * within the 10K character injection limit.
207
- */
208
- export const DEFAULT_PRINCIPLE_BUDGET = 4000;
10
+ // Re-exported from core for backward compatibility with existing imports
11
+ export {
12
+ formatPrinciple,
13
+ selectPrinciplesForInjection,
14
+ DEFAULT_PRINCIPLE_BUDGET,
15
+ } from '@principles/core/prompt-builder';
16
+ export type { InjectablePrinciple, PrincipleSelectionResult } from '@principles/core/prompt-builder';
@@ -0,0 +1,42 @@
1
+ import type { LifecycleDatasource } from '@principles/core/runtime-v2';
2
+ import type { LedgerTreeStore, ReplayReport, ArtifactLineageRecord } from '@principles/core/runtime-v2';
3
+ import { loadLedger } from '../principle-tree-ledger.js';
4
+ import { ReplayEngine } from '../replay-engine.js';
5
+
6
+ export class LineageSourceRetiredError extends Error {
7
+ constructor() {
8
+ super(
9
+ 'Artifact lineage source retired in PRI-230. ' +
10
+ 'The nocturnal-artifact-lineage module has been deleted; ' +
11
+ 'this datasource cannot provide lineage records. ' +
12
+ 'Callers must handle this error explicitly rather than interpreting an empty result as "no lineage".'
13
+ );
14
+ this.name = 'LineageSourceRetiredError';
15
+ }
16
+ }
17
+
18
+ export class FilesystemLifecycleDatasource implements LifecycleDatasource {
19
+ private _engine?: ReplayEngine;
20
+
21
+ constructor(
22
+ private readonly workspaceDir: string,
23
+ private readonly stateDir: string,
24
+ ) {}
25
+
26
+ private get engine(): ReplayEngine {
27
+ if (!this._engine) this._engine = new ReplayEngine(this.workspaceDir, this.stateDir);
28
+ return this._engine;
29
+ }
30
+
31
+ loadLedger(): LedgerTreeStore {
32
+ return loadLedger(this.stateDir).tree as unknown as LedgerTreeStore;
33
+ }
34
+
35
+ listReplayReports(implementationId: string): ReplayReport[] {
36
+ return this.engine.listReports(implementationId);
37
+ }
38
+
39
+ listLineageRecords(_kind: 'behavioral-sample' | 'rule-implementation-candidate'): ArtifactLineageRecord[] {
40
+ throw new LineageSourceRetiredError();
41
+ }
42
+ }
@@ -1,243 +1,40 @@
1
- import { loadLedger, type LedgerPrinciple, type LedgerRule } from '../principle-tree-ledger.js';
2
- import { listArtifactLineageRecords, type ArtifactLineageRecord } from '../nocturnal-artifact-lineage.js';
3
- import { ReplayEngine, type ClassificationSummary, type ReplayReport } from '../replay-engine.js';
4
- import type { Implementation, ImplementationLifecycleState } from '../../types/principle-tree-schema.js';
5
-
6
- export interface LifecycleClassificationTotals {
7
- total: number;
8
- passed: number;
9
- failed: number;
10
- }
11
-
12
- export interface RuleReplayEvidence {
13
- reportCount: number;
14
- latestReports: ReplayReport[];
15
- painNegative: LifecycleClassificationTotals;
16
- successPositive: LifecycleClassificationTotals;
17
- principleAnchor: LifecycleClassificationTotals;
18
- passingImplementationIds: string[];
19
- failingImplementationIds: string[];
20
- needsReviewImplementationIds: string[];
21
- }
22
-
23
- export interface RuleLiveEvidence {
24
- activeCount: number;
25
- candidateCount: number;
26
- disabledCount: number;
27
- archivedCount: number;
28
- durablePenaltyCount: number;
29
- rollbackEvidenceCount: number;
30
- hasActiveImplementation: boolean;
31
- hasPassingActiveImplementation: boolean;
32
- }
33
-
34
- export interface RuleLineageEvidence {
35
- records: ArtifactLineageRecord[];
36
- distinctPainSignalCount: number;
37
- distinctGateBlockCount: number;
38
- repeatedErrorSignal: number;
39
- latestCreatedAt?: string;
40
- }
41
-
42
- export interface ImplementationLifecycleEvidence {
43
- implementation: Implementation;
44
- latestReplayReport: ReplayReport | null;
45
- replayHistoryCount: number;
46
- lineageRecords: ArtifactLineageRecord[];
47
- }
48
-
49
- export interface RuleLifecycleEvidence {
50
- rule: LedgerRule;
51
- implementations: ImplementationLifecycleEvidence[];
52
- replayEvidence: RuleReplayEvidence;
53
- liveEvidence: RuleLiveEvidence;
54
- lineageEvidence: RuleLineageEvidence;
55
- }
56
-
57
- export interface PrincipleLifecycleEvidence {
58
- principle: LedgerPrinciple;
59
- rules: RuleLifecycleEvidence[];
60
- summary: {
61
- replayReportCount: number;
62
- activeImplementationCount: number;
63
- candidateImplementationCount: number;
64
- disabledImplementationCount: number;
65
- archivedImplementationCount: number;
66
- distinctPainSignalCount: number;
67
- distinctGateBlockCount: number;
68
- repeatedErrorSignal: number;
69
- };
70
- }
71
-
72
- export interface LifecycleReadModel {
73
- generatedAt: string;
74
- principles: PrincipleLifecycleEvidence[];
75
- }
76
-
77
- function toClassificationTotals(summary: ClassificationSummary[]): LifecycleClassificationTotals {
78
- return summary.reduce<LifecycleClassificationTotals>(
79
- (totals, entry) => ({
80
- total: totals.total + entry.total,
81
- passed: totals.passed + entry.passed,
82
- failed: totals.failed + entry.failed,
83
- }),
84
- { total: 0, passed: 0, failed: 0 },
85
- );
86
- }
87
-
88
- function countByLifecycle(implementations: Implementation[], lifecycleState: ImplementationLifecycleState): number {
89
- return implementations.filter((implementation) => implementation.lifecycleState === lifecycleState).length;
90
- }
91
-
92
- function hasDurablePenalty(implementation: Implementation): boolean {
93
- if (implementation.lifecycleState === 'disabled' || implementation.lifecycleState === 'archived') {
94
- return true;
95
- }
96
-
97
- return typeof implementation.disabledReason === 'string' && implementation.disabledReason.trim().length > 0;
98
- }
99
-
100
- function hasRollbackEvidence(implementation: Implementation): boolean {
101
- return typeof implementation.previousActive === 'string' && implementation.previousActive.length > 0;
102
- }
103
-
104
- function createRuleReplayEvidence(reports: { implementationId: string; report: ReplayReport }[]): RuleReplayEvidence {
105
- return {
106
- reportCount: reports.length,
107
- latestReports: reports.map((entry) => entry.report),
108
- painNegative: toClassificationTotals(reports.map((entry) => entry.report.replayResults.painNegative)),
109
- successPositive: toClassificationTotals(reports.map((entry) => entry.report.replayResults.successPositive)),
110
- principleAnchor: toClassificationTotals(reports.map((entry) => entry.report.replayResults.principleAnchor)),
111
- passingImplementationIds: reports
112
- .filter((entry) => entry.report.overallDecision === 'pass')
113
- .map((entry) => entry.implementationId),
114
- failingImplementationIds: reports
115
- .filter((entry) => entry.report.overallDecision === 'fail')
116
- .map((entry) => entry.implementationId),
117
- needsReviewImplementationIds: reports
118
- .filter((entry) => entry.report.overallDecision === 'needs-review')
119
- .map((entry) => entry.implementationId),
120
- };
121
- }
122
-
123
- function createRuleLineageEvidence(records: ArtifactLineageRecord[]): RuleLineageEvidence {
124
- const painIds = new Set<string>();
125
- const gateBlockIds = new Set<string>();
126
-
127
- for (const record of records) {
128
- for (const painId of record.sourcePainIds) {
129
- painIds.add(painId);
130
- }
131
- for (const gateBlockId of record.sourceGateBlockIds) {
132
- gateBlockIds.add(gateBlockId);
133
- }
134
- }
135
-
136
- const latestCreatedAt =
137
- records.length > 0
138
- ? records
139
- .map((record) => record.createdAt)
140
- .sort((left, right) => new Date(right).getTime() - new Date(left).getTime())[0]
141
- : undefined;
142
-
143
- return {
144
- records,
145
- distinctPainSignalCount: painIds.size,
146
- distinctGateBlockCount: gateBlockIds.size,
147
- repeatedErrorSignal: painIds.size + gateBlockIds.size,
148
- latestCreatedAt,
149
- };
150
- }
151
-
152
- function createRuleLiveEvidence(
153
- implementations: Implementation[],
154
- replayEvidence: RuleReplayEvidence,
155
- ): RuleLiveEvidence {
156
- const activeImplementations = implementations.filter((implementation) => implementation.lifecycleState === 'active');
157
-
158
- return {
159
- activeCount: countByLifecycle(implementations, 'active'),
160
- candidateCount: countByLifecycle(implementations, 'candidate'),
161
- disabledCount: countByLifecycle(implementations, 'disabled'),
162
- archivedCount: countByLifecycle(implementations, 'archived'),
163
- durablePenaltyCount: implementations.filter((implementation) => hasDurablePenalty(implementation)).length,
164
- rollbackEvidenceCount: implementations.filter((implementation) => hasRollbackEvidence(implementation)).length,
165
- hasActiveImplementation: activeImplementations.length > 0,
166
- hasPassingActiveImplementation: activeImplementations.some((implementation) =>
167
- replayEvidence.passingImplementationIds.includes(implementation.id),
168
- ),
169
- };
170
- }
171
-
172
- export function buildLifecycleReadModel(workspaceDir: string, stateDir: string): LifecycleReadModel {
173
- const ledger = loadLedger(stateDir);
174
- const replayEngine = new ReplayEngine(workspaceDir, stateDir);
175
- const lineageRecords = listArtifactLineageRecords(workspaceDir, 'rule-implementation-candidate');
176
-
177
- const principles = Object.values(ledger.tree.principles)
178
- .map((principle): PrincipleLifecycleEvidence => {
179
- const rules = principle.ruleIds
180
- .map((ruleId) => ledger.tree.rules[ruleId])
181
- .filter((rule): rule is LedgerRule => rule !== undefined)
182
- .map((rule): RuleLifecycleEvidence => {
183
- const implementations = rule.implementationIds
184
- .map((implementationId) => ledger.tree.implementations[implementationId])
185
- .filter((implementation): implementation is Implementation => implementation !== undefined);
186
-
187
- const implementationEvidence: ImplementationLifecycleEvidence[] = implementations.map((implementation) => {
188
- const reports = replayEngine.listReports(implementation.id);
189
- const implementationLineage = lineageRecords.filter(
190
- (record) => record.ruleId === rule.id || record.implementationId === implementation.id,
191
- );
192
-
193
- return {
194
- implementation,
195
- latestReplayReport: reports[0] ?? null,
196
- replayHistoryCount: reports.length,
197
- lineageRecords: implementationLineage,
198
- };
199
- });
200
-
201
- const replayEvidence = createRuleReplayEvidence(
202
- implementationEvidence
203
- .filter((entry) => entry.latestReplayReport !== null)
204
- .map((entry) => ({
205
- implementationId: entry.implementation.id,
206
- report: entry.latestReplayReport as ReplayReport,
207
- })),
208
- );
209
- const ruleLineageRecords = lineageRecords.filter((record) => record.ruleId === rule.id);
210
- const lineageEvidence = createRuleLineageEvidence(ruleLineageRecords);
211
- const liveEvidence = createRuleLiveEvidence(implementations, replayEvidence);
212
-
213
- return {
214
- rule,
215
- implementations: implementationEvidence,
216
- replayEvidence,
217
- liveEvidence,
218
- lineageEvidence,
219
- };
220
- });
221
-
222
- return {
223
- principle,
224
- rules,
225
- summary: {
226
- replayReportCount: rules.reduce((sum, rule) => sum + rule.replayEvidence.reportCount, 0),
227
- activeImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.activeCount, 0),
228
- candidateImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.candidateCount, 0),
229
- disabledImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.disabledCount, 0),
230
- archivedImplementationCount: rules.reduce((sum, rule) => sum + rule.liveEvidence.archivedCount, 0),
231
- distinctPainSignalCount: rules.reduce((sum, rule) => sum + rule.lineageEvidence.distinctPainSignalCount, 0),
232
- distinctGateBlockCount: rules.reduce((sum, rule) => sum + rule.lineageEvidence.distinctGateBlockCount, 0),
233
- repeatedErrorSignal: rules.reduce((sum, rule) => sum + rule.lineageEvidence.repeatedErrorSignal, 0),
234
- },
235
- };
236
- })
237
- .sort((left, right) => left.principle.id.localeCompare(right.principle.id));
238
-
239
- return {
240
- generatedAt: new Date().toISOString(),
241
- principles,
242
- };
1
+ /**
2
+ * Lifecycle read model re-export facade (PRI-56).
3
+ *
4
+ * All computation lives in @principles/core/runtime-v2.
5
+ * This file re-exports types, the core builder, and provides
6
+ * a backward-compatible path-based wrapper for existing consumers.
7
+ */
8
+
9
+ // Re-export lifecycle types from core (PRI-51)
10
+ export type {
11
+ LifecycleClassificationTotals,
12
+ RuleReplayEvidence,
13
+ RuleLiveEvidence,
14
+ RuleLineageEvidence,
15
+ ImplementationLifecycleEvidence,
16
+ RuleLifecycleEvidence,
17
+ PrincipleLifecycleEvidence,
18
+ LifecycleReadModel,
19
+ } from '@principles/core/runtime-v2';
20
+
21
+ // Re-export core builder (PRI-56)
22
+ export { buildLifecycleReadModel } from '@principles/core/runtime-v2';
23
+
24
+ // Re-export adapter interface (PRI-56)
25
+ export type { LifecycleDatasource } from '@principles/core/runtime-v2';
26
+
27
+ // Re-export filesystem implementation (PRI-56)
28
+ export { FilesystemLifecycleDatasource, LineageSourceRetiredError } from './filesystem-lifecycle-datasource.js';
29
+
30
+ import { buildLifecycleReadModel } from '@principles/core/runtime-v2';
31
+ import { FilesystemLifecycleDatasource } from './filesystem-lifecycle-datasource.js';
32
+
33
+ /**
34
+ * Backward-compatible wrapper — accepts directory paths like the original API.
35
+ * Existing consumers (lifecycle-refresh, evolution-status, nocturnal-service)
36
+ * continue using this without changes.
37
+ */
38
+ export function buildLifecycleReadModelFromPaths(workspaceDir: string, stateDir: string) {
39
+ return buildLifecycleReadModel(new FilesystemLifecycleDatasource(workspaceDir, stateDir));
243
40
  }