create-principles-disciple 1.121.7 → 1.121.9

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 (461) hide show
  1. package/README.md +13 -1
  2. package/console/dist/server/config/pd-config-store.d.ts +1 -3
  3. package/console/dist/server/config/pd-config-store.js +4 -4
  4. package/console/dist/server/feedback/channels.d.ts +2 -8
  5. package/console/dist/server/feedback/channels.js +0 -11
  6. package/console/dist/server/index.js +34 -5
  7. package/console/dist/server/models/ActivationsConsoleModel.d.ts +28 -1
  8. package/console/dist/server/models/ActivationsConsoleModel.js +72 -30
  9. package/console/dist/server/models/GovernanceExperienceCollector.d.ts +28 -0
  10. package/console/dist/server/models/GovernanceExperienceCollector.js +305 -0
  11. package/console/dist/server/models/GovernanceProjectionCollector.d.ts +60 -2
  12. package/console/dist/server/models/GovernanceProjectionCollector.js +323 -285
  13. package/console/dist/server/models/PrincipleClassifier.d.ts +1 -1
  14. package/console/dist/server/models/PrincipleClassifier.js +7 -4
  15. package/console/dist/server/models/PrinciplesConsoleModel.d.ts +2 -1
  16. package/console/dist/server/models/ReceiptsConsoleModel.d.ts +5 -0
  17. package/console/dist/server/models/ReceiptsConsoleModel.js +140 -13
  18. package/console/dist/server/routes/activations.js +1 -1
  19. package/console/dist/server/routes/failed-tasks.js +28 -11
  20. package/console/dist/server/routes/governance.d.ts +26 -0
  21. package/console/dist/server/routes/governance.js +51 -0
  22. package/console/dist/server/routes/owner-identity.d.ts +31 -0
  23. package/console/dist/server/routes/owner-identity.js +76 -0
  24. package/console/dist/server/routes/update-history.d.ts +5 -0
  25. package/console/dist/server/routes/update-history.js +50 -4
  26. package/console/dist/server/routes/update.js +186 -32
  27. package/console/dist/shared/feedback-channel-ids.d.ts +13 -0
  28. package/console/dist/shared/feedback-channel-ids.js +12 -0
  29. package/console/dist/shared/feedback-contract.d.ts +46 -0
  30. package/console/dist/shared/feedback-contract.js +45 -0
  31. package/console/dist/ui/App.js +1 -1
  32. package/console/dist/ui/api.d.ts +22 -3
  33. package/console/dist/ui/api.js +63 -3
  34. package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.d.ts +6 -0
  35. package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.js +66 -0
  36. package/console/dist/ui/i18n/en.json +198 -2
  37. package/console/dist/ui/i18n/zh-CN.json +196 -0
  38. package/console/dist/ui/pages/activation/ActivationPage.js +14 -2
  39. package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +25 -5
  40. package/console/dist/ui/pages/focus/FocusPage.d.ts +28 -1
  41. package/console/dist/ui/pages/focus/FocusPage.js +128 -15
  42. package/console/dist/ui/pages/principles/PrincipleDetailPage.d.ts +30 -0
  43. package/console/dist/ui/pages/principles/PrincipleDetailPage.js +49 -6
  44. package/console/dist/ui/pages/settings/SettingsPage.js +67 -2
  45. package/console/dist/ui/pages/settings/UpdatePage.js +7 -7
  46. package/console/dist/ui/utils/enum-labels.js +0 -1
  47. package/console/dist/ui/utils/validators.d.ts +53 -21
  48. package/console/dist/ui/utils/validators.js +248 -21
  49. package/console/dist/web/assets/app.css +6 -0
  50. package/console/dist/web/assets/app.js +2721 -1664
  51. package/console/package.json +4 -2
  52. package/core/dist/host/host-adapter.d.ts +1 -1
  53. package/core/dist/host/host-adapter.d.ts.map +1 -1
  54. package/core/dist/host/host-adapter.js +1 -0
  55. package/core/dist/host/host-adapter.js.map +1 -1
  56. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +12 -2
  57. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  58. package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js +1 -1
  59. package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js.map +1 -1
  60. package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts +2 -0
  61. package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts.map +1 -0
  62. package/core/dist/runtime-v2/__tests__/governance-experience.test.js +300 -0
  63. package/core/dist/runtime-v2/__tests__/governance-experience.test.js.map +1 -0
  64. package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts +2 -0
  65. package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts.map +1 -0
  66. package/core/dist/runtime-v2/__tests__/owner-identity.test.js +147 -0
  67. package/core/dist/runtime-v2/__tests__/owner-identity.test.js.map +1 -0
  68. package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts +18 -0
  69. package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts.map +1 -0
  70. package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js +303 -0
  71. package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js.map +1 -0
  72. package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js +40 -0
  73. package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js.map +1 -1
  74. package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts +2 -0
  75. package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts.map +1 -0
  76. package/core/dist/runtime-v2/__tests__/status-contract.test.js +107 -0
  77. package/core/dist/runtime-v2/__tests__/status-contract.test.js.map +1 -0
  78. package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts +2 -0
  79. package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts.map +1 -0
  80. package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js +104 -0
  81. package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js.map +1 -0
  82. package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js +19 -0
  83. package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js.map +1 -1
  84. package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js +20 -0
  85. package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js.map +1 -1
  86. package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js +40 -0
  87. package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js.map +1 -1
  88. package/core/dist/runtime-v2/activation/index.d.ts +2 -0
  89. package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
  90. package/core/dist/runtime-v2/activation/index.js +1 -0
  91. package/core/dist/runtime-v2/activation/index.js.map +1 -1
  92. package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts +30 -0
  93. package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts.map +1 -0
  94. package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js +87 -0
  95. package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js.map +1 -0
  96. package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts.map +1 -1
  97. package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js +3 -0
  98. package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js.map +1 -1
  99. package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts +1 -1
  100. package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts.map +1 -1
  101. package/core/dist/runtime-v2/activation/promotion-readiness-reader.js +2 -2
  102. package/core/dist/runtime-v2/activation/promotion-readiness-reader.js.map +1 -1
  103. package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts.map +1 -1
  104. package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js +18 -9
  105. package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js.map +1 -1
  106. package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js +1 -1
  107. package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js.map +1 -1
  108. package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js +91 -1
  109. package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js.map +1 -1
  110. package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js +59 -12
  111. package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js.map +1 -1
  112. package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js +10 -9
  113. package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js.map +1 -1
  114. package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js +42 -1
  115. package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js.map +1 -1
  116. package/core/dist/runtime-v2/adapter/json-extractor.d.ts +25 -0
  117. package/core/dist/runtime-v2/adapter/json-extractor.d.ts.map +1 -1
  118. package/core/dist/runtime-v2/adapter/json-extractor.js +126 -0
  119. package/core/dist/runtime-v2/adapter/json-extractor.js.map +1 -1
  120. package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +9 -4
  121. package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -1
  122. package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +9 -4
  123. package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -1
  124. package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts +5 -1
  125. package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts.map +1 -1
  126. package/core/dist/runtime-v2/adapter/output-repair-contract.js +4 -1
  127. package/core/dist/runtime-v2/adapter/output-repair-contract.js.map +1 -1
  128. package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts +7 -0
  129. package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -0
  130. package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +19 -0
  131. package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -0
  132. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +13 -15
  133. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
  134. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +104 -37
  135. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
  136. package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts +16 -1
  137. package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts.map +1 -1
  138. package/core/dist/runtime-v2/adapter/structured-output-repair.js +38 -6
  139. package/core/dist/runtime-v2/adapter/structured-output-repair.js.map +1 -1
  140. package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts +1 -1
  141. package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts.map +1 -1
  142. package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +8 -9
  143. package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
  144. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +27 -3
  145. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
  146. package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts +11 -0
  147. package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts.map +1 -0
  148. package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js +93 -0
  149. package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js.map +1 -0
  150. package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js +41 -0
  151. package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js.map +1 -1
  152. package/core/dist/runtime-v2/config/index.d.ts +2 -2
  153. package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
  154. package/core/dist/runtime-v2/config/index.js +2 -0
  155. package/core/dist/runtime-v2/config/index.js.map +1 -1
  156. package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
  157. package/core/dist/runtime-v2/config/pd-config-agent-binding.js +4 -13
  158. package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
  159. package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
  160. package/core/dist/runtime-v2/config/pd-config-effective.js +14 -7
  161. package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
  162. package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -1
  163. package/core/dist/runtime-v2/config/pd-config-feature-flags.js +5 -12
  164. package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -1
  165. package/core/dist/runtime-v2/config/pd-config-types.d.ts +8 -0
  166. package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
  167. package/core/dist/runtime-v2/config/pd-config-types.js +2 -0
  168. package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
  169. package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
  170. package/core/dist/runtime-v2/config/pd-config-validate.js +48 -3
  171. package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
  172. package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js +36 -8
  173. package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js.map +1 -1
  174. package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js +36 -12
  175. package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js.map +1 -1
  176. package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts +22 -8
  177. package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts.map +1 -1
  178. package/core/dist/runtime-v2/core-principles/core-axiom-block.js +28 -13
  179. package/core/dist/runtime-v2/core-principles/core-axiom-block.js.map +1 -1
  180. package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts +29 -4
  181. package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts.map +1 -1
  182. package/core/dist/runtime-v2/core-principles/core-principle-registry.js +68 -33
  183. package/core/dist/runtime-v2/core-principles/core-principle-registry.js.map +1 -1
  184. package/core/dist/runtime-v2/core-principles/index.d.ts +3 -3
  185. package/core/dist/runtime-v2/core-principles/index.d.ts.map +1 -1
  186. package/core/dist/runtime-v2/core-principles/index.js +1 -1
  187. package/core/dist/runtime-v2/core-principles/index.js.map +1 -1
  188. package/core/dist/runtime-v2/evolution/evolution-types.d.ts +2 -1
  189. package/core/dist/runtime-v2/evolution/evolution-types.d.ts.map +1 -1
  190. package/core/dist/runtime-v2/evolution/evolution-types.js.map +1 -1
  191. package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts +2 -0
  192. package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts.map +1 -0
  193. package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js +48 -0
  194. package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js.map +1 -0
  195. package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts +2 -0
  196. package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts.map +1 -0
  197. package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js +46 -0
  198. package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js.map +1 -0
  199. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +86 -31
  200. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  201. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts +2 -0
  202. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts.map +1 -0
  203. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js +83 -0
  204. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js.map +1 -0
  205. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts +19 -1
  206. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  207. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +128 -10
  208. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  209. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts +37 -0
  210. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts.map +1 -0
  211. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +304 -0
  212. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -0
  213. package/core/dist/runtime-v2/feature-flags/index.d.ts +4 -2
  214. package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
  215. package/core/dist/runtime-v2/feature-flags/index.js +3 -1
  216. package/core/dist/runtime-v2/feature-flags/index.js.map +1 -1
  217. package/core/dist/runtime-v2/governance-experience-contract.d.ts +468 -0
  218. package/core/dist/runtime-v2/governance-experience-contract.d.ts.map +1 -0
  219. package/core/dist/runtime-v2/governance-experience-contract.js +208 -0
  220. package/core/dist/runtime-v2/governance-experience-contract.js.map +1 -0
  221. package/core/dist/runtime-v2/governance-experience.d.ts +11 -0
  222. package/core/dist/runtime-v2/governance-experience.d.ts.map +1 -0
  223. package/core/dist/runtime-v2/governance-experience.js +276 -0
  224. package/core/dist/runtime-v2/governance-experience.js.map +1 -0
  225. package/core/dist/runtime-v2/index.d.ts +20 -8
  226. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  227. package/core/dist/runtime-v2/index.js +20 -6
  228. package/core/dist/runtime-v2/index.js.map +1 -1
  229. package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js +29 -10
  230. package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js.map +1 -1
  231. package/core/dist/runtime-v2/owner-identity.d.ts +69 -0
  232. package/core/dist/runtime-v2/owner-identity.d.ts.map +1 -0
  233. package/core/dist/runtime-v2/owner-identity.js +179 -0
  234. package/core/dist/runtime-v2/owner-identity.js.map +1 -0
  235. package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
  236. package/core/dist/runtime-v2/pain-signal-runtime-factory.js +2 -3
  237. package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
  238. package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts +70 -0
  239. package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts.map +1 -0
  240. package/core/dist/runtime-v2/product-telemetry/daily-identity.js +89 -0
  241. package/core/dist/runtime-v2/product-telemetry/daily-identity.js.map +1 -0
  242. package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts +110 -0
  243. package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts.map +1 -0
  244. package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js +250 -0
  245. package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js.map +1 -0
  246. package/core/dist/runtime-v2/pruning-read-model.d.ts +2 -1
  247. package/core/dist/runtime-v2/pruning-read-model.d.ts.map +1 -1
  248. package/core/dist/runtime-v2/pruning-read-model.js.map +1 -1
  249. package/core/dist/runtime-v2/receipt-coverage.d.ts +63 -0
  250. package/core/dist/runtime-v2/receipt-coverage.d.ts.map +1 -0
  251. package/core/dist/runtime-v2/receipt-coverage.js +19 -0
  252. package/core/dist/runtime-v2/receipt-coverage.js.map +1 -0
  253. package/core/dist/runtime-v2/recovery-actions-log.d.ts +7 -0
  254. package/core/dist/runtime-v2/recovery-actions-log.d.ts.map +1 -1
  255. package/core/dist/runtime-v2/recovery-actions-log.js +6 -0
  256. package/core/dist/runtime-v2/recovery-actions-log.js.map +1 -1
  257. package/core/dist/runtime-v2/runtime-protocol.js +1 -1
  258. package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
  259. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js +17 -1
  260. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js.map +1 -1
  261. package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
  262. package/core/dist/runtime-v2/store/task/sqlite-task-store.js +10 -0
  263. package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
  264. package/core/dist/runtime-v2/store/task/task-types.d.ts +2 -0
  265. package/core/dist/runtime-v2/store/task/task-types.d.ts.map +1 -1
  266. package/core/dist/runtime-v2/task-status.d.ts +9 -5
  267. package/core/dist/runtime-v2/task-status.d.ts.map +1 -1
  268. package/core/dist/runtime-v2/task-status.js +15 -7
  269. package/core/dist/runtime-v2/task-status.js.map +1 -1
  270. package/core/dist/runtime-v2/types/event-types.d.ts +4 -0
  271. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  272. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  273. package/core/dist/runtime-v2/types/index.d.ts +1 -1
  274. package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
  275. package/core/dist/runtime-v2/types/index.js +1 -1
  276. package/core/dist/runtime-v2/types/index.js.map +1 -1
  277. package/core/dist/runtime-v2/types/principle-enums.d.ts +3 -2
  278. package/core/dist/runtime-v2/types/principle-enums.d.ts.map +1 -1
  279. package/core/dist/runtime-v2/types/principle-enums.js +11 -5
  280. package/core/dist/runtime-v2/types/principle-enums.js.map +1 -1
  281. package/core/dist/runtime-v2/types/principle-schema.d.ts +1 -1
  282. package/core/dist/runtime-v2/types/principle-tree-store.d.ts +1 -1
  283. package/core/dist/runtime-v2/utils/cli-process-runner.d.ts.map +1 -1
  284. package/core/dist/runtime-v2/utils/cli-process-runner.js +3 -2
  285. package/core/dist/runtime-v2/utils/cli-process-runner.js.map +1 -1
  286. package/core/package.json +4 -5
  287. package/dist/i18n.d.ts.map +1 -1
  288. package/dist/i18n.js +4 -2
  289. package/dist/i18n.js.map +1 -1
  290. package/dist/index.d.ts +2 -0
  291. package/dist/index.d.ts.map +1 -1
  292. package/dist/index.js +47 -11
  293. package/dist/index.js.map +1 -1
  294. package/dist/installer.d.ts +31 -5
  295. package/dist/installer.d.ts.map +1 -1
  296. package/dist/installer.js +472 -161
  297. package/dist/installer.js.map +1 -1
  298. package/dist/installers/codex-host-installer.d.ts.map +1 -1
  299. package/dist/installers/codex-host-installer.js +4 -0
  300. package/dist/installers/codex-host-installer.js.map +1 -1
  301. package/dist/mvp-config.d.ts +10 -0
  302. package/dist/mvp-config.d.ts.map +1 -1
  303. package/dist/mvp-config.js +30 -3
  304. package/dist/mvp-config.js.map +1 -1
  305. package/dist/uninstaller.d.ts +9 -1
  306. package/dist/uninstaller.d.ts.map +1 -1
  307. package/dist/uninstaller.js +103 -23
  308. package/dist/uninstaller.js.map +1 -1
  309. package/dist/update/atomic-file.d.ts +35 -0
  310. package/dist/update/atomic-file.d.ts.map +1 -0
  311. package/dist/update/atomic-file.js +120 -0
  312. package/dist/update/atomic-file.js.map +1 -0
  313. package/dist/update/bootstrap-protocol.d.ts +55 -0
  314. package/dist/update/bootstrap-protocol.d.ts.map +1 -0
  315. package/dist/update/bootstrap-protocol.js +132 -0
  316. package/dist/update/bootstrap-protocol.js.map +1 -0
  317. package/dist/update/channel-metadata.d.ts +28 -0
  318. package/dist/update/channel-metadata.d.ts.map +1 -0
  319. package/dist/update/channel-metadata.js +90 -0
  320. package/dist/update/channel-metadata.js.map +1 -0
  321. package/dist/update/channel-promotion.d.ts +39 -0
  322. package/dist/update/channel-promotion.d.ts.map +1 -0
  323. package/dist/update/channel-promotion.js +55 -0
  324. package/dist/update/channel-promotion.js.map +1 -0
  325. package/dist/update/data-compatibility.d.ts +35 -0
  326. package/dist/update/data-compatibility.d.ts.map +1 -0
  327. package/dist/update/data-compatibility.js +45 -0
  328. package/dist/update/data-compatibility.js.map +1 -0
  329. package/dist/update/install-layout.d.ts +59 -0
  330. package/dist/update/install-layout.d.ts.map +1 -0
  331. package/dist/update/install-layout.js +127 -0
  332. package/dist/update/install-layout.js.map +1 -0
  333. package/dist/update/legacy-migration.d.ts +56 -0
  334. package/dist/update/legacy-migration.d.ts.map +1 -0
  335. package/dist/update/legacy-migration.js +254 -0
  336. package/dist/update/legacy-migration.js.map +1 -0
  337. package/dist/update/product-identity.d.ts +50 -0
  338. package/dist/update/product-identity.d.ts.map +1 -0
  339. package/dist/update/product-identity.js +63 -0
  340. package/dist/update/product-identity.js.map +1 -0
  341. package/dist/update/release-asset-manifest.d.ts +31 -0
  342. package/dist/update/release-asset-manifest.d.ts.map +1 -0
  343. package/dist/update/release-asset-manifest.js +161 -0
  344. package/dist/update/release-asset-manifest.js.map +1 -0
  345. package/dist/update/release-identity.d.ts +33 -0
  346. package/dist/update/release-identity.d.ts.map +1 -0
  347. package/dist/update/release-identity.js +108 -0
  348. package/dist/update/release-identity.js.map +1 -0
  349. package/dist/update/release-manager.d.ts +96 -0
  350. package/dist/update/release-manager.d.ts.map +1 -0
  351. package/dist/update/release-manager.js +253 -0
  352. package/dist/update/release-manager.js.map +1 -0
  353. package/dist/update/release-metadata.d.ts +57 -0
  354. package/dist/update/release-metadata.d.ts.map +1 -0
  355. package/dist/update/release-metadata.js +200 -0
  356. package/dist/update/release-metadata.js.map +1 -0
  357. package/dist/update/release-policy.d.ts +51 -0
  358. package/dist/update/release-policy.d.ts.map +1 -0
  359. package/dist/update/release-policy.js +103 -0
  360. package/dist/update/release-policy.js.map +1 -0
  361. package/dist/update/rollback-policy.d.ts +56 -0
  362. package/dist/update/rollback-policy.d.ts.map +1 -0
  363. package/dist/update/rollback-policy.js +61 -0
  364. package/dist/update/rollback-policy.js.map +1 -0
  365. package/dist/update/transaction-journal.d.ts +121 -0
  366. package/dist/update/transaction-journal.d.ts.map +1 -0
  367. package/dist/update/transaction-journal.js +333 -0
  368. package/dist/update/transaction-journal.js.map +1 -0
  369. package/dist/update/trust-metadata.d.ts +55 -0
  370. package/dist/update/trust-metadata.d.ts.map +1 -0
  371. package/dist/update/trust-metadata.js +170 -0
  372. package/dist/update/trust-metadata.js.map +1 -0
  373. package/dist/update/update-history.d.ts +46 -0
  374. package/dist/update/update-history.d.ts.map +1 -0
  375. package/dist/update/update-history.js +123 -0
  376. package/dist/update/update-history.js.map +1 -0
  377. package/dist/utils/env.d.ts +7 -0
  378. package/dist/utils/env.d.ts.map +1 -1
  379. package/dist/utils/env.js +134 -44
  380. package/dist/utils/env.js.map +1 -1
  381. package/host-runtime/dist/governance-observation-store.d.ts +172 -0
  382. package/host-runtime/dist/governance-observation-store.js +649 -0
  383. package/host-runtime/dist/index.d.ts +6 -0
  384. package/host-runtime/dist/index.js +8 -0
  385. package/host-runtime/dist/product-telemetry/consent-store.d.ts +107 -0
  386. package/host-runtime/dist/product-telemetry/consent-store.js +329 -0
  387. package/host-runtime/dist/product-telemetry/eligibility.d.ts +53 -0
  388. package/host-runtime/dist/product-telemetry/eligibility.js +69 -0
  389. package/host-runtime/dist/product-telemetry/exporter.d.ts +46 -0
  390. package/host-runtime/dist/product-telemetry/exporter.js +71 -0
  391. package/host-runtime/dist/product-telemetry/milestone-readers.d.ts +61 -0
  392. package/host-runtime/dist/product-telemetry/milestone-readers.js +234 -0
  393. package/host-runtime/dist/product-telemetry/service.d.ts +142 -0
  394. package/host-runtime/dist/product-telemetry/service.js +532 -0
  395. package/host-runtime/dist/product-telemetry/workspace-scope.d.ts +38 -0
  396. package/host-runtime/dist/product-telemetry/workspace-scope.js +64 -0
  397. package/host-runtime/package.json +7 -2
  398. package/install-layout/dist/index.d.ts +48 -0
  399. package/install-layout/dist/index.js +81 -0
  400. package/install-layout/dist/index.test.d.ts +1 -0
  401. package/install-layout/dist/index.test.js +34 -0
  402. package/install-layout/package.json +33 -0
  403. package/package.json +16 -6
  404. package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts +9 -0
  405. package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts.map +1 -0
  406. package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js +76 -0
  407. package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js.map +1 -0
  408. package/pd-cli/dist/commands/__tests__/version.test.d.ts +2 -0
  409. package/pd-cli/dist/commands/__tests__/version.test.d.ts.map +1 -0
  410. package/pd-cli/dist/commands/__tests__/version.test.js +134 -0
  411. package/pd-cli/dist/commands/__tests__/version.test.js.map +1 -0
  412. package/pd-cli/dist/commands/console.d.ts.map +1 -1
  413. package/pd-cli/dist/commands/console.js +29 -10
  414. package/pd-cli/dist/commands/console.js.map +1 -1
  415. package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
  416. package/pd-cli/dist/commands/pain-record.js +6 -15
  417. package/pd-cli/dist/commands/pain-record.js.map +1 -1
  418. package/pd-cli/dist/commands/runtime-activation.d.ts +29 -0
  419. package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
  420. package/pd-cli/dist/commands/runtime-activation.js +70 -31
  421. package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
  422. package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
  423. package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js +2 -2
  424. package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
  425. package/pd-cli/dist/commands/telemetry.d.ts +82 -0
  426. package/pd-cli/dist/commands/telemetry.d.ts.map +1 -0
  427. package/pd-cli/dist/commands/telemetry.js +268 -0
  428. package/pd-cli/dist/commands/telemetry.js.map +1 -0
  429. package/pd-cli/dist/commands/version.d.ts +11 -0
  430. package/pd-cli/dist/commands/version.d.ts.map +1 -0
  431. package/pd-cli/dist/commands/version.js +48 -0
  432. package/pd-cli/dist/commands/version.js.map +1 -0
  433. package/pd-cli/dist/index.js +35 -2
  434. package/pd-cli/dist/index.js.map +1 -1
  435. package/pd-cli/dist/services/version-report.d.ts +44 -0
  436. package/pd-cli/dist/services/version-report.d.ts.map +1 -0
  437. package/pd-cli/dist/services/version-report.js +152 -0
  438. package/pd-cli/dist/services/version-report.js.map +1 -0
  439. package/pd-cli/package.json +3 -2
  440. package/plugin/dist/bundle.js +870 -932
  441. package/plugin/dist/core/init.d.ts +2 -1
  442. package/plugin/dist/core/principle-application-ledger.d.ts +10 -0
  443. package/plugin/dist/core/product-telemetry-trigger.d.ts +14 -0
  444. package/plugin/dist/core/thinking-os-parser.d.ts +5 -2
  445. package/plugin/dist/governance-audit.js +386 -0
  446. package/plugin/dist/hooks/gate-block-helper.d.ts +25 -1
  447. package/plugin/dist/hooks/gate.d.ts +22 -0
  448. package/plugin/dist/openclaw.plugin.json +1 -1
  449. package/plugin/dist/rulehost-evidence.js +832 -0
  450. package/plugin/dist/templates/langs/en/principles/THINKING_OS.md +53 -45
  451. package/plugin/dist/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
  452. package/plugin/dist/templates/langs/zh/principles/THINKING_OS.md +62 -46
  453. package/plugin/dist/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
  454. package/plugin/dist/templates/workspace/.principles/THINKING_OS.md +66 -38
  455. package/plugin/openclaw.plugin.json +1 -1
  456. package/plugin/package.json +1 -1
  457. package/plugin/templates/langs/en/principles/THINKING_OS.md +53 -45
  458. package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
  459. package/plugin/templates/langs/zh/principles/THINKING_OS.md +62 -46
  460. package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
  461. package/plugin/templates/workspace/.principles/THINKING_OS.md +66 -38
package/dist/installer.js CHANGED
@@ -2,15 +2,17 @@ import { existsSync, readdirSync, statSync, readFileSync, writeFileSync, mkdirSy
2
2
  import fse from 'fs-extra';
3
3
  import * as path from 'path';
4
4
  import * as http from 'http';
5
- import { execSync, execFileSync, spawn } from 'child_process';
5
+ import { execFileSync, spawn } from 'child_process';
6
6
  import ora from 'ora';
7
7
  import { select } from '@inquirer/prompts';
8
8
  import { logger } from './utils/logger.js';
9
9
  import { checkOpenClawGateway, stopOpenClawGateway, restartOpenClawGateway } from './utils/env.js';
10
10
  import { t } from './i18n.js';
11
- import { generateConfigYamlContent, HostRuntimeConfigMigrationInfraError, migrateHostRuntimeFlagsInConfigYaml, getConfigYamlPath, readEnabledChannelsFromConfigYaml, getOpenClawDir, getPluginExtDir, getPdBackupsDir, getInstalledPdCliDir, getInstalledBinDir, getInstalledConsoleDir, isWindows, } from './mvp-config.js';
11
+ import { generateConfigYamlContent, HostRuntimeConfigMigrationInfraError, migrateHostRuntimeFlagsInConfigYaml, getConfigYamlPath, readEnabledChannelsFromConfigYaml, getOpenClawDir, getPdDir, getPdRuntimeDir, getInstallManifestPath, getPdRuntimeBackupsDir, getPluginExtDir, getInstalledPluginDir, getInstalledLayoutPackageDir, getPdBackupsDir, getInstalledPdCliDir, getInstalledBinDir, getInstalledConsoleDir, isWindows, } from './mvp-config.js';
12
12
  import { getHostInstallers } from './installers/index.js';
13
+ import { parseInstallManifest } from '@principles/install-layout';
13
14
  import { applySkillLanguageSelection } from './skill-language.js';
15
+ import { parseReleaseAssetIdentity, parseReleaseAssetManifest, ReleaseAssetManifestError, verifyReleaseAssetManifestAsync, verifyReleaseAssetTarget, } from './update/release-asset-manifest.js';
14
16
  /** PRI-343: Keep in sync with @principles/core CONVERSATION_ACCESS_CONFIG_KEY */
15
17
  export const CONVERSATION_ACCESS_CONFIG_KEY = 'allowConversationAccess';
16
18
  function isRecord(value) {
@@ -56,35 +58,125 @@ export function ensureConversationAccess(config) {
56
58
  }
57
59
  const INSTALL_TIMEOUT_MS = parseInt(process.env.PD_INSTALL_TIMEOUT_MS || '300000', 10);
58
60
  // 超时常量
59
- const PD_CLI_VERIFICATION_TIMEOUT_MS = 10_000;
61
+ const PD_CLI_VERIFICATION_TIMEOUT_MS = 30_000;
60
62
  const STORY_A_VERIFICATION_TIMEOUT_MS = 30_000;
61
63
  const CONSOLE_HEALTH_CHECK_TIMEOUT_MS = 8_000;
62
64
  const CONSOLE_WARMUP_TIME_MS = 6_000;
63
- // 端口范围常量
64
- const CONSOLE_PORT_RANGE_MIN = 3100;
65
- const CONSOLE_PORT_RANGE_MAX = 3199;
66
- // Task 8: auto-launch console via `pd console open` after successful install
67
- const CONSOLE_AUTOLAUNCH_BASE_PORT = 3100;
68
- const CONSOLE_AUTOLAUNCH_PORT_SCAN_LIMIT = 20; // 3100..3119 (matches pd console open PORT_FALLBACK_LIMIT)
65
+ // 端口范围常量。PD_CONSOLE_PORT_BASE 允许在操作系统保留了大段端口
66
+ // (如 Windows excludedportrange) 的机器上整体平移探测窗口;未设置时
67
+ // 保持历史默认 3100–3199。resolveConsolePortBase() 是唯一 resolved
68
+ // base:安装验证窗口、console 健康检查、autolaunch 扫描、测试全部
69
+ // 消费它——任何新窗口不得再硬编码第二个 base。
70
+ export function resolveConsolePortBase() {
71
+ const raw = process.env.PD_CONSOLE_PORT_BASE;
72
+ if (raw === undefined)
73
+ return 3100;
74
+ // Number() (not parseInt) so '3300.5' is rejected instead of silently
75
+ // truncating to 3300.
76
+ const parsed = Number(raw);
77
+ if (!Number.isInteger(parsed) || parsed < 1024 || parsed > 65000) {
78
+ throw new Error(`PD_CONSOLE_PORT_BASE must be an integer in [1024, 65000], got: ${JSON.stringify(raw)}`);
79
+ }
80
+ return parsed;
81
+ }
82
+ const CONSOLE_PORT_RANGE_MIN = resolveConsolePortBase();
83
+ const CONSOLE_PORT_RANGE_MAX = CONSOLE_PORT_RANGE_MIN + 99;
84
+ // Task 8: auto-launch console via `pd console open` after successful install.
85
+ // Derived from the SAME resolved base as the verification window above.
86
+ const CONSOLE_AUTOLAUNCH_BASE_PORT = CONSOLE_PORT_RANGE_MIN;
87
+ const CONSOLE_AUTOLAUNCH_PORT_SCAN_LIMIT = 20; // base..base+19 (matches pd console open PORT_FALLBACK_LIMIT)
69
88
  const CONSOLE_AUTOLAUNCH_READY_TIMEOUT_MS = 12_000;
70
89
  const CONSOLE_AUTOLAUNCH_POLL_INTERVAL_MS = 500;
71
90
  // 允许的原生模块白名单
72
91
  const ALLOWED_NATIVE_MODULES = ['better-sqlite3'];
73
- function getCapturingExecOptions(cwd, timeoutOverride) {
74
- return {
75
- cwd,
76
- stdio: 'pipe',
77
- env: process.env,
78
- timeout: timeoutOverride ?? INSTALL_TIMEOUT_MS,
79
- };
92
+ // Shared components use ~/.pd/runtime. The plugin package is host-neutral for
93
+ // Codex-only installs; OpenClaw/all still receive their adapter copy under
94
+ // ~/.openclaw/extensions for host discovery.
95
+ let activeHostTarget = 'openclaw';
96
+ function installsOpenClaw(host) {
97
+ return host === 'openclaw' || host === 'all';
98
+ }
99
+ function installedPluginDir() {
100
+ return getInstalledPluginDir();
101
+ }
102
+ function pluginInstallDirs() {
103
+ return installsOpenClaw(activeHostTarget)
104
+ ? [getInstalledPluginDir(), getPluginExtDir()]
105
+ : [getInstalledPluginDir()];
106
+ }
107
+ export function mergeInstallManifestHosts(current, host) {
108
+ const hosts = new Set();
109
+ const parsed = parseInstallManifest(current);
110
+ if (current !== undefined && !parsed.manifest) {
111
+ throw new Error(parsed.error ?? 'install_manifest_malformed');
112
+ }
113
+ for (const existingHost of parsed.manifest?.hosts ?? [])
114
+ hosts.add(existingHost);
115
+ if (host === 'all' || host === 'codex')
116
+ hosts.add('codex');
117
+ if (host === 'all' || host === 'openclaw')
118
+ hosts.add('openclaw');
119
+ return [...hosts];
120
+ }
121
+ function resolveInstallManifestHosts(host) {
122
+ let current;
123
+ try {
124
+ current = JSON.parse(readFileSync(getInstallManifestPath(), 'utf8'));
125
+ }
126
+ catch (error) {
127
+ if (existsSync(getInstallManifestPath()))
128
+ throw error;
129
+ }
130
+ return mergeInstallManifestHosts(current, host);
131
+ }
132
+ function writeInstallManifest(hosts) {
133
+ mkdirSync(getPdDir(), { recursive: true });
134
+ writeFileSync(getInstallManifestPath(), JSON.stringify({ layoutVersion: 1, mode: 'canonical', hosts }, null, 2) + '\n', 'utf8');
135
+ }
136
+ function installBundledLayoutPackage(pluginDir) {
137
+ const source = path.join(pluginDir, 'install-layout');
138
+ const destination = getInstalledLayoutPackageDir();
139
+ if (!existsSync(path.join(source, 'package.json')) || !existsSync(path.join(source, 'dist'))) {
140
+ throw new Error('Bundled @principles/install-layout is incomplete. Re-run the installer with a current package.');
141
+ }
142
+ rmSync(destination, { recursive: true, force: true });
143
+ cpSync(source, destination, { recursive: true });
144
+ }
145
+ /**
146
+ * Run npm with array-form argv, no shell (PRI-569 hardening).
147
+ *
148
+ * On Windows `npm` is an npm.cmd shim: Node cannot spawn .cmd without a
149
+ * shell (EINVAL/ENOENT), so win32 routes through cmd.exe with CONSTANT argv
150
+ * elements — args are compile-time literals at every call site; the one
151
+ * external-derived value (registry version) is regex-guarded before use.
152
+ * Returns captured stdout (encoding utf-8).
153
+ */
154
+ function execNpm(args, cwd, timeoutOverride) {
155
+ // encoding:'utf-8' resolves the string overload of execFileSync (TS-typed);
156
+ // callers and tests must honor that contract (string output).
157
+ return (process.platform === 'win32'
158
+ ? execFileSync('cmd.exe', ['/c', 'npm', ...args], {
159
+ cwd,
160
+ encoding: 'utf-8',
161
+ stdio: 'pipe',
162
+ env: process.env,
163
+ windowsHide: true,
164
+ timeout: timeoutOverride ?? INSTALL_TIMEOUT_MS,
165
+ })
166
+ : execFileSync('npm', args, {
167
+ cwd,
168
+ encoding: 'utf-8',
169
+ stdio: 'pipe',
170
+ env: process.env,
171
+ timeout: timeoutOverride ?? INSTALL_TIMEOUT_MS,
172
+ })).trim();
80
173
  }
81
174
  /**
82
175
  * 执行 npm install 并提供友好的错误提示
83
176
  */
84
177
  async function runNpmInstall(cwd, componentName = 'npm') {
85
- const execOpts = getCapturingExecOptions(cwd);
86
178
  try {
87
- execSync('npm install --ignore-scripts --legacy-peer-deps', execOpts);
179
+ execNpm(['install', '--ignore-scripts', '--legacy-peer-deps'], cwd);
88
180
  }
89
181
  catch (e) {
90
182
  const errorMsg = e instanceof Error ? e.message : String(e);
@@ -101,23 +193,10 @@ async function runNpmInstall(cwd, componentName = 'npm') {
101
193
  }
102
194
  }
103
195
  /**
104
- * 重建原生模块
105
- */
106
- export async function rebuildNativeModules(cwd, componentName) {
107
- for (const mod of ALLOWED_NATIVE_MODULES) {
108
- const modPath = path.join(cwd, 'node_modules', mod);
109
- if (!existsSync(modPath))
110
- continue;
111
- try {
112
- execSync(`npm rebuild ${mod}`, getCapturingExecOptions(cwd));
113
- }
114
- catch (e) {
115
- throw new Error(`${componentName} native module ${mod} rebuild failed: ${e instanceof Error ? e.message : String(e)}. Try manually: cd ${cwd} && npm rebuild ${mod}`, { cause: e });
116
- }
117
- }
118
- }
119
- /**
120
- * 验证原生模块
196
+ * 验证原生模块:better-sqlite3 随发布资产携带 prebuilt 二进制
197
+ * (prebuilds/*.node),node-gyp-build 在 require 时解析——无需(也没有)
198
+ * npm rebuild 步骤。本函数的 require 探针就是唯一验证(历史上存在一个
199
+ * 名为 rebuildNativeModules 的空壳函数,已删除以避免误导维护者)。
121
200
  */
122
201
  export function verifyNativeModules(cwd, componentName) {
123
202
  for (const nativeMod of ALLOWED_NATIVE_MODULES) {
@@ -128,10 +207,147 @@ export function verifyNativeModules(cwd, componentName) {
128
207
  execFileSync(process.execPath, ['-e', `require('${nativeMod}')`], { cwd, stdio: 'pipe' });
129
208
  }
130
209
  catch {
131
- throw new Error(`${componentName} native module ${nativeMod} verification failed after rebuild. The install cannot proceed.`);
210
+ throw new Error(`${componentName} native module ${nativeMod} failed its require probe: the prebuilt binary for this Node.js ABI is missing or incompatible (no rebuild step exists by design). Install the platform release asset matching this OS, architecture, and ABI.`);
132
211
  }
133
212
  }
134
213
  }
214
+ const SELF_CONTAINED_DEPENDENCY_NEXT_ACTION = 'Install a complete platform release asset for this Node.js ABI and re-run the installer.';
215
+ const SELF_CONTAINED_NATIVE_NEXT_ACTION = 'Install the platform release asset matching this operating system, architecture, and Node.js ABI.';
216
+ export class SelfContainedDependencyError extends Error {
217
+ reason;
218
+ nextAction;
219
+ component;
220
+ dependency;
221
+ constructor(options) {
222
+ super(options.message, { cause: options.cause });
223
+ this.name = 'SelfContainedDependencyError';
224
+ this.reason = options.reason;
225
+ this.nextAction = options.nextAction;
226
+ this.component = options.component;
227
+ this.dependency = options.dependency;
228
+ }
229
+ }
230
+ function legacyNpmInstallEnabled() {
231
+ const value = process.env.PD_ALLOW_LEGACY_NPM_INSTALL;
232
+ return value === '1' || value === 'true';
233
+ }
234
+ /**
235
+ * Supported release assets are self-contained: installation validates the
236
+ * copied component and never resolves dependencies or runs lifecycle scripts.
237
+ * The old npm path remains opt-in for development/legacy recovery only.
238
+ */
239
+ export async function prepareBundledComponentDependencies(cwd, componentName) {
240
+ const packageJsonPath = path.join(cwd, 'package.json');
241
+ let packageJsonRaw;
242
+ try {
243
+ packageJsonRaw = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
244
+ }
245
+ catch (error) {
246
+ throw new SelfContainedDependencyError({
247
+ reason: 'self_contained_package_manifest_invalid',
248
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
249
+ message: `${componentName} package.json is missing or malformed after copy.`,
250
+ component: componentName,
251
+ cause: error,
252
+ });
253
+ }
254
+ if (!isRecord(packageJsonRaw)) {
255
+ throw new SelfContainedDependencyError({
256
+ reason: 'self_contained_package_manifest_invalid',
257
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
258
+ message: `${componentName} package.json must contain an object.`,
259
+ component: componentName,
260
+ });
261
+ }
262
+ const { dependencies } = packageJsonRaw;
263
+ if (dependencies !== undefined && !isRecord(dependencies)) {
264
+ throw new SelfContainedDependencyError({
265
+ reason: 'self_contained_package_manifest_invalid',
266
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
267
+ message: `${componentName} package.json dependencies must contain an object.`,
268
+ component: componentName,
269
+ });
270
+ }
271
+ for (const dependency of Object.keys(dependencies ?? {})) {
272
+ if (!existsSync(path.join(cwd, 'node_modules', dependency))) {
273
+ throw new SelfContainedDependencyError({
274
+ reason: 'self_contained_runtime_dependency_missing',
275
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
276
+ message: `${componentName} self-contained release asset is missing declared runtime dependency ${dependency}.`,
277
+ component: componentName,
278
+ dependency,
279
+ });
280
+ }
281
+ }
282
+ try {
283
+ verifyNativeModules(cwd, componentName);
284
+ }
285
+ catch (error) {
286
+ throw new SelfContainedDependencyError({
287
+ reason: 'self_contained_native_module_unloadable',
288
+ nextAction: SELF_CONTAINED_NATIVE_NEXT_ACTION,
289
+ message: `${componentName} bundled better-sqlite3 cannot be loaded by this Node.js runtime.`,
290
+ component: componentName,
291
+ dependency: 'better-sqlite3',
292
+ cause: error,
293
+ });
294
+ }
295
+ }
296
+ const SELF_CONTAINED_COMPONENTS = [
297
+ ['Core', 'core'],
298
+ ['Host runtime', 'host-runtime'],
299
+ ['Plugin', 'plugin'],
300
+ ['PD CLI', 'pd-cli'],
301
+ ['Console', 'console'],
302
+ ['Install layout', 'install-layout'],
303
+ ];
304
+ export async function preflightSelfContainedReleaseAsset(assetDir) {
305
+ const identityPath = path.join(assetDir, '_release', 'asset.json');
306
+ let identityValue;
307
+ try {
308
+ identityValue = JSON.parse(readFileSync(identityPath, 'utf8'));
309
+ const identity = parseReleaseAssetIdentity(identityValue);
310
+ verifyReleaseAssetTarget(identity, {
311
+ platform: process.platform,
312
+ arch: process.arch,
313
+ nodeAbi: process.versions.modules,
314
+ });
315
+ }
316
+ catch (error) {
317
+ const targetMismatch = error instanceof ReleaseAssetManifestError && error.code === 'asset_target_mismatch';
318
+ throw new SelfContainedDependencyError({
319
+ reason: targetMismatch ? 'self_contained_asset_target_mismatch' : 'self_contained_asset_identity_invalid',
320
+ nextAction: targetMismatch ? SELF_CONTAINED_NATIVE_NEXT_ACTION : SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
321
+ message: error instanceof Error ? error.message : 'Release asset identity is missing or malformed.',
322
+ component: 'Release asset',
323
+ cause: error,
324
+ });
325
+ }
326
+ try {
327
+ const manifestValue = JSON.parse(readFileSync(path.join(assetDir, '_release', 'manifest.json'), 'utf8'));
328
+ await verifyReleaseAssetManifestAsync(assetDir, parseReleaseAssetManifest(manifestValue));
329
+ }
330
+ catch (error) {
331
+ throw new SelfContainedDependencyError({
332
+ reason: 'self_contained_asset_integrity_invalid',
333
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
334
+ message: error instanceof Error ? error.message : 'Release asset manifest is missing, malformed, or does not match its files.',
335
+ component: 'Release asset',
336
+ cause: error,
337
+ });
338
+ }
339
+ for (const [componentName, componentDirectory] of SELF_CONTAINED_COMPONENTS) {
340
+ await prepareBundledComponentDependencies(path.join(assetDir, componentDirectory), componentName);
341
+ }
342
+ }
343
+ async function prepareComponentDependencies(cwd, componentName) {
344
+ if (!legacyNpmInstallEnabled()) {
345
+ await prepareBundledComponentDependencies(cwd, componentName);
346
+ return;
347
+ }
348
+ await runNpmInstall(cwd, componentName);
349
+ verifyNativeModules(cwd, componentName);
350
+ }
135
351
  /**
136
352
  * 验证路径是否在工作区目录内,防止路径遍历攻击
137
353
  */
@@ -147,17 +363,18 @@ const INSTALL_STEPS = [
147
363
  { name: 'Checking workspace rule compatibility', weight: 1 },
148
364
  { name: 'Backing up existing install', weight: 3 },
149
365
  { name: 'Installing bundled @principles/core', weight: 8 },
366
+ { name: 'Validating bundled core dependencies', weight: 5 },
150
367
  { name: 'Installing bundled @principles/host-runtime', weight: 3 },
151
- { name: 'Installing core dependencies', weight: 10 },
368
+ { name: 'Validating bundled host runtime dependencies', weight: 5 },
152
369
  { name: 'Installing plugin', weight: 10 },
153
370
  { name: 'Preparing core library for plugin', weight: 3 },
154
- { name: 'Installing plugin dependencies', weight: 20 },
371
+ { name: 'Validating bundled plugin dependencies', weight: 10 },
155
372
  { name: 'Installing pd CLI', weight: 8 },
156
373
  { name: 'Preparing core library for pd-cli', weight: 3 },
157
374
  { name: 'Verifying pd CLI', weight: 3 },
158
375
  { name: 'Installing pd-console', weight: 8 },
159
376
  { name: 'Preparing core library for console', weight: 3 },
160
- { name: 'Installing console dependencies', weight: 10 },
377
+ { name: 'Validating bundled console dependencies', weight: 5 },
161
378
  { name: 'Verifying pd-console', weight: 3 },
162
379
  { name: 'Copying templates', weight: 3 },
163
380
  { name: 'Generating config.yaml', weight: 2 },
@@ -224,34 +441,51 @@ export function migrateLegacyPdBackups() {
224
441
  /**
225
442
  * Exported for real-filesystem tests (tests/backup-location.test.ts).
226
443
  */
227
- export function backupExistingInstall() {
444
+ export function backupExistingInstall(host = 'openclaw') {
228
445
  const extDir = getPluginExtDir();
229
- if (!existsSync(extDir))
446
+ const runtimeDir = getPdRuntimeDir();
447
+ const hasExt = installsOpenClaw(host) && existsSync(extDir);
448
+ const hasRuntime = existsSync(runtimeDir);
449
+ if (!hasExt && !hasRuntime)
230
450
  return { type: 'no_existing', backupDir: null };
231
451
  // The backup must live OUTSIDE the extensions dir (see getPdBackupsDir):
232
452
  // OpenClaw plugin discovery scans every extensions/ child directory and
233
453
  // would discover the backup as a second principles-disciple plugin.
234
- const backupsDir = getPdBackupsDir();
235
- const backupDir = path.join(backupsDir, `principles-disciple.backup.${Date.now()}`);
454
+ const backupsDir = hasExt ? getPdBackupsDir() : getPdRuntimeBackupsDir();
455
+ const timestamp = Date.now();
456
+ const backupDir = hasExt ? path.join(backupsDir, `principles-disciple.backup.${timestamp}`) : null;
457
+ const runtimeBackupDir = hasRuntime ? path.join(getPdRuntimeBackupsDir(), `runtime.backup.${timestamp}`) : null;
236
458
  try {
237
459
  mkdirSync(backupsDir, { recursive: true });
238
- renameSync(extDir, backupDir);
239
- logger.info(`Backed up existing install to ${backupDir}`);
240
- return { type: 'backed_up', backupDir };
460
+ if (backupDir)
461
+ renameSync(extDir, backupDir);
462
+ if (runtimeBackupDir) {
463
+ mkdirSync(getPdRuntimeBackupsDir(), { recursive: true });
464
+ renameSync(runtimeDir, runtimeBackupDir);
465
+ }
466
+ logger.info(`Backed up existing install to ${backupDir ?? runtimeBackupDir}`);
467
+ return { type: 'backed_up', backupDir, runtimeBackupDir };
241
468
  }
242
469
  catch (e) {
243
470
  throw new Error(`Could not backup existing install at ${extDir}: ${e instanceof Error ? e.message : String(e)}. Aborting to prevent data loss — resolve the lock or rename manually and re-run.`, { cause: e });
244
471
  }
245
472
  }
246
- function restoreBackup(backupDir) {
247
- if (!backupDir || !existsSync(backupDir))
473
+ function restoreBackup(backupDir, runtimeBackupDir) {
474
+ if ((!backupDir || !existsSync(backupDir)) && (!runtimeBackupDir || !existsSync(runtimeBackupDir)))
248
475
  return { restored: true };
249
476
  const extDir = getPluginExtDir();
477
+ const runtimeDir = getPdRuntimeDir();
250
478
  try {
251
- if (existsSync(extDir)) {
479
+ if (backupDir && existsSync(extDir)) {
252
480
  rmSync(extDir, { recursive: true, force: true });
253
481
  }
254
- renameSync(backupDir, extDir);
482
+ if (backupDir && existsSync(backupDir))
483
+ renameSync(backupDir, extDir);
484
+ if (runtimeBackupDir && existsSync(runtimeBackupDir)) {
485
+ if (existsSync(runtimeDir))
486
+ rmSync(runtimeDir, { recursive: true, force: true });
487
+ renameSync(runtimeBackupDir, runtimeDir);
488
+ }
255
489
  logger.info('Restored previous install from backup');
256
490
  return { restored: true };
257
491
  }
@@ -261,14 +495,16 @@ function restoreBackup(backupDir) {
261
495
  return { restored: false, error: msg };
262
496
  }
263
497
  }
264
- function cleanupBackup(backupDir) {
265
- if (!backupDir || !existsSync(backupDir))
266
- return;
267
- try {
268
- rmSync(backupDir, { recursive: true, force: true });
269
- }
270
- catch {
271
- // non-fatal
498
+ function cleanupBackup(backupDir, runtimeBackupDir) {
499
+ for (const backup of [backupDir, runtimeBackupDir]) {
500
+ if (!backup || !existsSync(backup))
501
+ continue;
502
+ try {
503
+ rmSync(backup, { recursive: true, force: true });
504
+ }
505
+ catch {
506
+ // non-fatal
507
+ }
272
508
  }
273
509
  }
274
510
  /**
@@ -532,17 +768,28 @@ export async function checkBuiltPlugin(pluginDir) {
532
768
  }
533
769
  }
534
770
  export async function installPluginToStaging(pluginDir, language) {
535
- const extDir = getPluginExtDir();
536
771
  const builtPluginDir = path.join(pluginDir, 'plugin');
537
- await fse.ensureDir(extDir);
538
- await fse.copy(builtPluginDir, extDir, { overwrite: true });
539
- // Skill-language selection: OpenClaw publishes skills by name with no
540
- // locale mechanism, so the installed manifest must declare exactly one
541
- // language root. The shipped manifest declares zh (product default);
542
- // --lang en installs rewrite it to the en root here.
543
- const selection = applySkillLanguageSelection(extDir, language);
544
- if (!selection.applied) {
545
- logger.warn(`Skill language "${language}" not applied (${selection.note ?? 'unknown'}) — published skills stay at the manifest default`);
772
+ for (const targetDir of pluginInstallDirs()) {
773
+ await fse.ensureDir(targetDir);
774
+ await fse.copy(builtPluginDir, targetDir, { overwrite: true });
775
+ // The published plugin declares its bundled core as file:./core. Keep that
776
+ // package-local contract while storing the actual core once in the shared
777
+ // host-neutral runtime directory.
778
+ const pluginCoreLink = path.join(targetDir, 'core');
779
+ if (!existsSync(pluginCoreLink)) {
780
+ const coreDir = path.join(getPdRuntimeDir(), 'core');
781
+ if (isWindows())
782
+ symlinkSync(coreDir, pluginCoreLink, 'junction');
783
+ else
784
+ symlinkSync(path.relative(targetDir, coreDir), pluginCoreLink, 'dir');
785
+ }
786
+ // OpenClaw publishes skills by name with no locale mechanism. Applying the
787
+ // same selected language to both copies also keeps the canonical package
788
+ // ready if another host is attached later.
789
+ const selection = applySkillLanguageSelection(targetDir, language);
790
+ if (!selection.applied) {
791
+ logger.warn(`Skill language "${language}" not applied at ${targetDir} (${selection.note ?? 'unknown'}) — published skills stay at the manifest default`);
792
+ }
546
793
  }
547
794
  }
548
795
  // ADR-0020 §2.3: The OpenClaw config write logic previously lived here as
@@ -551,42 +798,13 @@ export async function installPluginToStaging(pluginDir, language) {
551
798
  // `runHostInstallers()` below. This file no longer writes openclaw.json
552
799
  // directly — the HostInstaller interface keeps install/uninstall host-agnostic.
553
800
  async function installPluginDependencies() {
554
- const extDir = getPluginExtDir();
555
- const packageJsonPath = path.join(extDir, 'package.json');
556
- const nodeModulesPath = path.join(extDir, 'node_modules');
557
- if (!existsSync(packageJsonPath)) {
558
- throw new Error('Plugin package.json not found after copy — install is corrupted');
559
- }
560
- const packageJsonRaw = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
561
- if (typeof packageJsonRaw !== 'object' || packageJsonRaw === null || Array.isArray(packageJsonRaw)) {
562
- throw new Error('Plugin package.json is malformed');
563
- }
564
- const pkg = packageJsonRaw;
565
- const deps = (typeof pkg.dependencies === 'object' && pkg.dependencies !== null && !Array.isArray(pkg.dependencies))
566
- ? Object.keys(pkg.dependencies)
567
- : [];
568
- const devDeps = (typeof pkg.devDependencies === 'object' && pkg.devDependencies !== null && !Array.isArray(pkg.devDependencies))
569
- ? Object.keys(pkg.devDependencies)
570
- : [];
571
- const allDeps = [...deps, ...devDeps];
572
- let needsInstall = !existsSync(nodeModulesPath);
573
- if (!needsInstall) {
574
- for (const dep of allDeps) {
575
- if (!existsSync(path.join(extDir, 'node_modules', dep))) {
576
- needsInstall = true;
577
- break;
578
- }
579
- }
580
- }
581
- if (needsInstall) {
582
- await runNpmInstall(extDir, 'Plugin');
801
+ for (const extDir of pluginInstallDirs()) {
802
+ await prepareComponentDependencies(extDir, 'Plugin');
583
803
  }
584
- await rebuildNativeModules(extDir, 'Plugin');
585
- verifyNativeModules(extDir, 'Plugin');
586
804
  }
587
805
  function getNpmGlobalBinDir() {
588
806
  try {
589
- const prefix = execSync('npm prefix -g', { encoding: 'utf-8', stdio: 'pipe' }).trim();
807
+ const prefix = execNpm(['prefix', '-g']).trim();
590
808
  if (!prefix)
591
809
  return null;
592
810
  return process.platform === 'win32' ? prefix : path.join(prefix, 'bin');
@@ -596,6 +814,10 @@ function getNpmGlobalBinDir() {
596
814
  }
597
815
  }
598
816
  function installGlobalPdShim() {
817
+ if (!legacyNpmInstallEnabled()) {
818
+ logger.info('Skipping npm global shim discovery for the self-contained release asset.');
819
+ return false;
820
+ }
599
821
  // Allow skipping global shim installation in smoke tests to avoid
600
822
  // polluting the host's npm global bin dir. The bundled pd-cli is
601
823
  // still installed locally (getInstalledBinDir); only the global
@@ -630,6 +852,10 @@ function installGlobalPdShim() {
630
852
  }
631
853
  }
632
854
  function tryUpgradePdCliFromNpm(installedPdCliDir) {
855
+ if (!legacyNpmInstallEnabled()) {
856
+ logger.info('Skipping npm pd-cli upgrade for the self-contained release asset.');
857
+ return;
858
+ }
633
859
  // Allow skipping the npm upgrade in smoke tests / offline environments.
634
860
  // The bundled pd-cli is built from the current repo state and is the
635
861
  // authoritative version for testing. Upgrading to an npm-published version
@@ -640,12 +866,11 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
640
866
  return;
641
867
  }
642
868
  try {
643
- const npmVersion = execSync('npm view @principles/pd-cli version', {
644
- encoding: 'utf-8',
645
- timeout: 15_000,
646
- stdio: ['pipe', 'pipe', 'pipe'],
647
- }).trim();
648
- if (!npmVersion || !/^\d+\.\d+\.\d+/.test(npmVersion))
869
+ const npmVersion = execNpm(['view', '@principles/pd-cli', 'version'], undefined, 15_000).trim();
870
+ // Fully anchored semver: this value is interpolated into a cmd.exe
871
+ // command line below, so a registry response carrying shell
872
+ // metacharacters after a valid-looking prefix must be rejected outright.
873
+ if (!npmVersion || !/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/.test(npmVersion))
649
874
  return;
650
875
  const localPkgPath = path.join(installedPdCliDir, 'package.json');
651
876
  const localPkg = JSON.parse(readFileSync(localPkgPath, 'utf-8'));
@@ -656,11 +881,29 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
656
881
  const tmpDir = path.join(installedPdCliDir, '__npm_upgrade_tmp');
657
882
  try {
658
883
  mkdirSync(tmpDir, { recursive: true });
659
- execSync(`npm pack @principles/pd-cli@${npmVersion} --pack-destination "${tmpDir}"`, {
660
- encoding: 'utf-8',
661
- timeout: 30_000,
662
- stdio: ['pipe', 'pipe', 'pipe'],
663
- });
884
+ // Platform dispatch (CodeRabbit review): cmd.exe does not exist on
885
+ // POSIX, where npm is a real executable and can be spawned directly.
886
+ // The only registry-derived value on this command line is npmVersion,
887
+ // restricted to a metacharacter-free semver charset by the anchored
888
+ // check above; tmpDir is the local install root (profile-derived, not
889
+ // attacker-controlled). CodeQL's js/indirect-command-line-injection
890
+ // cannot model the regex sanitizer — see the evidence-based dismissal
891
+ // on alert 431.
892
+ const packArgs = ['pack', `@principles/pd-cli@${npmVersion}`, '--pack-destination', tmpDir];
893
+ if (process.platform === 'win32') {
894
+ execFileSync('cmd.exe', ['/d', '/s', '/c', 'npm', ...packArgs], {
895
+ encoding: 'utf-8',
896
+ timeout: 30_000,
897
+ stdio: ['pipe', 'pipe', 'pipe'],
898
+ });
899
+ }
900
+ else {
901
+ execFileSync('npm', packArgs, {
902
+ encoding: 'utf-8',
903
+ timeout: 30_000,
904
+ stdio: ['pipe', 'pipe', 'pipe'],
905
+ });
906
+ }
664
907
  const tgzFiles = readdirSync(tmpDir).filter(f => f.endsWith('.tgz'));
665
908
  const [tgzFile] = tgzFiles;
666
909
  if (!tgzFile) {
@@ -669,7 +912,7 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
669
912
  }
670
913
  const extractDir = path.join(tmpDir, 'extracted');
671
914
  mkdirSync(extractDir, { recursive: true });
672
- execSync(`tar -xzf "${path.join(tmpDir, tgzFile)}" -C "${extractDir}"`, {
915
+ execFileSync('tar', ['-xzf', path.join(tmpDir, tgzFile), '-C', extractDir], {
673
916
  encoding: 'utf-8',
674
917
  timeout: 15_000,
675
918
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -706,12 +949,16 @@ function syncPdCli(pluginDir) {
706
949
  mkdirSync(installedPdCliDir, { recursive: true });
707
950
  cpSync(distDir, path.join(installedPdCliDir, 'dist'), { recursive: true });
708
951
  copyFileSync(path.join(pdCliSourceDir, 'package.json'), path.join(installedPdCliDir, 'package.json'));
952
+ const bundledNodeModules = path.join(pdCliSourceDir, 'node_modules');
953
+ if (existsSync(bundledNodeModules)) {
954
+ cpSync(bundledNodeModules, path.join(installedPdCliDir, 'node_modules'), { recursive: true });
955
+ }
709
956
  // Create node_modules/@principles/core symlink so pd-cli can resolve
710
957
  // its @principles/core dependency (rewritten to "file:../core" by bundle-plugin.mjs).
711
958
  // Without this, `node dist/index.js --version` fails because static imports
712
959
  // from @principles/core/runtime-v2 cannot be resolved.
713
960
  const coreLinkDir = path.join(installedPdCliDir, 'node_modules', '@principles');
714
- const coreLinkTarget = path.join(getPluginExtDir(), 'core');
961
+ const coreLinkTarget = path.join(getPdRuntimeDir(), 'core');
715
962
  mkdirSync(coreLinkDir, { recursive: true });
716
963
  const coreLinkPath = path.join(coreLinkDir, 'core');
717
964
  if (!existsSync(coreLinkPath)) {
@@ -731,7 +978,7 @@ function syncPdCli(pluginDir) {
731
978
  // host-runtime's own better-sqlite3 / js-yaml / @principles/core dependencies
732
979
  // resolve through the plugin's <ext>/node_modules/ (shared via Node's upward
733
980
  // module resolution), so no separate npm install is needed.
734
- const hostRuntimeLinkTarget = path.join(getPluginExtDir(), 'host-runtime');
981
+ const hostRuntimeLinkTarget = path.join(getPdRuntimeDir(), 'host-runtime');
735
982
  const hostRuntimeLinkPath = path.join(coreLinkDir, 'host-runtime');
736
983
  if (!existsSync(hostRuntimeLinkPath)) {
737
984
  if (isWindows()) {
@@ -750,7 +997,7 @@ function syncPdCli(pluginDir) {
750
997
  // Without this, `pd runtime init` crashes with ERR_MODULE_NOT_FOUND
751
998
  // because runtime-init.ts statically imports initTrajectorySchema/initWorkflowSchema.
752
999
  const pdLinkDir = path.join(installedPdCliDir, 'node_modules');
753
- const pdLinkTarget = getPluginExtDir();
1000
+ const pdLinkTarget = installedPluginDir();
754
1001
  mkdirSync(pdLinkDir, { recursive: true });
755
1002
  const pdLinkPath = path.join(pdLinkDir, 'principles-disciple');
756
1003
  if (!existsSync(pdLinkPath)) {
@@ -798,20 +1045,35 @@ function syncPdCli(pluginDir) {
798
1045
  function verifyPdCliShim() {
799
1046
  const localShim = path.join(getInstalledBinDir(), isWindows() ? 'pd.cmd' : 'pd');
800
1047
  let localOk = false;
1048
+ let localError;
801
1049
  try {
802
1050
  const installedEntry = path.join(getInstalledPdCliDir(), 'dist', 'index.js');
803
1051
  execFileSync(process.execPath, [installedEntry, '--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS });
804
1052
  localOk = true;
805
1053
  }
806
1054
  catch (e) {
807
- const err = e;
808
- const detail = err.stderr?.toString().slice(0, 500) ?? err.message ?? 'unknown error';
1055
+ let detail = 'unknown error';
1056
+ if (typeof e === 'object' && e !== null) {
1057
+ const stderr = Object.hasOwn(e, 'stderr') ? Reflect.get(e, 'stderr') : undefined;
1058
+ const message = Object.hasOwn(e, 'message') ? Reflect.get(e, 'message') : undefined;
1059
+ const stderrText = Buffer.isBuffer(stderr) ? stderr.toString().trim().slice(0, 500) : '';
1060
+ if (stderrText.length > 0)
1061
+ detail = stderrText;
1062
+ else if (typeof message === 'string' && message.trim().length > 0)
1063
+ detail = message.trim().slice(0, 500);
1064
+ }
1065
+ else if (typeof e === 'string' && e.trim().length > 0) {
1066
+ detail = e.trim().slice(0, 500);
1067
+ }
1068
+ localError = detail;
809
1069
  logger.warn(`PD CLI local verification failed: ${detail}`);
810
1070
  }
811
1071
  const globalOk = (() => {
812
1072
  try {
813
1073
  if (isWindows()) {
814
- execSync('pd --version', { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS, shell: 'cmd' });
1074
+ // 'pd' is an npm .cmd shim on Windows — resolve via cmd.exe with a
1075
+ // constant argv array (no shell string, no interpolation).
1076
+ execFileSync('cmd.exe', ['/c', 'pd', '--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS, windowsHide: true });
815
1077
  }
816
1078
  else {
817
1079
  execFileSync('pd', ['--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS });
@@ -822,7 +1084,7 @@ function verifyPdCliShim() {
822
1084
  return false;
823
1085
  }
824
1086
  })();
825
- return { localOk, globalOk, localPath: localShim };
1087
+ return { localOk, globalOk, localPath: localShim, localError };
826
1088
  }
827
1089
  function installConsole(consoleDir) {
828
1090
  const consoleSrc = path.join(consoleDir, 'console');
@@ -844,18 +1106,18 @@ function installConsole(consoleDir) {
844
1106
  mkdirSync(path.dirname(pluginLinkPath), { recursive: true });
845
1107
  if (!existsSync(pluginLinkPath)) {
846
1108
  if (isWindows()) {
847
- symlinkSync(getPluginExtDir(), pluginLinkPath, 'junction');
1109
+ symlinkSync(installedPluginDir(), pluginLinkPath, 'junction');
848
1110
  }
849
1111
  else {
850
- symlinkSync('../../', pluginLinkPath, 'dir');
1112
+ symlinkSync(path.relative(path.dirname(pluginLinkPath), installedPluginDir()), pluginLinkPath, 'dir');
851
1113
  }
852
1114
  }
853
1115
  }
854
1116
  function getInstalledCoreDir() {
855
- return path.join(getPluginExtDir(), 'core');
1117
+ return path.join(getPdRuntimeDir(), 'core');
856
1118
  }
857
1119
  function getInstalledHostRuntimeDir() {
858
- return path.join(getPluginExtDir(), 'host-runtime');
1120
+ return path.join(getPdRuntimeDir(), 'host-runtime');
859
1121
  }
860
1122
  function installBundledCore(pluginDir) {
861
1123
  const coreSrc = path.join(pluginDir, 'core');
@@ -893,22 +1155,19 @@ function ensureCoreDependency(_targetDir) {
893
1155
  }
894
1156
  async function installCoreDependencies() {
895
1157
  const coreDir = getInstalledCoreDir();
896
- const packageJsonPath = path.join(coreDir, 'package.json');
897
- if (!existsSync(packageJsonPath)) {
898
- throw new Error('Core package.json not found after copy — install is corrupted');
899
- }
900
- await runNpmInstall(coreDir, 'Core');
901
- await rebuildNativeModules(coreDir, 'Core');
902
- verifyNativeModules(coreDir, 'Core');
1158
+ await prepareComponentDependencies(coreDir, 'Core');
1159
+ }
1160
+ async function installHostRuntimeDependencies() {
1161
+ const hostRuntimeDir = getInstalledHostRuntimeDir();
1162
+ await prepareComponentDependencies(hostRuntimeDir, 'Host runtime');
1163
+ }
1164
+ async function installPdCliDependencies() {
1165
+ const pdCliDir = getInstalledPdCliDir();
1166
+ await prepareComponentDependencies(pdCliDir, 'PD CLI');
903
1167
  }
904
1168
  async function installConsoleDependencies() {
905
1169
  const consoleDest = getInstalledConsoleDir();
906
- const packageJsonPath = path.join(consoleDest, 'package.json');
907
- if (!existsSync(packageJsonPath)) {
908
- throw new Error('Console package.json not found after copy — install is corrupted');
909
- }
910
- await runNpmInstall(consoleDest, 'Console');
911
- await rebuildNativeModules(consoleDest, 'Console');
1170
+ await prepareComponentDependencies(consoleDest, 'Console');
912
1171
  }
913
1172
  const CONSOLE_PORT_MAX_RETRIES = 3;
914
1173
  async function verifyConsole(workspaceDir) {
@@ -1336,11 +1595,44 @@ export async function install(options, pluginDir, mode = {}) {
1336
1595
  // because jsonMode always implies non-interactive.
1337
1596
  const quiet = mode.quiet === true;
1338
1597
  const nonInteractive = mode.nonInteractive ?? quiet;
1598
+ activeHostTarget = options.host;
1599
+ if (!legacyNpmInstallEnabled()) {
1600
+ try {
1601
+ await preflightSelfContainedReleaseAsset(pluginDir);
1602
+ }
1603
+ catch (error) {
1604
+ const preflightError = error instanceof SelfContainedDependencyError
1605
+ ? error
1606
+ : new SelfContainedDependencyError({
1607
+ reason: 'self_contained_asset_preflight_failed',
1608
+ nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
1609
+ message: error instanceof Error ? error.message : String(error),
1610
+ component: 'Release asset',
1611
+ cause: error,
1612
+ });
1613
+ return {
1614
+ success: false,
1615
+ workspaceDir: options.workspaceDir,
1616
+ configYamlPath: getConfigYamlPath(options.workspaceDir),
1617
+ templatesCount: 0,
1618
+ components: { plugin: 'skipped', cli: 'skipped', console: 'skipped' },
1619
+ verification: { features: 'skipped', storyA: 'skipped' },
1620
+ enabledChannels: options.channels,
1621
+ nextAction: preflightError.nextAction,
1622
+ reason: preflightError.reason,
1623
+ component: preflightError.component,
1624
+ dependency: preflightError.dependency,
1625
+ error: `${preflightError.message} — ${t('rollback_no_changes')}`,
1626
+ };
1627
+ }
1628
+ }
1339
1629
  // Gateway lock pre-flight: a running gateway holds native-module file handles
1340
1630
  // that make the backup rename fail with EPERM. Decide stop/abort/proceed
1341
1631
  // BEFORE mutating anything (cli-5: abort/stop-failed paths must not mutate).
1342
1632
  let restartedGateway = false;
1343
- const gatewayStatus = await checkOpenClawGateway();
1633
+ const gatewayStatus = installsOpenClaw(options.host)
1634
+ ? await checkOpenClawGateway()
1635
+ : { isRunning: false };
1344
1636
  if (gatewayStatus.isRunning) {
1345
1637
  const action = await resolveGatewayAction(gatewayStatus, {
1346
1638
  stopGateway: options.stopGateway,
@@ -1376,6 +1668,8 @@ export async function install(options, pluginDir, mode = {}) {
1376
1668
  }
1377
1669
  const spinner = quiet ? null : ora('Installing...').start();
1378
1670
  let backupDir = null;
1671
+ let runtimeBackupDir = null;
1672
+ let installManifestHosts;
1379
1673
  const components = { plugin: 'skipped', cli: 'skipped', console: 'skipped' };
1380
1674
  const verification = { features: 'skipped', storyA: 'skipped' };
1381
1675
  let consoleProcess = null;
@@ -1416,22 +1710,33 @@ export async function install(options, pluginDir, mode = {}) {
1416
1710
  stepIndex++;
1417
1711
  if (spinner)
1418
1712
  updateProgress(spinner, stepIndex, 'Backing up existing install...');
1419
- migrateLegacyPdBackups();
1420
- const { backupDir: backupDirFromResult } = backupExistingInstall();
1713
+ // Validate the existing host-ownership record before mutating runtime or
1714
+ // host config. A malformed manifest must not be discovered only after the
1715
+ // old installation has already been replaced (rc-3/rc-9).
1716
+ installManifestHosts = resolveInstallManifestHosts(options.host);
1717
+ if (installsOpenClaw(options.host))
1718
+ migrateLegacyPdBackups();
1719
+ const { backupDir: backupDirFromResult, runtimeBackupDir: runtimeBackupDirFromResult } = backupExistingInstall(options.host);
1421
1720
  backupDir = backupDirFromResult;
1721
+ runtimeBackupDir = runtimeBackupDirFromResult ?? null;
1422
1722
  stepIndex++;
1423
1723
  if (spinner)
1424
1724
  updateProgress(spinner, stepIndex, 'Installing bundled @principles/core...');
1425
1725
  installBundledCore(pluginDir);
1426
1726
  stepIndex++;
1727
+ if (spinner)
1728
+ updateProgress(spinner, stepIndex, 'Validating bundled core dependencies...');
1729
+ await installCoreDependencies();
1730
+ stepIndex++;
1427
1731
  if (spinner)
1428
1732
  updateProgress(spinner, stepIndex, 'Installing bundled @principles/host-runtime...');
1429
1733
  installBundledHostRuntime(pluginDir);
1430
1734
  stepIndex++;
1431
1735
  if (spinner)
1432
- updateProgress(spinner, stepIndex, 'Installing core dependencies...');
1433
- await installCoreDependencies();
1736
+ updateProgress(spinner, stepIndex, 'Validating bundled host runtime dependencies...');
1737
+ await installHostRuntimeDependencies();
1434
1738
  stepIndex++;
1739
+ installBundledLayoutPackage(pluginDir);
1435
1740
  if (spinner)
1436
1741
  updateProgress(spinner, stepIndex, 'Installing plugin...');
1437
1742
  await installPluginToStaging(pluginDir, options.language);
@@ -1441,13 +1746,14 @@ export async function install(options, pluginDir, mode = {}) {
1441
1746
  ensureCoreDependency(getPluginExtDir());
1442
1747
  stepIndex++;
1443
1748
  if (spinner)
1444
- updateProgress(spinner, stepIndex, 'Installing plugin dependencies...');
1749
+ updateProgress(spinner, stepIndex, 'Validating bundled plugin dependencies...');
1445
1750
  await installPluginDependencies();
1446
1751
  components.plugin = 'verified';
1447
1752
  stepIndex++;
1448
1753
  if (spinner)
1449
1754
  updateProgress(spinner, stepIndex, 'Installing pd CLI...');
1450
1755
  syncPdCli(pluginDir);
1756
+ await installPdCliDependencies();
1451
1757
  stepIndex++;
1452
1758
  if (spinner)
1453
1759
  updateProgress(spinner, stepIndex, 'Preparing core library for pd-cli...');
@@ -1457,7 +1763,7 @@ export async function install(options, pluginDir, mode = {}) {
1457
1763
  updateProgress(spinner, stepIndex, 'Verifying pd CLI...');
1458
1764
  const cliVerify = verifyPdCliShim();
1459
1765
  if (!cliVerify.localOk) {
1460
- throw new Error('PD CLI verification failed — local shim is not executable after install. Check Node.js and PATH configuration.');
1766
+ throw new Error(`PD CLI verification failed — local shim is not executable after install: ${cliVerify.localError ?? 'unknown error'}. Check Node.js and PATH configuration.`);
1461
1767
  }
1462
1768
  if (cliVerify.globalOk) {
1463
1769
  components.cli = 'verified';
@@ -1477,7 +1783,7 @@ export async function install(options, pluginDir, mode = {}) {
1477
1783
  ensureCoreDependency(getInstalledConsoleDir());
1478
1784
  stepIndex++;
1479
1785
  if (spinner)
1480
- updateProgress(spinner, stepIndex, 'Installing console dependencies...');
1786
+ updateProgress(spinner, stepIndex, 'Validating bundled console dependencies...');
1481
1787
  await installConsoleDependencies();
1482
1788
  stepIndex++;
1483
1789
  if (spinner)
@@ -1594,14 +1900,13 @@ export async function install(options, pluginDir, mode = {}) {
1594
1900
  logger.info(`Host "${hr.hostId}" install: ${hr.reason ?? 'skipped'}. Next: ${hr.nextAction}`);
1595
1901
  }
1596
1902
  }
1597
- cleanupBackup(backupDir);
1903
+ if (hostFailures.length > 0) {
1904
+ throw new Error(`Host installation failed: ${hostFailures.join(' | ')}`);
1905
+ }
1906
+ writeInstallManifest(installManifestHosts);
1907
+ cleanupBackup(backupDir, runtimeBackupDir);
1598
1908
  if (spinner) {
1599
- if (hostFailures.length > 0) {
1600
- spinner.warn('Install complete with host warnings');
1601
- }
1602
- else {
1603
- spinner.succeed('Install complete!');
1604
- }
1909
+ spinner.succeed('Install complete!');
1605
1910
  }
1606
1911
  killConsoleChild();
1607
1912
  // Task 8: auto-launch console via `pd console open` (reuses PRI-300
@@ -1614,7 +1919,6 @@ export async function install(options, pluginDir, mode = {}) {
1614
1919
  // A host installer failure means the install is not fully successful,
1615
1920
  // even if all component verifications passed. The operator should see
1616
1921
  // success=false and be guided to fix the failed host.
1617
- const hasHostFailures = hostFailures.length > 0;
1618
1922
  const nextActions = [];
1619
1923
  if (components.cli === 'verified') {
1620
1924
  nextActions.push(`pd runtime canary --workspace "${options.workspaceDir}" --json`);
@@ -1635,10 +1939,8 @@ export async function install(options, pluginDir, mode = {}) {
1635
1939
  if (launchResult.fallbackAction) {
1636
1940
  nextActions.push(launchResult.fallbackAction);
1637
1941
  }
1638
- // Append host-failure remediation actions so the operator knows what to fix.
1639
- nextActions.push(...hostFailures);
1640
1942
  return {
1641
- success: isComplete && !hasHostFailures,
1943
+ success: isComplete,
1642
1944
  workspaceDir: options.workspaceDir,
1643
1945
  configYamlPath,
1644
1946
  templatesCount: templatesCount + principlesCount,
@@ -1654,7 +1956,7 @@ export async function install(options, pluginDir, mode = {}) {
1654
1956
  if (spinner)
1655
1957
  spinner.fail('Install failed');
1656
1958
  killConsoleChild();
1657
- const restoreResult = restoreBackup(backupDir);
1959
+ const restoreResult = restoreBackup(backupDir, runtimeBackupDir);
1658
1960
  const errorMsg = error instanceof Error ? error.message : String(error);
1659
1961
  // ERR-046 / rc-9: never claim a restore that didn't happen. When backupDir
1660
1962
  // is null, the backup step never completed (it threw — e.g. EPERM — or
@@ -1664,15 +1966,16 @@ export async function install(options, pluginDir, mode = {}) {
1664
1966
  const isLockError = /EPERM|EBUSY|EACCES|operation not permitted/i.test(errorMsg);
1665
1967
  const extDir = getPluginExtDir();
1666
1968
  // EP-11: all operator-visible failure/rollback text goes through t().
1667
- const rollbackSuffix = !backupDir
1969
+ const hasBackup = Boolean(backupDir || runtimeBackupDir);
1970
+ const rollbackSuffix = !hasBackup
1668
1971
  ? t('rollback_no_changes')
1669
1972
  : restoreResult.restored
1670
1973
  ? t('rollback_restored')
1671
1974
  : t('rollback_failed')
1672
1975
  .replace('{restoreError}', restoreResult.error ?? '')
1673
1976
  .replace('{extDir}', extDir)
1674
- .replace('{backupDir}', backupDir);
1675
- const nextAction = !backupDir
1977
+ .replace('{backupDir}', backupDir ?? runtimeBackupDir ?? '');
1978
+ const rollbackNextAction = !hasBackup
1676
1979
  ? (isLockError
1677
1980
  ? t('next_no_changes_lock')
1678
1981
  : t('next_no_changes_other'))
@@ -1680,13 +1983,19 @@ export async function install(options, pluginDir, mode = {}) {
1680
1983
  ? t('next_restored')
1681
1984
  : t('next_restore_failed')
1682
1985
  .replace('{extDir}', extDir)
1683
- .replace('{backupDir}', backupDir)
1986
+ .replace('{backupDir}', backupDir ?? runtimeBackupDir ?? '')
1684
1987
  .replace('{errorMsg}', errorMsg);
1685
- const reason = !backupDir
1988
+ const rollbackReason = !hasBackup
1686
1989
  ? (isLockError ? `install_aborted_lock: ${errorMsg}` : `install_failed_before_mutation: ${errorMsg}`)
1687
1990
  : restoreResult.restored
1688
1991
  ? errorMsg
1689
1992
  : `install_failed_rollback_failed: ${errorMsg}`;
1993
+ const nextAction = error instanceof SelfContainedDependencyError
1994
+ ? restoreResult.restored || !hasBackup
1995
+ ? error.nextAction
1996
+ : `${error.nextAction} ${rollbackNextAction}`
1997
+ : rollbackNextAction;
1998
+ const reason = error instanceof SelfContainedDependencyError ? error.reason : rollbackReason;
1690
1999
  return {
1691
2000
  success: false,
1692
2001
  workspaceDir: options.workspaceDir,
@@ -1697,6 +2006,8 @@ export async function install(options, pluginDir, mode = {}) {
1697
2006
  enabledChannels: options.channels,
1698
2007
  nextAction,
1699
2008
  reason,
2009
+ component: error instanceof SelfContainedDependencyError ? error.component : undefined,
2010
+ dependency: error instanceof SelfContainedDependencyError ? error.dependency : undefined,
1700
2011
  error: `${errorMsg} — ${rollbackSuffix}`,
1701
2012
  };
1702
2013
  }