create-principles-disciple 1.92.0 → 1.94.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 (335) hide show
  1. package/console/dist/server/config/AuthConfig.js +6 -0
  2. package/console/dist/server/config/pd-config-store.d.ts +7 -1
  3. package/console/dist/server/config/pd-config-store.js +11 -1
  4. package/console/dist/server/index.js +41 -22
  5. package/console/dist/server/models/ApprovalsConsoleModel.js +4 -12
  6. package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +6 -3
  7. package/console/dist/server/models/ConsoleLifecycleDatasource.js +1 -1
  8. package/console/dist/server/routes/activations.js +4 -0
  9. package/console/dist/server/routes/approvals.js +24 -4
  10. package/console/dist/server/routes/feedback-reports.js +7 -5
  11. package/console/dist/server/routes/lifecycle.js +6 -1
  12. package/console/dist/server/routes/principles.js +10 -2
  13. package/console/dist/server/routes/workspaces.js +4 -0
  14. package/console/dist/ui/components/ui/charts.js +4 -1
  15. package/console/dist/ui/components/ui/markdown.js +9 -5
  16. package/console/dist/ui/utils/enum-labels.js +4 -1
  17. package/console/dist/web/assets/app.js +5 -2
  18. package/core/dist/index.d.ts +2 -3
  19. package/core/dist/index.d.ts.map +1 -1
  20. package/core/dist/index.js +1 -3
  21. package/core/dist/index.js.map +1 -1
  22. package/core/dist/pain-signal.d.ts +11 -71
  23. package/core/dist/pain-signal.d.ts.map +1 -1
  24. package/core/dist/pain-signal.js +10 -120
  25. package/core/dist/pain-signal.js.map +1 -1
  26. package/core/dist/principle-tree-ledger.d.ts +4 -87
  27. package/core/dist/principle-tree-ledger.d.ts.map +1 -1
  28. package/core/dist/principle-tree-ledger.js +51 -148
  29. package/core/dist/principle-tree-ledger.js.map +1 -1
  30. package/core/dist/prompt-builder/__tests__/model-config.test.d.ts +2 -0
  31. package/core/dist/prompt-builder/__tests__/model-config.test.d.ts.map +1 -0
  32. package/core/dist/prompt-builder/__tests__/model-config.test.js +158 -0
  33. package/core/dist/prompt-builder/__tests__/model-config.test.js.map +1 -0
  34. package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts +2 -0
  35. package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts.map +1 -0
  36. package/core/dist/prompt-builder/__tests__/xml-escape.test.js +42 -0
  37. package/core/dist/prompt-builder/__tests__/xml-escape.test.js.map +1 -0
  38. package/core/dist/prompt-builder/index.d.ts +3 -0
  39. package/core/dist/prompt-builder/index.d.ts.map +1 -1
  40. package/core/dist/prompt-builder/index.js +2 -0
  41. package/core/dist/prompt-builder/index.js.map +1 -1
  42. package/core/dist/prompt-builder/model-config.d.ts +42 -0
  43. package/core/dist/prompt-builder/model-config.d.ts.map +1 -0
  44. package/core/dist/prompt-builder/model-config.js +84 -0
  45. package/core/dist/prompt-builder/model-config.js.map +1 -0
  46. package/core/dist/prompt-builder/xml-escape.d.ts +12 -0
  47. package/core/dist/prompt-builder/xml-escape.d.ts.map +1 -0
  48. package/core/dist/prompt-builder/xml-escape.js +19 -0
  49. package/core/dist/prompt-builder/xml-escape.js.map +1 -0
  50. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +265 -20
  51. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  52. package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts +12 -0
  53. package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.d.ts.map +1 -0
  54. package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js +46 -0
  55. package/core/dist/runtime-v2/__tests__/barrel-io-cleanup.test.js.map +1 -0
  56. package/core/dist/runtime-v2/__tests__/io-deletion.test.d.ts +12 -0
  57. package/core/dist/runtime-v2/__tests__/io-deletion.test.d.ts.map +1 -0
  58. package/core/dist/runtime-v2/__tests__/io-deletion.test.js +92 -0
  59. package/core/dist/runtime-v2/__tests__/io-deletion.test.js.map +1 -0
  60. package/core/dist/runtime-v2/__tests__/ledger-codec.test.d.ts +2 -0
  61. package/core/dist/runtime-v2/__tests__/ledger-codec.test.d.ts.map +1 -0
  62. package/core/dist/runtime-v2/__tests__/ledger-codec.test.js +429 -0
  63. package/core/dist/runtime-v2/__tests__/ledger-codec.test.js.map +1 -0
  64. package/core/dist/runtime-v2/__tests__/ledger-store.test.d.ts +2 -0
  65. package/core/dist/runtime-v2/__tests__/ledger-store.test.d.ts.map +1 -0
  66. package/core/dist/runtime-v2/__tests__/ledger-store.test.js +65 -0
  67. package/core/dist/runtime-v2/__tests__/ledger-store.test.js.map +1 -0
  68. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts +2 -0
  69. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts.map +1 -0
  70. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +395 -0
  71. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -0
  72. package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js +146 -0
  73. package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js.map +1 -1
  74. package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts +2 -0
  75. package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.d.ts.map +1 -0
  76. package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.js +150 -0
  77. package/core/dist/runtime-v2/__tests__/pain-signal-unification.test.js.map +1 -0
  78. package/core/dist/runtime-v2/adapter/__tests__/test-double-runtime-adapter.test.js +199 -0
  79. package/core/dist/runtime-v2/adapter/__tests__/test-double-runtime-adapter.test.js.map +1 -1
  80. package/core/dist/runtime-v2/bridge-result-shaper.d.ts +53 -0
  81. package/core/dist/runtime-v2/bridge-result-shaper.d.ts.map +1 -0
  82. package/core/dist/runtime-v2/bridge-result-shaper.js +117 -0
  83. package/core/dist/runtime-v2/bridge-result-shaper.js.map +1 -0
  84. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts +13 -0
  85. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts.map +1 -0
  86. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js +111 -0
  87. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js.map +1 -0
  88. package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts +103 -0
  89. package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts.map +1 -0
  90. package/core/dist/runtime-v2/detection/detection-funnel-policy.js +135 -0
  91. package/core/dist/runtime-v2/detection/detection-funnel-policy.js.map +1 -0
  92. package/core/dist/runtime-v2/detection/index.d.ts +10 -0
  93. package/core/dist/runtime-v2/detection/index.d.ts.map +1 -0
  94. package/core/dist/runtime-v2/detection/index.js +9 -0
  95. package/core/dist/runtime-v2/detection/index.js.map +1 -0
  96. package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js +156 -0
  97. package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js.map +1 -1
  98. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts +12 -0
  99. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts.map +1 -0
  100. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js +181 -0
  101. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js.map +1 -0
  102. package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js +104 -1
  103. package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js.map +1 -1
  104. package/core/dist/runtime-v2/evidence-triage/index.d.ts +3 -0
  105. package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
  106. package/core/dist/runtime-v2/evidence-triage/index.js +3 -0
  107. package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
  108. package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts +128 -0
  109. package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts.map +1 -0
  110. package/core/dist/runtime-v2/evidence-triage/observation-resolver.js +203 -0
  111. package/core/dist/runtime-v2/evidence-triage/observation-resolver.js.map +1 -0
  112. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +4 -0
  113. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
  114. package/core/dist/runtime-v2/evidence-triage/triage-policy.js +66 -9
  115. package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
  116. package/core/dist/runtime-v2/evidence-triage/types.d.ts +14 -0
  117. package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
  118. package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
  119. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +33 -4
  120. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  121. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  122. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +9 -2
  123. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  124. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts +15 -0
  125. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts.map +1 -0
  126. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js +450 -0
  127. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js.map +1 -0
  128. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts +13 -0
  129. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts.map +1 -0
  130. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js +243 -0
  131. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js.map +1 -0
  132. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts +12 -0
  133. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts.map +1 -0
  134. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js +172 -0
  135. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js.map +1 -0
  136. package/core/dist/runtime-v2/index.d.ts +9 -6
  137. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  138. package/core/dist/runtime-v2/index.js +8 -4
  139. package/core/dist/runtime-v2/index.js.map +1 -1
  140. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts +2 -0
  141. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts.map +1 -0
  142. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js +306 -0
  143. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js.map +1 -0
  144. package/core/dist/runtime-v2/internalization/index.d.ts +0 -16
  145. package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
  146. package/core/dist/runtime-v2/internalization/index.js +0 -8
  147. package/core/dist/runtime-v2/internalization/index.js.map +1 -1
  148. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts +15 -0
  149. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts.map +1 -0
  150. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js +179 -0
  151. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js.map +1 -0
  152. package/core/dist/runtime-v2/pain-gate/index.d.ts +10 -0
  153. package/core/dist/runtime-v2/pain-gate/index.d.ts.map +1 -0
  154. package/core/dist/runtime-v2/pain-gate/index.js +9 -0
  155. package/core/dist/runtime-v2/pain-gate/index.js.map +1 -0
  156. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts +121 -0
  157. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts.map +1 -0
  158. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js +157 -0
  159. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js.map +1 -0
  160. package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
  161. package/core/dist/runtime-v2/pain-signal-bridge.js +14 -88
  162. package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
  163. package/core/dist/runtime-v2/pain-signal-observability.d.ts.map +1 -1
  164. package/core/dist/runtime-v2/pain-signal-observability.js +15 -5
  165. package/core/dist/runtime-v2/pain-signal-observability.js.map +1 -1
  166. package/core/dist/runtime-v2/principle-tree/ledger-codec.d.ts +30 -0
  167. package/core/dist/runtime-v2/principle-tree/ledger-codec.d.ts.map +1 -0
  168. package/core/dist/runtime-v2/principle-tree/ledger-codec.js +154 -0
  169. package/core/dist/runtime-v2/principle-tree/ledger-codec.js.map +1 -0
  170. package/core/dist/runtime-v2/types/event-types.d.ts +0 -27
  171. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  172. package/core/dist/runtime-v2/types/event-types.js +2 -17
  173. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  174. package/core/dist/runtime-v2/types/index.d.ts +4 -2
  175. package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
  176. package/core/dist/runtime-v2/types/index.js +4 -1
  177. package/core/dist/runtime-v2/types/index.js.map +1 -1
  178. package/core/dist/runtime-v2/types/ledger-store.d.ts +101 -0
  179. package/core/dist/runtime-v2/types/ledger-store.d.ts.map +1 -0
  180. package/core/dist/runtime-v2/types/ledger-store.js +15 -0
  181. package/core/dist/runtime-v2/types/ledger-store.js.map +1 -0
  182. package/core/dist/runtime-v2/types/pain-signal.d.ts +7 -5
  183. package/core/dist/runtime-v2/types/pain-signal.d.ts.map +1 -1
  184. package/core/dist/runtime-v2/types/pain-signal.js +25 -5
  185. package/core/dist/runtime-v2/types/pain-signal.js.map +1 -1
  186. package/core/package.json +3 -3
  187. package/dist/installer.d.ts.map +1 -1
  188. package/dist/installer.js +9 -3
  189. package/dist/installer.js.map +1 -1
  190. package/dist/mvp-config.d.ts +0 -10
  191. package/dist/mvp-config.d.ts.map +1 -1
  192. package/dist/mvp-config.js +0 -64
  193. package/dist/mvp-config.js.map +1 -1
  194. package/dist/utils/env.d.ts.map +1 -1
  195. package/dist/utils/env.js +10 -4
  196. package/dist/utils/env.js.map +1 -1
  197. package/package.json +1 -1
  198. package/pd-cli/dist/commands/__tests__/legacy-cleanup.test.js +11 -3
  199. package/pd-cli/dist/commands/__tests__/legacy-cleanup.test.js.map +1 -1
  200. package/pd-cli/dist/commands/candidate.d.ts.map +1 -1
  201. package/pd-cli/dist/commands/candidate.js +2 -1
  202. package/pd-cli/dist/commands/candidate.js.map +1 -1
  203. package/pd-cli/dist/commands/health.d.ts.map +1 -1
  204. package/pd-cli/dist/commands/health.js +2 -1
  205. package/pd-cli/dist/commands/health.js.map +1 -1
  206. package/pd-cli/dist/commands/mvp-smoke.js +1 -1
  207. package/pd-cli/dist/commands/mvp-smoke.js.map +1 -1
  208. package/pd-cli/dist/commands/rulecode.js +1 -1
  209. package/pd-cli/dist/commands/rulecode.js.map +1 -1
  210. package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
  211. package/pd-cli/dist/commands/runtime-canary.js +10 -11
  212. package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
  213. package/pd-cli/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
  214. package/pd-cli/dist/commands/runtime-internalization-integrity.js +3 -1
  215. package/pd-cli/dist/commands/runtime-internalization-integrity.js.map +1 -1
  216. package/pd-cli/dist/commands/runtime-internalization-queue.d.ts.map +1 -1
  217. package/pd-cli/dist/commands/runtime-internalization-queue.js +13 -16
  218. package/pd-cli/dist/commands/runtime-internalization-queue.js.map +1 -1
  219. package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  220. package/pd-cli/dist/commands/runtime-internalization-run-once.js +3 -0
  221. package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
  222. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
  223. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js +61 -7
  224. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
  225. package/pd-cli/dist/commands/runtime-uat.d.ts.map +1 -1
  226. package/pd-cli/dist/commands/runtime-uat.js +4 -1
  227. package/pd-cli/dist/commands/runtime-uat.js.map +1 -1
  228. package/pd-cli/dist/commands/runtime.js +1 -1
  229. package/pd-cli/dist/commands/runtime.js.map +1 -1
  230. package/pd-cli/dist/index.js +67 -34
  231. package/pd-cli/dist/index.js.map +1 -1
  232. package/pd-cli/dist/legacy/session-history-import.js +7 -5
  233. package/pd-cli/dist/legacy/session-history-import.js.map +1 -1
  234. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts +2 -0
  235. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts.map +1 -0
  236. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js +314 -0
  237. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js.map +1 -0
  238. package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js +33 -14
  239. package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
  240. package/pd-cli/dist/services/pain-flood-simulation-runner.d.ts.map +1 -1
  241. package/pd-cli/dist/services/pain-flood-simulation-runner.js +6 -2
  242. package/pd-cli/dist/services/pain-flood-simulation-runner.js.map +1 -1
  243. package/pd-cli/dist/services/rulehost-readiness.d.ts +62 -0
  244. package/pd-cli/dist/services/rulehost-readiness.d.ts.map +1 -0
  245. package/pd-cli/dist/services/rulehost-readiness.js +214 -0
  246. package/pd-cli/dist/services/rulehost-readiness.js.map +1 -0
  247. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -1
  248. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
  249. package/pd-cli/dist/services/runtime-adapter-resolver.js +9 -7
  250. package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
  251. package/plugin/dist/commands/capabilities.js +3 -2
  252. package/plugin/dist/commands/disable-impl.js +1 -1
  253. package/plugin/dist/commands/evolution-status.js +0 -2
  254. package/plugin/dist/commands/focus.js +10 -2
  255. package/plugin/dist/commands/rollback-impl.js +1 -1
  256. package/plugin/dist/commands/thinking-os.js +5 -1
  257. package/plugin/dist/core/correction-cue-learner.js +2 -0
  258. package/plugin/dist/core/detection-funnel.d.ts +25 -11
  259. package/plugin/dist/core/detection-funnel.js +32 -80
  260. package/plugin/dist/core/event-log.d.ts +1 -3
  261. package/plugin/dist/core/event-log.js +27 -31
  262. package/plugin/dist/core/evolution-reducer.d.ts +0 -8
  263. package/plugin/dist/core/evolution-reducer.js +9 -19
  264. package/plugin/dist/core/focus-history.js +1 -1
  265. package/plugin/dist/core/hygiene/tracker.js +3 -3
  266. package/plugin/dist/core/pain-diagnostic-gate.d.ts +37 -28
  267. package/plugin/dist/core/pain-diagnostic-gate.js +53 -89
  268. package/plugin/dist/core/pain.d.ts +0 -63
  269. package/plugin/dist/core/pain.js +0 -167
  270. package/plugin/dist/core/paths.d.ts +0 -1
  271. package/plugin/dist/core/paths.js +2 -1
  272. package/plugin/dist/core/principle-compiler/compiler.js +2 -0
  273. package/plugin/dist/core/replay-engine.js +1 -1
  274. package/plugin/dist/core/rule-host.js +3 -1
  275. package/plugin/dist/core/schema/migrations/001-init-trajectory.js +3 -6
  276. package/plugin/dist/core/schema/schema-definitions.js +4 -9
  277. package/plugin/dist/core/thinking-os-parser.js +13 -4
  278. package/plugin/dist/core/trajectory.d.ts +0 -16
  279. package/plugin/dist/core/trajectory.js +9 -60
  280. package/plugin/dist/hooks/after-tool-call-helpers.d.ts +4 -1
  281. package/plugin/dist/hooks/after-tool-call-helpers.js +13 -17
  282. package/plugin/dist/hooks/gate-block-helper.js +57 -17
  283. package/plugin/dist/hooks/lifecycle.js +3 -6
  284. package/plugin/dist/hooks/llm.js +66 -26
  285. package/plugin/dist/hooks/pain.d.ts +3 -1
  286. package/plugin/dist/hooks/pain.js +119 -49
  287. package/plugin/dist/hooks/prompt-helpers.d.ts +87 -0
  288. package/plugin/dist/hooks/prompt-helpers.js +251 -0
  289. package/plugin/dist/hooks/prompt-types.d.ts +66 -0
  290. package/plugin/dist/hooks/prompt-types.js +12 -0
  291. package/plugin/dist/hooks/prompt.d.ts +7 -38
  292. package/plugin/dist/hooks/prompt.js +361 -325
  293. package/plugin/dist/hooks/raw-observation-adapter.d.ts +9 -50
  294. package/plugin/dist/hooks/raw-observation-adapter.js +9 -164
  295. package/plugin/dist/hooks/raw-observation-types.d.ts +6 -57
  296. package/plugin/dist/hooks/raw-observation-types.js +5 -9
  297. package/plugin/dist/hooks/trajectory-collector.d.ts +20 -4
  298. package/plugin/dist/hooks/trajectory-collector.js +95 -156
  299. package/plugin/dist/hooks/triage-adapter.js +6 -26
  300. package/plugin/dist/hooks/trigger-cooldown-tracker.d.ts +12 -0
  301. package/plugin/dist/hooks/trigger-cooldown-tracker.js +25 -0
  302. package/plugin/dist/index.js +7 -2
  303. package/plugin/dist/openclaw-sdk.d.ts +4 -1
  304. package/plugin/dist/service/evolution-worker.js +8 -62
  305. package/plugin/dist/service/internalization-auto-consumer-service.js +2 -1
  306. package/plugin/dist/service/runtime-summary-service.d.ts +0 -2
  307. package/plugin/dist/service/runtime-summary-service.js +8 -5
  308. package/plugin/dist/service/workflow-watchdog.js +2 -1
  309. package/plugin/dist/types/event-types.d.ts +1 -1
  310. package/plugin/dist/utils/retry.js +7 -2
  311. package/plugin/dist/utils/session-key.js +4 -1
  312. package/plugin/scripts/sync-plugin.mjs +33 -22
  313. package/plugin/scripts/validate-live-path.ts +0 -18
  314. package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +20 -11
  315. package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +10 -0
  316. package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +20 -11
  317. package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +10 -0
  318. package/console/dist/server/config/feature-flags.d.ts +0 -25
  319. package/console/dist/server/config/feature-flags.js +0 -101
  320. package/core/dist/io.d.ts +0 -35
  321. package/core/dist/io.d.ts.map +0 -1
  322. package/core/dist/io.js +0 -95
  323. package/core/dist/io.js.map +0 -1
  324. package/pd-cli/dist/commands/central-sync.d.ts +0 -10
  325. package/pd-cli/dist/commands/central-sync.d.ts.map +0 -1
  326. package/pd-cli/dist/commands/central-sync.js +0 -32
  327. package/pd-cli/dist/commands/central-sync.js.map +0 -1
  328. package/pd-cli/dist/services/feature-flag-loader.d.ts +0 -6
  329. package/pd-cli/dist/services/feature-flag-loader.d.ts.map +0 -1
  330. package/pd-cli/dist/services/feature-flag-loader.js +0 -53
  331. package/pd-cli/dist/services/feature-flag-loader.js.map +0 -1
  332. package/plugin/dist/core/observability.d.ts +0 -40
  333. package/plugin/dist/core/observability.js +0 -164
  334. package/plugin/dist/hooks/subagent.d.ts +0 -9
  335. package/plugin/dist/hooks/subagent.js +0 -122
@@ -15,6 +15,8 @@ import { evaluatePainDiagnosticGate } from '../core/pain-diagnostic-gate.js';
15
15
  import { emitPainDetectedEvent } from './pain.js';
16
16
  import { loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
17
17
  import { evaluateEvidenceTriage } from './triage-adapter.js';
18
+ import { evaluateTriggerController } from '@principles/core/runtime-v2';
19
+ import { isSharedCooldownActive, markSharedEpisodeAsDiagnosed } from './trigger-cooldown-tracker.js';
18
20
  import { isRisky } from '../utils/io.js';
19
21
  import { normalizeProfile } from '../core/profile.js';
20
22
  import { SystemLogger } from '../core/system-logger.js';
@@ -78,19 +80,19 @@ export function recordGateBlockAndReturn(wctx, blockCtx, logger) {
78
80
  // so one mild block does not start a long diagnostician run.
79
81
  if (sessionId) {
80
82
  const GATE_BLOCK_PAIN_SCORE = 45; // Must be >= pain_trigger (40) so single gate block can trigger diagnosis (PRI-274)
81
- // Record to trajectory (fire-and-forget, no .pain_flag file needed)
82
- wctx.trajectory?.recordPainEvent?.({
83
- sessionId,
84
- source: 'gate_blocked',
85
- score: GATE_BLOCK_PAIN_SCORE,
86
- reason: `Gate blocked ${toolName} on ${filePath}: ${reason}`,
87
- severity: 'mild',
88
- origin: 'system_infer',
89
- });
90
- // PEAT-B1: Evidence triage (feature-flagged)
91
- let triageAdmitted = true;
92
- const gateBlockTriageFlag = loadFeatureFlagFromConfig(wctx.workspaceDir, 'painEvidenceAdmission');
93
- if (gateBlockTriageFlag.enabled) {
83
+ // PRI-453: Generate painId early. SDK observability path (emitPainDetectedEvent
84
+ // with default recordObservability: true) handles all writes: events_*.jsonl +
85
+ // evolution.jsonl + trajectory.db (with canonicalPainId for dedup). No separate
86
+ // legacy recordPainEvent call needed — avoids double-write to trajectory.db.
87
+ const gatePainId = `gate_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
88
+ // PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
89
+ // When either OFF → Gate A (PainDiagnosticGate, rollback).
90
+ const triageFlag = loadFeatureFlagFromConfig(wctx.workspaceDir, 'painEvidenceAdmission');
91
+ const defaultFlag = loadFeatureFlagFromConfig(wctx.workspaceDir, 'painEvidenceAdmissionDefault');
92
+ const useGateB = triageFlag.enabled && defaultFlag.enabled;
93
+ // PEAT-B1: Evidence triage (runs when Gate B is active)
94
+ const session = getSession(sessionId);
95
+ if (useGateB) {
94
96
  // Load profile with 1MB size guard, matching pain.ts pattern
95
97
  const profilePath = wctx.resolve('PROFILE');
96
98
  let profile = normalizeProfile({});
@@ -115,16 +117,54 @@ export function recordGateBlockAndReturn(wctx, blockCtx, logger) {
115
117
  // weight, NOT the action risk severity. The rulehost principle already determined
116
118
  // this action was important enough to block — that is the real signal.
117
119
  const isUnsafe = isRisky(filePath, profile.risk_paths);
120
+ // PRI-454 P2-1: Pass consecutiveErrors and isRisky to match Gate A's
121
+ // upgrade logic. Rule 3 (consecutiveErrors >= 4 → admit) was being
122
+ // dropped, so non-risky repeated gate blocks never triggered diagnosis.
118
123
  const triage = evaluateEvidenceTriage('rulehost_block', GATE_BLOCK_PAIN_SCORE, {
119
124
  isUnsafeHighConfidence: isUnsafe,
125
+ isRisky: isUnsafe,
126
+ consecutiveErrors: session?.consecutiveErrors,
120
127
  });
121
128
  if (triage.decision !== 'admit') {
122
- triageAdmitted = false;
123
129
  logger.info?.(`[PD_GATE] Triage ${triage.decision}: ${triage.reason}`);
124
130
  }
131
+ else {
132
+ // PRI-454: Gate B path — TriggerController owns admission
133
+ const errorHash = `${toolName}:${filePath}:${reason}`;
134
+ const cooldownActive = isSharedCooldownActive('rulehost_block', sessionId, errorHash);
135
+ const triggerDecision = evaluateTriggerController({
136
+ triageResult: triage,
137
+ isOwnerManual: false,
138
+ isCooldownActive: cooldownActive,
139
+ isValid: true,
140
+ score: GATE_BLOCK_PAIN_SCORE,
141
+ sessionId,
142
+ });
143
+ if (triggerDecision.shouldCreateDiagnosticTask) {
144
+ markSharedEpisodeAsDiagnosed('rulehost_block', sessionId, errorHash);
145
+ void emitPainDetectedEvent(wctx, {
146
+ ts: new Date().toISOString(),
147
+ type: 'pain_detected',
148
+ data: {
149
+ painId: gatePainId,
150
+ painType: 'user_frustration',
151
+ source: 'gate_blocked',
152
+ reason: `Gate blocked ${toolName} on ${filePath}: ${reason}`,
153
+ score: GATE_BLOCK_PAIN_SCORE,
154
+ sessionId,
155
+ agentId: 'main',
156
+ },
157
+ }).catch((emitErr) => {
158
+ logWarn(`[PD_GATE] Failed to emit gate block pain event: ${String(emitErr)}`);
159
+ });
160
+ }
161
+ else {
162
+ logger.info?.(`[PD_GATE] Gate B skipped: ${triggerDecision.reason}`);
163
+ }
164
+ }
125
165
  }
126
- const session = getSession(sessionId);
127
- if (triageAdmitted) {
166
+ else {
167
+ // PRI-454: Gate A path (rollback when either flag is OFF)
128
168
  const gate = evaluatePainDiagnosticGate({
129
169
  source: 'gate_blocked',
130
170
  score: GATE_BLOCK_PAIN_SCORE,
@@ -142,7 +182,7 @@ export function recordGateBlockAndReturn(wctx, blockCtx, logger) {
142
182
  ts: new Date().toISOString(),
143
183
  type: 'pain_detected',
144
184
  data: {
145
- painId: `gate_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
185
+ painId: gatePainId,
146
186
  painType: 'user_frustration',
147
187
  source: 'gate_blocked',
148
188
  reason: `Gate blocked ${toolName} on ${filePath}: ${reason}`,
@@ -120,12 +120,9 @@ export async function extractPainFromSessionFile(sessionFile, ctx) {
120
120
  if (!fs.existsSync(dir))
121
121
  fs.mkdirSync(dir, { recursive: true });
122
122
  fs.appendFileSync(dailyLogPath, entry, 'utf8');
123
- const semanticPath = wctx.resolve('SEMANTIC_PAIN');
124
- const semanticDir = path.dirname(semanticPath);
125
- if (!fs.existsSync(semanticDir))
126
- fs.mkdirSync(semanticDir, { recursive: true });
127
- let semanticEntry = `\n### Sample ${timestamp}\n- Source: compaction\n\n\`\`\`\n${painPoints.join('\n---\n')}\n\`\`\`\n`;
128
- fs.appendFileSync(semanticPath, semanticEntry, 'utf8');
123
+ // SEMANTIC_PAIN (confusion_samples.md) write removed (PRI-451 Wave 1):
124
+ // the file had zero readers. The MEMORY.md write above and the fatal-intercept
125
+ // emitPainDetectedEvent below are both LIVE and remain.
129
126
  const hasFatal = painPoints.some(p => p.includes('[FATAL INTERCEPT]'));
130
127
  if (hasFatal) {
131
128
  // Emit via the Runtime v2 pain chain — no .pain_flag file written
@@ -13,6 +13,8 @@ import { evaluatePainDiagnosticGate } from '../core/pain-diagnostic-gate.js';
13
13
  import { loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
14
14
  import { resolveSourceKind } from './raw-observation-adapter.js';
15
15
  import { evaluateEvidenceTriage } from './triage-adapter.js';
16
+ import { evaluateTriggerController } from '@principles/core/runtime-v2';
17
+ import { isSharedCooldownActive, markSharedEpisodeAsDiagnosed } from './trigger-cooldown-tracker.js';
16
18
  function clamp(value, min, max) {
17
19
  return Math.max(min, Math.min(max, value));
18
20
  }
@@ -194,14 +196,8 @@ export function handleLlmOutput(event, ctx) {
194
196
  const detectionText = isEmpathyAuditPayload(text) ? '' : text;
195
197
  const detectionService = DetectionService.get(wctx.stateDir);
196
198
  const detection = detectionService.detect(detectionText);
197
- if (detection.detected) {
198
- eventLog.recordRuleMatch(ctx.sessionId, {
199
- ruleId: detection.ruleId || detection.source,
200
- layer: detection.source === 'l1_exact' ? 'L1' : (detection.source === 'l2_cache' ? 'L2' : 'L3'),
201
- severity: detection.severity || 0,
202
- textPreview: detectionText.substring(0, 100)
203
- });
204
- }
199
+ // recordRuleMatch call removed (PRI-451 Wave 1): dead code — its only
200
+ // consumer was stats.pain.rulesMatched (dead counter, removed in Wave 1.5).
205
201
  let painScore = detection.detected ? (detection.severity || 0) : 0;
206
202
  let source = detection.detected
207
203
  ? (detection.ruleId ? `llm_${detection.ruleId.toLowerCase()}` : `llm_${detection.source}`)
@@ -247,11 +243,31 @@ export function handleLlmOutput(event, ctx) {
247
243
  matchedReason = `Accumulated GFI (${state.currentGfi.toFixed(1)}) crossed highGfi threshold (${highGfiThreshold}). Source: empathy keyword friction.`;
248
244
  }
249
245
  if (painScore >= painTriggerThreshold) {
250
- // PEAT-B1: Evidence triage (feature-flagged)
251
- let triageAdmitted = true;
252
- const llmTriageFlag = loadFeatureFlagFromConfig(ctx.workspaceDir, 'painEvidenceAdmission');
253
- if (llmTriageFlag.enabled) {
254
- // PRI-360 S1: Build RawObservation for unified source mapping
246
+ // PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
247
+ // When either OFF → Gate A (PainDiagnosticGate, rollback).
248
+ const triageFlag = loadFeatureFlagFromConfig(ctx.workspaceDir, 'painEvidenceAdmission');
249
+ const defaultFlag = loadFeatureFlagFromConfig(ctx.workspaceDir, 'painEvidenceAdmissionDefault');
250
+ const useGateB = triageFlag.enabled && defaultFlag.enabled;
251
+ eventLog.recordPainSignal(ctx.sessionId, {
252
+ score: painScore,
253
+ source: source,
254
+ reason: matchedReason,
255
+ isRisky: false
256
+ });
257
+ // PRI-453: Generate painId early and write to trajectory.db via legacy
258
+ // recordPainEvent so that disabling SDK observability path does not lose
259
+ // trajectory coverage. canonicalPainId enables dedup.
260
+ const painId = `llm_${Date.now()}`;
261
+ wctx.trajectory?.recordPainEvent?.({
262
+ sessionId: ctx.sessionId || 'unknown',
263
+ source,
264
+ score: painScore,
265
+ reason: matchedReason,
266
+ origin: 'system_infer',
267
+ canonicalPainId: painId,
268
+ });
269
+ if (useGateB) {
270
+ // PRI-454: Gate B path — TriggerController owns admission
255
271
  const rawObs = {
256
272
  observedAt: new Date().toISOString(),
257
273
  workspaceId: ctx.workspaceDir,
@@ -262,17 +278,44 @@ export function handleLlmOutput(event, ctx) {
262
278
  const sourceKind = resolveSourceKind(rawObs);
263
279
  const triage = evaluateEvidenceTriage(sourceKind, painScore);
264
280
  if (triage.decision !== 'admit') {
265
- triageAdmitted = false;
266
281
  ctx.logger?.info?.(`[PD:LLM] Triage ${triage.decision}: ${triage.reason}`);
267
282
  }
283
+ else {
284
+ const cooldownActive = isSharedCooldownActive(sourceKind, ctx.sessionId, source);
285
+ const triggerDecision = evaluateTriggerController({
286
+ triageResult: triage,
287
+ isOwnerManual: false,
288
+ isCooldownActive: cooldownActive,
289
+ isValid: true,
290
+ score: painScore,
291
+ sessionId: ctx.sessionId,
292
+ });
293
+ if (triggerDecision.shouldCreateDiagnosticTask) {
294
+ markSharedEpisodeAsDiagnosed(sourceKind, ctx.sessionId, source);
295
+ const evidence = buildTrajectoryEvidence(wctx, ctx.sessionId || 'unknown');
296
+ emitPainDetectedEvent(wctx, {
297
+ ts: new Date().toISOString(),
298
+ type: 'pain_detected',
299
+ data: {
300
+ painId,
301
+ painType: 'user_frustration',
302
+ source,
303
+ reason: `${matchedReason}; trigger=${triggerDecision.outcome}`,
304
+ score: painScore,
305
+ sessionId: ctx.sessionId || 'unknown',
306
+ agentId: ctx.agentId,
307
+ provenance: 'openclaw_context_bound',
308
+ evidence,
309
+ },
310
+ }, { recordObservability: false });
311
+ }
312
+ else {
313
+ ctx.logger?.info?.(`[PD:LLM] Gate B skipped: ${triggerDecision.reason}`);
314
+ }
315
+ }
268
316
  }
269
- eventLog.recordPainSignal(ctx.sessionId, {
270
- score: painScore,
271
- source: source,
272
- reason: matchedReason,
273
- isRisky: false
274
- });
275
- if (triageAdmitted) {
317
+ else {
318
+ // PRI-454: Gate A path (rollback when either flag is OFF)
276
319
  const gate = evaluatePainDiagnosticGate({
277
320
  source: source === 'llm_paralysis' ? 'llm_paralysis' : 'semantic',
278
321
  score: painScore,
@@ -292,7 +335,7 @@ export function handleLlmOutput(event, ctx) {
292
335
  ts: new Date().toISOString(),
293
336
  type: 'pain_detected',
294
337
  data: {
295
- painId: `llm_${Date.now()}`,
338
+ painId,
296
339
  painType: 'user_frustration',
297
340
  source,
298
341
  reason: `${matchedReason}; diagnosticGate=${gate.reason}`,
@@ -302,15 +345,12 @@ export function handleLlmOutput(event, ctx) {
302
345
  provenance: 'openclaw_context_bound',
303
346
  evidence,
304
347
  },
305
- });
348
+ }, { recordObservability: false });
306
349
  }
307
350
  else {
308
351
  ctx.logger?.info?.(`[PD:LLM] Pain signal recorded without Runtime V2 diagnosis: ${gate.detail}`);
309
352
  }
310
353
  }
311
- else {
312
- ctx.logger?.info?.(`[PD:LLM] Triage evidence-only: pain signal recorded without diagnosis or gate evaluation`);
313
- }
314
354
  }
315
355
  // ═══ Thinking OS: Mental Model Usage Tracking ═══
316
356
  trackThinkingModelUsage({
@@ -19,7 +19,9 @@ import type { EvolutionLoopEvent } from '../core/evolution-types.js';
19
19
  import type { PluginHookAfterToolCallEvent, PluginHookToolContext, OpenClawPluginApi } from '../openclaw-sdk.js';
20
20
  import { buildTrajectoryEvidence } from './trajectory-evidence.js';
21
21
  export { buildTrajectoryEvidence };
22
- export declare function emitPainDetectedEvent(wctx: WorkspaceContext, event: EvolutionLoopEvent): Promise<void>;
22
+ export declare function emitPainDetectedEvent(wctx: WorkspaceContext, event: EvolutionLoopEvent, options?: {
23
+ recordObservability?: boolean;
24
+ }): Promise<void>;
23
25
  /**
24
26
  * Handle after_tool_call hook — decomposed into pipeline stages.
25
27
  *
@@ -24,7 +24,11 @@ import { getEvolutionLogger, createTraceId } from '../core/evolution-logger.js';
24
24
  import { resolveWorkspaceDirForRuntimeV2 } from '../utils/workspace-resolver.js';
25
25
  import { PainToPrincipleService, PrincipleTreeLedgerAdapter } from '@principles/core/runtime-v2';
26
26
  import { evaluatePainDiagnosticGate } from '../core/pain-diagnostic-gate.js';
27
- import { loadPdConfigForPlugin } from '../core/pd-config-loader.js';
27
+ import { loadPdConfigForPlugin, loadFeatureFlagFromConfig } from '../core/pd-config-loader.js';
28
+ import { evaluateTriggerController } from '@principles/core/runtime-v2';
29
+ import { isSharedCooldownActive, markSharedEpisodeAsDiagnosed } from './trigger-cooldown-tracker.js';
30
+ import { buildManualPainObservation, resolveSourceKind } from './raw-observation-adapter.js';
31
+ import { evaluateEvidenceTriage } from './triage-adapter.js';
28
32
  import { classifyToolCallOutcome, buildToolCallObservation, handleFrictionTrackingForFailure, handleFrictionTrackingForSuccess, recordHygieneTracking, handleProbationFeedback, evaluatePainAdmissionForToolCall, emitPainIfAdmitted, } from './after-tool-call-helpers.js';
29
33
  import { buildTrajectoryEvidence } from './trajectory-evidence.js';
30
34
  export { buildTrajectoryEvidence };
@@ -44,7 +48,7 @@ function createPainToPrincipleService(wctx) {
44
48
  }
45
49
  // buildTrajectoryEvidence is in ./trajectory-evidence.ts (re-exported above)
46
50
  // ── Pain Event Emission ─────────────────────────────────────────────────────
47
- export async function emitPainDetectedEvent(wctx, event) {
51
+ export async function emitPainDetectedEvent(wctx, event, options) {
48
52
  try {
49
53
  wctx.evolutionReducer.emitSync(event);
50
54
  }
@@ -68,6 +72,10 @@ export async function emitPainDetectedEvent(wctx, event) {
68
72
  score: painData.score,
69
73
  }));
70
74
  }
75
+ // PRI-453: Hook paths that already write events_*.jsonl + trajectory.db
76
+ // via legacy writers pass recordObservability: false to avoid triple-write.
77
+ // CLI pd pain record and paths without legacy writers keep the default true.
78
+ const recordObs = options?.recordObservability ?? true;
71
79
  const result = await service.recordPain({
72
80
  painId: painData.painId,
73
81
  painType: painData.painType,
@@ -80,7 +88,7 @@ export async function emitPainDetectedEvent(wctx, event) {
80
88
  traceId: painData.traceId,
81
89
  provenance: painData.provenance,
82
90
  evidence: painData.evidence,
83
- recordObservability: true,
91
+ recordObservability: recordObs,
84
92
  });
85
93
  if (result.status === 'failed' && result.failureCategory) {
86
94
  SystemLogger.log(wctx.workspaceDir, 'PAIN_SERVICE_FAILED', JSON.stringify({
@@ -216,6 +224,8 @@ function handleManualPain(event, ctx, wctx, workspaceDir, sessionId) {
216
224
  reason: `User intervention: ${reason}`,
217
225
  isRisky: true
218
226
  });
227
+ // PRI-453: Generate painId early to pass as canonicalPainId for dedup.
228
+ const painId = createPainId(sessionId);
219
229
  wctx.trajectory?.recordPainEvent?.({
220
230
  sessionId,
221
231
  source: 'manual',
@@ -223,6 +233,7 @@ function handleManualPain(event, ctx, wctx, workspaceDir, sessionId) {
223
233
  reason: `User intervention: ${reason}`,
224
234
  origin: 'user_manual',
225
235
  text: reason,
236
+ canonicalPainId: painId,
226
237
  });
227
238
  // Log to EvolutionLogger
228
239
  const evoLogger = getEvolutionLogger(workspaceDir, wctx.trajectory);
@@ -234,61 +245,120 @@ function handleManualPain(event, ctx, wctx, workspaceDir, sessionId) {
234
245
  toolName: event.toolName,
235
246
  sessionId,
236
247
  });
237
- // Apply PainDiagnosticGate with cooldown
238
- const session = getSession(sessionId);
239
- const gate = evaluatePainDiagnosticGate({
240
- source: 'manual',
241
- score: 100,
242
- currentGfi: session?.currentGfi ?? 0,
243
- sessionId,
244
- });
245
- if (!gate.shouldDiagnose) {
246
- SystemLogger.log(workspaceDir, 'MANUAL_PAIN_SKIPPED', `Manual pain within cooldown: ${gate.detail}`);
247
- let payload;
248
- try {
249
- payload = JSON.stringify({
250
- reason: gate.reason,
251
- detail: gate.detail,
252
- source: 'manual',
253
- sessionId,
254
- gfi: 0,
255
- score: 100,
256
- });
257
- }
258
- catch (e) {
259
- SystemLogger.log(workspaceDir, 'PAYLOAD_SERIALIZE_FAILED', String(e));
260
- payload = JSON.stringify({ reason: gate.reason, detail: '(log serialization failed)' });
261
- }
262
- SystemLogger.log(workspaceDir, 'PAIN_GATE_REJECTED', payload);
263
- // PEAT-B2: Record trigger decision even when cooldown blocks manual pain
248
+ // PRI-454: Dual-gate migration. When both flags ON → Gate B (TriggerController).
249
+ // When either OFF → Gate A (PainDiagnosticGate, rollback).
250
+ const triageFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmission');
251
+ const defaultFlag = loadFeatureFlagFromConfig(workspaceDir, 'painEvidenceAdmissionDefault');
252
+ const useGateB = triageFlag.enabled && defaultFlag.enabled;
253
+ if (useGateB) {
254
+ // PRI-454: Gate B path — manual pain is owner-reported.
255
+ // isOwnerManual: true → evaluateTriggerController returns manual_owner_admitted
256
+ // (bypasses triage and cooldown per PRODUCT_IDENTITY: owner-governed).
257
+ const rawObs = buildManualPainObservation({ sessionId });
258
+ const sourceKind = resolveSourceKind(rawObs); // → 'owner_reported'
259
+ const triage = evaluateEvidenceTriage(sourceKind, 100); // → 'admit'
260
+ const cooldownActive = isSharedCooldownActive(sourceKind, sessionId, 'manual_pain');
261
+ const triggerDecision = evaluateTriggerController({
262
+ triageResult: triage,
263
+ isOwnerManual: true,
264
+ isCooldownActive: cooldownActive,
265
+ isValid: true,
266
+ score: 100,
267
+ sessionId,
268
+ });
269
+ // PEAT-B2: Record trigger decision
264
270
  const painTriageFlag = loadPdConfigForPlugin(workspaceDir);
265
271
  if (painTriageFlag.effective) {
266
272
  SystemLogger.log(workspaceDir, 'TRIGGER_DECISION', JSON.stringify({
267
- outcome: 'cooldown_skipped',
268
- sourceKind: 'owner_reported',
269
- reason: `Manual pain within cooldown: ${gate.detail}`,
270
- nextAction: 'wait_for_cooldown_or_manual_retrigger',
273
+ outcome: triggerDecision.outcome,
274
+ sourceKind: triggerDecision.sourceKind,
275
+ reason: triggerDecision.reason,
276
+ nextAction: triggerDecision.nextAction,
271
277
  isOwnerManual: true,
272
278
  sessionId,
273
279
  score: 100,
274
280
  }));
275
281
  }
276
- return;
282
+ if (triggerDecision.shouldCreateDiagnosticTask) {
283
+ markSharedEpisodeAsDiagnosed(sourceKind, sessionId, 'manual_pain');
284
+ emitPainDetectedEvent(wctx, {
285
+ ts: new Date().toISOString(),
286
+ type: 'pain_detected',
287
+ data: {
288
+ painId,
289
+ painType: 'user_frustration',
290
+ source: event.toolName,
291
+ reason: `User intervention: ${reason}`,
292
+ score: 100,
293
+ sessionId,
294
+ traceId,
295
+ agentId: ctx.agentId,
296
+ provenance: (sessionId && sessionId !== 'unknown') ? 'openclaw_context_bound' : 'owner_reported_no_host_trace',
297
+ evidence: buildTrajectoryEvidence(wctx, sessionId),
298
+ },
299
+ }, { recordObservability: false });
300
+ }
301
+ else {
302
+ SystemLogger.log(workspaceDir, 'MANUAL_PAIN_SKIPPED', triggerDecision.reason);
303
+ }
277
304
  }
278
- emitPainDetectedEvent(wctx, {
279
- ts: new Date().toISOString(),
280
- type: 'pain_detected',
281
- data: {
282
- painId: createPainId(sessionId),
283
- painType: 'user_frustration',
284
- source: event.toolName,
285
- reason: `User intervention: ${reason}`,
305
+ else {
306
+ // PRI-454: Gate A path (rollback when either flag is OFF)
307
+ const session = getSession(sessionId);
308
+ const gate = evaluatePainDiagnosticGate({
309
+ source: 'manual',
286
310
  score: 100,
311
+ currentGfi: session?.currentGfi ?? 0,
287
312
  sessionId,
288
- traceId,
289
- agentId: ctx.agentId,
290
- provenance: (sessionId && sessionId !== 'unknown') ? 'openclaw_context_bound' : 'owner_reported_no_host_trace',
291
- evidence: buildTrajectoryEvidence(wctx, sessionId),
292
- },
293
- });
313
+ });
314
+ if (!gate.shouldDiagnose) {
315
+ SystemLogger.log(workspaceDir, 'MANUAL_PAIN_SKIPPED', `Manual pain within cooldown: ${gate.detail}`);
316
+ let payload;
317
+ try {
318
+ payload = JSON.stringify({
319
+ reason: gate.reason,
320
+ detail: gate.detail,
321
+ source: 'manual',
322
+ sessionId,
323
+ gfi: 0,
324
+ score: 100,
325
+ });
326
+ }
327
+ catch (e) {
328
+ SystemLogger.log(workspaceDir, 'PAYLOAD_SERIALIZE_FAILED', String(e));
329
+ payload = JSON.stringify({ reason: gate.reason, detail: '(log serialization failed)' });
330
+ }
331
+ SystemLogger.log(workspaceDir, 'PAIN_GATE_REJECTED', payload);
332
+ // PEAT-B2: Record trigger decision even when cooldown blocks manual pain
333
+ const painTriageFlag = loadPdConfigForPlugin(workspaceDir);
334
+ if (painTriageFlag.effective) {
335
+ SystemLogger.log(workspaceDir, 'TRIGGER_DECISION', JSON.stringify({
336
+ outcome: 'cooldown_skipped',
337
+ sourceKind: 'owner_reported',
338
+ reason: `Manual pain within cooldown: ${gate.detail}`,
339
+ nextAction: 'wait_for_cooldown_or_manual_retrigger',
340
+ isOwnerManual: true,
341
+ sessionId,
342
+ score: 100,
343
+ }));
344
+ }
345
+ return;
346
+ }
347
+ emitPainDetectedEvent(wctx, {
348
+ ts: new Date().toISOString(),
349
+ type: 'pain_detected',
350
+ data: {
351
+ painId,
352
+ painType: 'user_frustration',
353
+ source: event.toolName,
354
+ reason: `User intervention: ${reason}`,
355
+ score: 100,
356
+ sessionId,
357
+ traceId,
358
+ agentId: ctx.agentId,
359
+ provenance: (sessionId && sessionId !== 'unknown') ? 'openclaw_context_bound' : 'owner_reported_no_host_trace',
360
+ evidence: buildTrajectoryEvidence(wctx, sessionId),
361
+ },
362
+ }, { recordObservability: false });
363
+ }
294
364
  }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Pure-logic helpers for prompt assembly.
3
+ *
4
+ * Extracted from hooks/prompt.ts per PRI-444. These functions contain NO I/O
5
+ * and NO side effects — they are independently unit-testable.
6
+ *
7
+ * I/O helpers (cachedReadFile, loadContextInjectionConfig, resolveEmpathyObserver)
8
+ * remain in prompt.ts because they depend on module-level cache state and fs.
9
+ *
10
+ * Pattern follows after-tool-call-helpers.ts (PRI-326): plugin-internal
11
+ * decomposition + core pure-function reuse.
12
+ *
13
+ * ERR checklist:
14
+ * EP-01: All unknown inputs use typeof/Object.hasOwn guards, never `as`
15
+ * EP-03: Pure functions never swallow errors; invalid input returns empty string
16
+ * EP-09: Pure functions are independently unit-testable without mocks
17
+ */
18
+ import type { ExtractedUserMessage, CorePrincipleEntry, EvolutionPrincipleEntry, AppendSystemContextParts } from './prompt-types.js';
19
+ /**
20
+ * Extract the actual user message from the raw prompt text.
21
+ *
22
+ * The prompt may contain:
23
+ * - Boot check messages (system-generated, return empty)
24
+ * - Feishu wrapper format 1: "Sender (untrusted metadata): ```json {...}``` text"
25
+ * - Feishu wrapper format 2: "Conversation info (untrusted metadata): ```json {...}``` text"
26
+ * - Clean user message text
27
+ *
28
+ * Also detects empathy observer output (to prevent recursive spawn) and
29
+ * agent-to-agent messages (to skip empathy evaluation).
30
+ *
31
+ * Pure logic — no I/O, no side effects.
32
+ */
33
+ export declare function extractUserMessageFromPrompt(prompt: string, sessionId: string | undefined): ExtractedUserMessage;
34
+ /**
35
+ * Build the minimal Agent Identity section for prependSystemContext.
36
+ *
37
+ * EvolutionWorker-era INTERNAL SYSTEM LAYOUT removed per PRI-294.
38
+ * The EVOLUTION_WORKER PathResolver key and system layout reference are
39
+ * not MVP-Core; agents discover what they need via tool calls.
40
+ *
41
+ * Pure logic — returns a constant string.
42
+ */
43
+ export declare function buildAgentIdentity(): string;
44
+ /**
45
+ * Build the empathy output restriction constraint text.
46
+ *
47
+ * Pure logic — returns a constant string.
48
+ */
49
+ export declare function buildEmpathySilenceConstraint(): string;
50
+ /**
51
+ * Wrap heartbeat checklist content in XML tags.
52
+ *
53
+ * Pure logic — no I/O, no side effects.
54
+ */
55
+ export declare function assembleHeartbeatChecklist(content: string): string;
56
+ /**
57
+ * Format core principles into prompt-ready text.
58
+ *
59
+ * Pure logic — uses escapeXml for safe XML embedding.
60
+ *
61
+ * @param principles Active principles from evolution reducer
62
+ * @returns Formatted lines (empty string if no principles)
63
+ */
64
+ export declare function formatCorePrinciples(principles: CorePrincipleEntry[]): string;
65
+ /**
66
+ * Format evolution principles (active + probation) into prompt-ready text.
67
+ *
68
+ * Pure logic — uses escapeXml for safe XML embedding.
69
+ *
70
+ * @param active Active principles (high priority)
71
+ * @param probation Probation principles (contextual, caution)
72
+ * @returns Formatted lines (empty string if no principles)
73
+ */
74
+ export declare function formatEvolutionPrinciples(active: EvolutionPrincipleEntry[], probation: EvolutionPrincipleEntry[]): string;
75
+ /**
76
+ * Assemble appendSystemContext from ordered parts.
77
+ *
78
+ * Content order (most important last):
79
+ * behavioral_constraints → project_context → working_memory →
80
+ * thinking_os → evolution_principles → core_principles
81
+ *
82
+ * Pure logic — string assembly only, no I/O.
83
+ *
84
+ * @param parts Ordered content parts (empty/undefined parts are skipped)
85
+ * @returns Assembled appendSystemContext (empty string if no parts)
86
+ */
87
+ export declare function assembleAppendSystemContext(parts: AppendSystemContextParts): string;