chainlesschain 0.166.89 → 0.166.91

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 (181) hide show
  1. package/README.md +91 -5
  2. package/package.json +3 -3
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-C8AkN9R5.js → AIOps-DgV7xb8F.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-BrAzSQor.js → ActionButton-CgANpkKu.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Cu56X8Oh.js → Analytics-DnvpX7RB.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BP1Riofl.js → AppLayout-C2bHccBM.js} +4 -4
  9. package/src/assets/web-panel/assets/{Artifacts-CIW-nNAz.js → Artifacts-BIhijC9g.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CJtDabk-.js → Audit-CKRjWGdp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DYIHeQ_P.js → BackgroundAgents-CblYtgBE.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-B4CsFzj7.js → Backup-Cq35b78a.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-3eoJ5kfb.js → BaseInput-DcB7NoRz.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-BBhX2L_E.js → Chat-tc3b-s7i.js} +5 -5
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-RN8cbv7w.js → ChatBubbleRenderer-fcc_Tvqu.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-5UvmwHVk.js → Checkbox-BLD5bH5u.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-BFy8zsBN.js → Codegen-BLOsoazN.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-4M6bKRRO.js → Col-Bdr7JwIx.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-D6LC0j7_.js → Community-C84BsWE0.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-Dd48xMcv.js → Compact-Dzdwd04z.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Ba85ggmy.js → Compliance-CCG-R0EV.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-D1BXlkuK.js → Cowork-BYj72SK0.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-Ca2Uy7Ia.js → Cron-B6iKAwOf.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-C2bDRXZg.js → Crosschain-BJ-oDC6u.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-DySZKAJf.js → DID-BnMckGLr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-DDpYf-TT.js → Dashboard-Cyje-gCO.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-DGjROfPv.js → Dropdown-BpNlenjK.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-DxX9QYiB.js → EmailListRenderer-BhonO7Nv.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-TBCZyrSJ.js → EvolutionSettings-DVoNU-Id.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BeqwTXBa.js → FamilyGuardDashboard-tdn-KC67.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-CiCpKJQ1.js → Federation--EEVrHhz.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-CdTmbLkU.js → FormItemContext-Cy8zr0-4.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-BwbkEY-5.js → GenericCardRenderer-BuUhpgFi.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-VnAga2vv.js → Git-Ctd3E5Pe.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-i-4Ebs-H.js → Governance-Ce7dV6aU.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-CirjTgNw.js → Inference-CD1vExIH.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-CunS7vhA.js → KnowledgeGraph-Dn64OdQ7.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-DBuTF0c6.js → Logs-PmElVRrT.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-B-iE-tt_.js → MarkdownRenderer-BFiVKf5t.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-BK6ZivTS.js → Marketplace-OW4jTXwx.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-CUnCRnd3.js → McpTools-BEq2Ib4x.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CBGGr8Gy.js → Memory-Can_P2oK.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-reB6iaWD.js → MobileBridge-DJ8R-dn3.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-o1YdVB7i.js → MobileProjects-B7kV9GOt.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-if5OE3GH.js → Mtc-BfxamolS.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-BTZWpq0j.js → MtcAudit-DHtuv7av.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-8cvMAYFL.js → Multisig-DLkLpvxc.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-BMvUXAWo.js → NLProgramming-u4XtJTIt.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-BWWjColh.js → Notes-BwuuPJLS.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-Ccr4lIhS.js → NotificationSettings-HEeu-E9v.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-DhksGy6D.js → OrderTableRenderer-BtvN-Qwh.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-DciXQfdY.js → Organization-Yh-czs3b.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-8DR7uMSx.js → Overflow-DmE8mYVM.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-DE6euHYl.js → P2P-CWVck8WN.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-ByuWoauq.js → PdhVaultBrowser-DgFqekod.js} +4 -4
  56. package/src/assets/web-panel/assets/{Permissions-DkjM87ac.js → Permissions-BtJBVOHV.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-2DLp0KTL.js → PersonalDataHub-6VBObXzd.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-Ci2Qlkfr.js → Pipeline-D222FmqY.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-DlwDnDVA.js → Privacy-Bi9FMikp.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-CmMifW39.js → ProjectInit-Bo52H47H.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-DJVFIh-6.js → ProjectSettings-BPkesfOc.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-P2nWBS70.js → Projects-GynohSFX.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-B2cxaGCU.js → Providers-DVdMg04n.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-CpO77kcE.js → QrScannerModal-DqJCb595.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BDQl1hb0.js → QuickAsk-J7loQbXi.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DTD2f3IN.js → Recommend-BI5aURVc.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-DGZAnwvs.js → RemoteSession-BN2sqGvz.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-B_R4vitb.js → Reputation-BGOND-Fi.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-4Jj6JyXN.js → Row-77dfwaUk.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-D1t1MCZ-.js → RssFeed-FtBAxS3g.js} +2 -2
  71. package/src/assets/web-panel/assets/{Search-CyOUlIn7.js → Search-BaYVLFb7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-BmknPT5Q.js → Security-LE3Vv6ab.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-DkEK8mpa.js → Services-C5pP-Whz.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-Bvo5bpuk.js → Skeleton-CLqKUVsF.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-AMmG8fim.js → Skills-BPjN0SX5.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-Dl7-OKOV.js → Sla-14jD70kg.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-DtiGKu0E.js → SpeechSettings-Dr9ij42W.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-Ch7mp3ES.js → SyncSettings-BzLHP7B8.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-Ck-sEgj-.js → Tasks-YqV9b0rV.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-BlV22Il8.js → Templates-CxxAE4PK.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-CaaAu0mX.js → Tenant-CRb3PcKJ.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-lA9g3FtJ.js → Terminal-CTzPpBaP.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-CG26IFC3.js → TimelineRenderer-DjFUj_hy.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-iaJUBLBm.js → Tokens-Bbb8tPvx.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DWQJtLK3.js → Trigger-CSeWGM0W.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-CTjmUwqp.js → Trust-JgESMBo3.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CMnxufgD.js → UkeySign-CiObLk0T.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-diCFSWJw.js → VideoEditing-CFEZaQ2x.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-Ba1oND1K.js → Wallet-DR8ZGDNn.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-DZDqPS-S.js → WebAuthn-DxZukvu7.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-CfN8fPMe.js → WorkflowEditor-CKgSZQwn.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-BiqMsO_i.js → chat-CTxEQE66.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-By8LkjqH.js → colors-CAjKMUu3.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-B0mxvRe3.js → compact-item-BXuz49at.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-Li2ub348.js → createContext-CFN_Hwr9.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-DYbHPkbl.js → hasIn-BwoSBSfP.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CVZNYRzM.js → index-B0QbLlWn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CGZzexNa.js → index-B2o_BBjg.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CYv3JIzl.js → index-B2tEnBPx.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-1lVoRUrQ.js → index-B7kp-zRE.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CTVPeUh3.js → index-B9yR7zqr.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BFhksbXp.js → index-BK4ftQ4d.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B0D0HkkM.js → index-Bj4hIiLW.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CEp_3fKJ.js → index-BmQITjMU.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DIImi0cd.js → index-BmXpdcHI.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D6qL3QBU.js → index-Bqv_Cray.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BSk0xuXP.js → index-Bu2P6u8m.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-zSzXsF9b.js → index-Bw9s2d3c.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-beDji-cB.js → index-C8er4W9u.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C-RE3mFh.js → index-CB3kVd9c.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CCsRfd0k.js +1 -0
  113. package/src/assets/web-panel/assets/{index-CA0AOURT.js → index-CF9lWi1o.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CMh3VxgO.js → index-CN53dE_u.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-KWt8Owo8.js → index-CSmFby3Q.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DB4DCzqU.js → index-CehdwJ_Q.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CHgiSV6R.js → index-Cgk0YEiq.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-b4O_YBVR.js → index-Cp5y7lX_.js} +1 -1
  119. package/src/assets/web-panel/assets/index-CsmiZIQ4.js +1 -0
  120. package/src/assets/web-panel/assets/{index-DAOpBv3C.js → index-DTX9CJPx.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BZqTG7fP.js → index-DViK2bkv.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Bc6bxU24.js → index-DY-gBSm8.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-Czt7WAtA.js → index-DjF5BOZx.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-KqfqSdAC.js → index-DmkbAADP.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Bd5znvCV.js → index-DpdDnZX_.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-C5Se6Lnv.js → index-Dv7V2kg6.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cpfn4YbT.js → index-DxunxaTw.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BcOJEgBE.js → index-F2E5RCwz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CgyrklzQ.js → index-IY9bd5az.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-ClsJN8sW.js → index-IahILygB.js} +3 -3
  131. package/src/assets/web-panel/assets/{index-hw3sCYAz.js → index-T3MTE6jB.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Bm2P2Kgp.js → index-Tz5dheZa.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BRzewWeE.js → index-_ZtCyUdz.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DPRgnazi.js → index-o9DpkZKf.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-ByqFKMWL.js → index-t2Ch_JKn.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DgMFnBOv.js → index-u9_DM3ZC.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-TgDL_7OY.js → initDefaultProps-BoiGJDoO.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-fHosyV5c.js → motion-5eL4E0pA.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-C_QfW5qg.js → move-DjggDi_1.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-u7ywDVOg.js → mtc-parser-Ce8Vo2T3.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-BEJdUgE9.js → omit-D1yOBaO2.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-DGkQFAJ5.js → pickAttrs-8NLceQe8.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-DUyZXAjt.js → placementArrow-CsIdBRmQ.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-B4xDxO7Q.js → responsiveObserve-GM5NE8En.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-B8WuJtst.js → slide-44yj3u49.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-DLUqy7JO.js → statusUtils-B8tqtWcX.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-BYOJOyqL.js → styleChecker-NhDPBbyB.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-WChWQURv.js → useFlexGapSupport-C8Qz1GtN.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-vLNpm3dv.js → useFs-ClUv4kih.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DSZ8unoU.js → usePersonalDataHub-BwkOVEh6.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-C4Xf7Kg1.js → vnode--gMF33R0.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-BulmeAGy.js → zoom-DXg3TqOP.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +5 -5
  155. package/src/commands/agent-process-ownership.js +121 -0
  156. package/src/commands/agent.js +2 -0
  157. package/src/commands/automation.js +35 -8
  158. package/src/commands/hub.js +224 -0
  159. package/src/commands/project.js +162 -0
  160. package/src/data/changelog.json +26 -0
  161. package/src/gateways/ws/personal-data-hub-protocol.js +54 -8
  162. package/src/lib/audit-logger.js +59 -46
  163. package/src/lib/audit-sanitizer.js +279 -0
  164. package/src/lib/automation-center.js +14 -4
  165. package/src/lib/automation-engine.js +151 -39
  166. package/src/lib/checkpoint-restore-saga.js +11 -1
  167. package/src/lib/eval/verify01-host-evidence.js +36 -3
  168. package/src/lib/knowledge-graph.js +27 -0
  169. package/src/lib/personal-data-hub-wiring.js +44 -1
  170. package/src/lib/process-execution-broker/index.js +91 -1
  171. package/src/lib/process-execution-broker/platform-sandbox.js +42 -0
  172. package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +757 -0
  173. package/src/lib/process-execution-broker/windows-native-evaluator.js +316 -0
  174. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  175. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  176. package/src/lib/process-execution-broker/windows-sandbox.cs +383 -11
  177. package/src/lib/scheduler-kernel/automation-adapter.js +15 -3
  178. package/src/lib/scheduler-kernel/automation-event-adapter.js +15 -3
  179. package/src/assets/web-panel/assets/devWarning-D90arbUg.js +0 -1
  180. package/src/assets/web-panel/assets/index-CeP1oROI.js +0 -1
  181. package/src/assets/web-panel/assets/index-Cu9gkyRc.js +0 -1
@@ -107,6 +107,20 @@ function _dbFromCtx(cmd) {
107
107
  return null;
108
108
  }
109
109
 
110
+ function reportExecution(execution) {
111
+ const message = `Execution ${execution.id} → ${execution.status}`;
112
+ if (execution.status === EXECUTION_STATUS.SUCCESS) {
113
+ logger.success(message);
114
+ } else if (execution.status === EXECUTION_STATUS.SIMULATED) {
115
+ logger.log(`${message} (simulation only; no external actions applied)`);
116
+ } else {
117
+ logger.error(
118
+ `${message}: ${execution.error || "execution did not succeed"}`,
119
+ );
120
+ process.exitCode = 1;
121
+ }
122
+ }
123
+
110
124
  async function readBoundedJsonStdin(options, maximum = 80 * 1024) {
111
125
  if (options?.jsonStdin !== true) {
112
126
  throw new Error("--json-stdin is required for routine definitions");
@@ -665,8 +679,18 @@ function _wire(root) {
665
679
  action,
666
680
  expectedRevision: opts.expectedRevision,
667
681
  });
668
- if (opts.json) console.log(JSON.stringify(result, null, 2));
669
- else logger.success(`${flowId} ${action} completed`);
682
+ if (opts.json) {
683
+ console.log(JSON.stringify(result, null, 2));
684
+ if (
685
+ [EXECUTION_STATUS.FAILED, EXECUTION_STATUS.UNSUPPORTED].includes(
686
+ result.result?.status,
687
+ )
688
+ ) {
689
+ process.exitCode = 1;
690
+ }
691
+ } else if (result.result?.id && result.result?.flowId) {
692
+ reportExecution(result.result);
693
+ } else logger.success(`${flowId} ${action} completed`);
670
694
  } catch (e) {
671
695
  logger.error(e.message);
672
696
  process.exitCode = 1;
@@ -1033,14 +1057,17 @@ function _wire(root) {
1033
1057
 
1034
1058
  root
1035
1059
  .command("fire-trigger <triggerId>")
1036
- .description("Simulate trigger firing (executes flow)")
1060
+ .description("Fire a trigger; use --test for simulation")
1037
1061
  .option("-i, --input <json>", "Input data as JSON")
1062
+ .option("--test", "Simulate only; no external actions are applied")
1038
1063
  .action(async (triggerId, opts, cmd) => {
1039
1064
  const db = _dbFromCtx(cmd);
1040
1065
  try {
1041
1066
  const input = parseJsonOption(opts.input, "--input") || {};
1042
- const exec = fireTrigger(db, triggerId, input);
1043
- logger.success(`Fired trigger → exec ${chalk.cyan(exec.id)}`);
1067
+ const exec = fireTrigger(db, triggerId, input, {
1068
+ testMode: Boolean(opts.test),
1069
+ });
1070
+ reportExecution(exec);
1044
1071
  logger.log(` status: ${exec.status}`);
1045
1072
  logger.log(` duration: ${exec.durationMs}ms`);
1046
1073
  logger.log(` steps: ${exec.stepsLog.length}`);
@@ -1095,9 +1122,9 @@ function _wire(root) {
1095
1122
 
1096
1123
  root
1097
1124
  .command("execute <flowId>")
1098
- .description("Manually execute a flow (simulated)")
1125
+ .description("Execute a flow; use --test for simulation")
1099
1126
  .option("-i, --input <json>", "Input data as JSON")
1100
- .option("--test", "Test mode (marks execution as test)")
1127
+ .option("--test", "Simulate only; no external actions are applied")
1101
1128
  .action(async (flowId, opts, cmd) => {
1102
1129
  const db = _dbFromCtx(cmd);
1103
1130
  try {
@@ -1106,7 +1133,7 @@ function _wire(root) {
1106
1133
  inputData: input,
1107
1134
  testMode: Boolean(opts.test),
1108
1135
  });
1109
- logger.success(`Execution ${chalk.cyan(exec.id)} → ${exec.status}`);
1136
+ reportExecution(exec);
1110
1137
  logger.log(` duration: ${exec.durationMs}ms`);
1111
1138
  logger.log(` steps: ${exec.stepsLog.length}`);
1112
1139
  if (exec.error) logger.log(chalk.red(` error: ${exec.error}`));
@@ -3446,6 +3446,139 @@ function _defaultKnownVendors() {
3446
3446
 
3447
3447
  // ─── Commander wire-up ───────────────────────────────────────────────
3448
3448
 
3449
+ async function cmdDerivation(operation, reference, options = {}) {
3450
+ try {
3451
+ if (
3452
+ reference &&
3453
+ (!["event", "person", "place", "item", "topic"].includes(
3454
+ reference.entityType,
3455
+ ) ||
3456
+ typeof reference.entityId !== "string" ||
3457
+ !reference.entityId.trim() ||
3458
+ reference.entityId.length > 1024)
3459
+ ) {
3460
+ throw new Error("A valid entity type and ID are required");
3461
+ }
3462
+ if (operation === "delete" && options.confirm !== true) {
3463
+ throw new Error(
3464
+ "Normalized entity deletion requires --confirm; raw archive is retained",
3465
+ );
3466
+ }
3467
+ if (
3468
+ operation === "prune" &&
3469
+ options.confirm !== true &&
3470
+ options.dryRun !== true
3471
+ ) {
3472
+ throw new Error("Retired derivation receipt pruning requires --confirm");
3473
+ }
3474
+ if (
3475
+ operation === "prune" &&
3476
+ (!Array.isArray(options.consumer) ||
3477
+ options.consumer.length < 1 ||
3478
+ options.consumer.length > 100 ||
3479
+ options.consumer.some(
3480
+ (id) => typeof id !== "string" || !id.trim() || id.length > 1024,
3481
+ ))
3482
+ ) {
3483
+ throw new Error("Select between 1 and 100 retired consumer IDs");
3484
+ }
3485
+ const limit = options.limit === undefined ? 100 : Number(options.limit);
3486
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1000) {
3487
+ throw new Error("Derivation limit must be between 1 and 1000");
3488
+ }
3489
+ const budget = {};
3490
+ for (const name of ["maxVaultBytes", "minFreeBytes", "reserveBytes"]) {
3491
+ if (options[name] === undefined) continue;
3492
+ const value = Number(options[name]);
3493
+ if (!Number.isSafeInteger(value) || value < 0)
3494
+ throw new Error(`${name} must be a non-negative safe integer`);
3495
+ budget[name] = value;
3496
+ }
3497
+ if (options.audit && (options.state || options.kind)) {
3498
+ throw new Error(
3499
+ "Consumer audit includes all kinds and states; omit --kind and --state",
3500
+ );
3501
+ }
3502
+ if (
3503
+ operation === "status" &&
3504
+ Object.keys(budget).length &&
3505
+ !options.storage
3506
+ ) {
3507
+ throw new Error(
3508
+ "Storage budget options require --storage for derivation-status",
3509
+ );
3510
+ }
3511
+ // Check before constructing a registry: full hub startup may rebuild indexes.
3512
+ if (operation === "retry" && Object.keys(budget).length) {
3513
+ const minimal = await (options._getHub || getHubMinimal)();
3514
+ minimal.vault.assertStorageBudget(budget);
3515
+ }
3516
+ if (operation === "status" && options.storage) {
3517
+ if (options.adapter !== undefined || options.scope !== undefined) {
3518
+ throw new Error(
3519
+ "Storage reports cover the whole vault; omit --adapter and --scope",
3520
+ );
3521
+ }
3522
+ const minimal = await (options._getHub || getHubMinimal)();
3523
+ const result = { storage: minimal.vault.assertStorageBudget(budget) };
3524
+ printJson(result);
3525
+ return result;
3526
+ }
3527
+ const hub = await (
3528
+ options._getHub ||
3529
+ (operation === "consumers" || (operation === "prune" && options.dryRun)
3530
+ ? getHubMinimal
3531
+ : getHub)
3532
+ )();
3533
+ const filters = { adapter: options.adapter, scope: options.scope };
3534
+ let result;
3535
+ if (operation === "consumers") {
3536
+ result = options.audit
3537
+ ? hub.vault.getDerivationStore().auditConsumers({
3538
+ afterConsumerId: options.after,
3539
+ limit,
3540
+ })
3541
+ : hub.vault.getDerivationStore().listConsumers({
3542
+ state: options.state,
3543
+ kind: options.kind,
3544
+ afterConsumerId: options.after,
3545
+ limit,
3546
+ });
3547
+ } else if (operation === "prune") {
3548
+ result = hub.vault.getDerivationStore().pruneRetiredConsumers({
3549
+ consumerIds: options.consumer,
3550
+ activeConsumerId: hub.registry?.consumerId,
3551
+ limit,
3552
+ ...(options.dryRun ? { dryRun: true } : {}),
3553
+ });
3554
+ } else if (operation === "retry") {
3555
+ if (Object.keys(budget).length) hub.vault.assertStorageBudget(budget);
3556
+ result = await hub.registry.retryDerivations({ ...filters, limit });
3557
+ } else if (operation === "state") {
3558
+ result = hub.vault
3559
+ .getDerivationStore()
3560
+ .getState(reference.entityType, reference.entityId, {
3561
+ consumerId: hub.registry.consumerId,
3562
+ });
3563
+ } else if (operation === "delete") {
3564
+ const deleted = hub.vault.deleteEntity(
3565
+ reference.entityType,
3566
+ reference.entityId,
3567
+ );
3568
+ result = {
3569
+ deleted,
3570
+ derivations: await hub.registry.retryDerivations({ limit: 1000 }),
3571
+ };
3572
+ } else {
3573
+ result = hub.registry.getDerivationStatus(filters);
3574
+ }
3575
+ printJson(result);
3576
+ return result;
3577
+ } catch (error) {
3578
+ fail(null, error, options.json);
3579
+ }
3580
+ }
3581
+
3449
3582
  export function registerHubCommand(program, dependencies = {}) {
3450
3583
  const factory = readEvolutionCompositionFactory(dependencies);
3451
3584
  const invocationOptions = (options) => {
@@ -3571,6 +3704,96 @@ export function registerHubCommand(program, dependencies = {}) {
3571
3704
  .option("--json", "Output JSON")
3572
3705
  .action(cmdListAdapters);
3573
3706
 
3707
+ for (const [name, operation, description] of [
3708
+ [
3709
+ "derivation-status",
3710
+ "status",
3711
+ "Inspect KG/RAG delivery status for this vault",
3712
+ ],
3713
+ [
3714
+ "retry-derivations",
3715
+ "retry",
3716
+ "Retry a bounded page of KG/RAG work from current vault state",
3717
+ ],
3718
+ ]) {
3719
+ const command = hub
3720
+ .command(name)
3721
+ .description(description)
3722
+ .option("--adapter <name>", "Filter by source adapter")
3723
+ .option("--scope <scope>", "Filter by source scope")
3724
+ .option("--json", "Output JSON");
3725
+ command
3726
+ .option("--max-vault-bytes <n>", "Preflight maximum DB + WAL + SHM bytes")
3727
+ .option(
3728
+ "--min-free-bytes <n>",
3729
+ "Preflight minimum free disk bytes after reserve",
3730
+ )
3731
+ .option(
3732
+ "--reserve-bytes <n>",
3733
+ "Caller-estimated extra bytes for preflight (not a reservation)",
3734
+ );
3735
+ if (operation === "retry")
3736
+ command.option("--limit <n>", "Maximum deliveries (1-1000)", "100");
3737
+ else
3738
+ command.option(
3739
+ "--storage",
3740
+ "Inspect storage only and check the supplied byte budget",
3741
+ );
3742
+ command.action((options) => cmdDerivation(operation, null, options));
3743
+ }
3744
+
3745
+ hub
3746
+ .command("derivation-consumers")
3747
+ .description(
3748
+ "List registered derivation consumers without retirement tokens",
3749
+ )
3750
+ .option("--state <state>", "Filter by active or retired")
3751
+ .option(
3752
+ "--audit",
3753
+ "Inventory registered and historical consumers with retention reasons and receipt counts",
3754
+ )
3755
+ .option("--kind <kind>", "Filter by ephemeral or persistent")
3756
+ .option("--after <id>", "Continue after a consumer ID")
3757
+ .option("--limit <n>", "Maximum consumers (1-1000)", "100")
3758
+ .option("--json", "Output JSON")
3759
+ .action((options) => cmdDerivation("consumers", null, options));
3760
+
3761
+ hub
3762
+ .command("prune-derivations")
3763
+ .description(
3764
+ "Prune non-running receipts of explicitly selected retired ephemeral consumers",
3765
+ )
3766
+ .requiredOption("--consumer <ids...>", "Retired consumer IDs (1-100)")
3767
+ .option("--limit <n>", "Maximum receipts removed (1-1000)", "100")
3768
+ .option("--confirm", "Confirm removal of these retired projection receipts")
3769
+ .option(
3770
+ "--dry-run",
3771
+ "Validate IDs and preview bounded receipt cleanup without deletion",
3772
+ )
3773
+ .option("--json", "Output JSON")
3774
+ .action((options) => cmdDerivation("prune", null, options));
3775
+
3776
+ hub
3777
+ .command("derivation-state <entityType> <entityId>")
3778
+ .description(
3779
+ "Inspect an entity's source revision and KG/RAG receipts without its payload",
3780
+ )
3781
+ .option("--json", "Output JSON")
3782
+ .action((entityType, entityId, options) =>
3783
+ cmdDerivation("state", { entityType, entityId }, options),
3784
+ );
3785
+
3786
+ hub
3787
+ .command("delete-entity <entityType> <entityId>")
3788
+ .description(
3789
+ "Delete a normalized entity and queue index removal; raw archive remains and reimport may restore it",
3790
+ )
3791
+ .option("--confirm", "Confirm deletion of this normalized entity")
3792
+ .option("--json", "Output JSON")
3793
+ .action((entityType, entityId, options) =>
3794
+ cmdDerivation("delete", { entityType, entityId }, options),
3795
+ );
3796
+
3574
3797
  hub
3575
3798
  .command("readiness")
3576
3799
  .description(
@@ -4318,6 +4541,7 @@ export function registerHubCommand(program, dependencies = {}) {
4318
4541
  // `_wizard` / `_factoryDeps` / `_knownVendors` injected, bypassing the
4319
4542
  // real `getHub()` call. The commander wiring above is the runtime path.
4320
4543
  export const _internal = {
4544
+ cmdDerivation,
4321
4545
  cmdAsk,
4322
4546
  cmdRepl,
4323
4547
  cmdRetrieveContext,
@@ -14,6 +14,8 @@
14
14
  * cc project list [--user <id>] [--status <s>] [--limit <n>] [--json]
15
15
  * cc project show <id> [--json]
16
16
  * cc project delete <id> [--hard] [--json]
17
+ * cc project risk-evaluate --snapshot <json-file> [--json]
18
+ * cc project task-description-preview --snapshot <json-file> [--json]
17
19
  *
18
20
  * 设计 (per #21 v1.2 GA 反馈 "目标在手机端做ai项目的交互要像在电脑端那样丝滑"):
19
21
  * CLI 直接读写 desktop chainlesschain.db, 立刻在 desktop UI 出现,
@@ -21,6 +23,8 @@
21
23
  */
22
24
 
23
25
  import chalk from "chalk";
26
+ import fs from "node:fs";
27
+ import path from "node:path";
24
28
  import {
25
29
  openProjectsDb,
26
30
  defaultProjectDbPath,
@@ -30,6 +34,114 @@ import {
30
34
  } from "../lib/project-runtime.js";
31
35
 
32
36
  const DEFAULT_USER = "default";
37
+ const MAX_PROJECT_SNAPSHOT_BYTES = 2 * 1024 * 1024;
38
+
39
+ function snapshotFailure(code) {
40
+ const error = new Error(code);
41
+ error.code = code;
42
+ throw error;
43
+ }
44
+
45
+ /** Read a user-selected regular snapshot without following links or devices. */
46
+ function readProjectSnapshot(file, io = fs) {
47
+ if (
48
+ typeof file !== "string" ||
49
+ !file ||
50
+ /^[\\/]{2}[?.][\\/]/u.test(file) ||
51
+ (process.platform === "win32" &&
52
+ /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(
53
+ path.basename(file),
54
+ ))
55
+ )
56
+ snapshotFailure("SNAPSHOT_INVALID_PATH");
57
+ let fd;
58
+ try {
59
+ // Reject FIFO/device paths before opening. O_NONBLOCK also covers a POSIX
60
+ // file replaced by a FIFO between this check and the descriptor open.
61
+ if (!io.lstatSync(file).isFile())
62
+ snapshotFailure("SNAPSHOT_REGULAR_FILE_REQUIRED");
63
+ fd = io.openSync(
64
+ file,
65
+ fs.constants.O_RDONLY |
66
+ (fs.constants.O_NONBLOCK || 0) |
67
+ (fs.constants.O_NOFOLLOW || 0),
68
+ );
69
+ const before = io.fstatSync(fd);
70
+ if (!before.isFile()) snapshotFailure("SNAPSHOT_REGULAR_FILE_REQUIRED");
71
+ if (
72
+ !Number.isSafeInteger(before.size) ||
73
+ before.size < 0 ||
74
+ before.size > MAX_PROJECT_SNAPSHOT_BYTES
75
+ )
76
+ snapshotFailure("SNAPSHOT_FILE_TOO_LARGE");
77
+ const data = Buffer.alloc(before.size + 1);
78
+ let count = 0;
79
+ while (count < data.length) {
80
+ const read = io.readSync(fd, data, count, data.length - count, count);
81
+ if (read === 0) break;
82
+ count += read;
83
+ }
84
+ const after = io.fstatSync(fd);
85
+ if (
86
+ count !== before.size ||
87
+ after.size !== before.size ||
88
+ after.mtimeMs !== before.mtimeMs ||
89
+ after.ctimeMs !== before.ctimeMs
90
+ )
91
+ snapshotFailure("SNAPSHOT_CHANGED_DURING_READ");
92
+ let text;
93
+ try {
94
+ text = new TextDecoder("utf-8", { fatal: true }).decode(
95
+ data.subarray(0, count),
96
+ );
97
+ } catch {
98
+ snapshotFailure("SNAPSHOT_INVALID_UTF8");
99
+ }
100
+ try {
101
+ return JSON.parse(text);
102
+ } catch {
103
+ snapshotFailure("SNAPSHOT_INVALID_JSON");
104
+ }
105
+ } catch (error) {
106
+ if (error.code?.startsWith("SNAPSHOT_")) throw error;
107
+ snapshotFailure("SNAPSHOT_READ_FAILED");
108
+ } finally {
109
+ if (fd !== undefined) io.closeSync(fd);
110
+ }
111
+ }
112
+
113
+ function printSnapshotError(error, options) {
114
+ const code =
115
+ typeof error?.code === "string" &&
116
+ /^(SNAPSHOT|ACTION)_[A-Z_]+$/u.test(error.code)
117
+ ? error.code
118
+ : "SNAPSHOT_EVALUATION_FAILED";
119
+ if (options.json)
120
+ console.log(JSON.stringify({ status: "error", error: code }));
121
+ else console.error(chalk.red(code));
122
+ process.exitCode = 2;
123
+ }
124
+
125
+ function printProjectRisk(result) {
126
+ console.log("Offline project risk evaluation (unverified snapshot)");
127
+ console.log(`Status: ${result.status}`);
128
+ console.log(`Rule: ${result.ruleVersion}`);
129
+ if (result.asOf) console.log(`As of: ${result.asOf}`);
130
+ if (result.inputDigest) console.log(`Input: ${result.inputDigest}`);
131
+ if (result.status !== "evaluated") {
132
+ console.log(`Reasons: ${result.reasonCodes.join(", ")}`);
133
+ return;
134
+ }
135
+ console.log(
136
+ `Tasks: ${result.summary.taskCount}; matching tasks: ${result.summary.riskTaskCount}; overdue: ${result.summary.overdueTaskCount}; blocked: ${result.summary.blockedTaskCount}`,
137
+ );
138
+ for (const task of result.tasks) {
139
+ const blockers = task.blockingTaskRefs.map((ref) => ref.id).join(", ");
140
+ console.log(
141
+ `${task.taskRef.id}: ${task.reasonCodes.join(", ")}${blockers ? ` (dependencies: ${blockers})` : ""}`,
142
+ );
143
+ }
144
+ }
33
145
 
34
146
  function _now() {
35
147
  return Date.now();
@@ -74,6 +186,54 @@ export function registerProjectCommand(program) {
74
186
  "Manage desktop projects (shared SQLite, syncs to mobile via Phase 3d)",
75
187
  );
76
188
 
189
+ cmd
190
+ .command("risk-evaluate")
191
+ .description(
192
+ "Evaluate overdue tasks and direct blockers in an offline snapshot",
193
+ )
194
+ .requiredOption(
195
+ "--snapshot <json-file>",
196
+ "Complete project risk snapshot (max 2 MiB)",
197
+ )
198
+ .option("--json", "Output JSON")
199
+ .action(async (options) => {
200
+ try {
201
+ const snapshot = readProjectSnapshot(options.snapshot);
202
+ const { evaluateProjectRiskSnapshot } =
203
+ await import("@chainlesschain/session-core/project-risk-evaluation");
204
+ const result = evaluateProjectRiskSnapshot(snapshot);
205
+ if (options.json) console.log(JSON.stringify(result, null, 2));
206
+ else printProjectRisk(result);
207
+ if (result.status === "insufficient-data") process.exitCode = 2;
208
+ } catch (error) {
209
+ printSnapshotError(error, options);
210
+ }
211
+ });
212
+
213
+ cmd
214
+ .command("task-description-preview")
215
+ .description(
216
+ "Preview a task description request from an unverified offline snapshot",
217
+ )
218
+ .requiredOption(
219
+ "--snapshot <json-file>",
220
+ "Task/project/description/idempotencyKey JSON (max 2 MiB)",
221
+ )
222
+ .option("--json", "Output JSON")
223
+ .action(async (options) => {
224
+ try {
225
+ const snapshot = readProjectSnapshot(options.snapshot);
226
+ const { createTaskDescriptionPreview } =
227
+ await import("@chainlesschain/session-core/task-description-action-service");
228
+ const result = createTaskDescriptionPreview(snapshot);
229
+ if (!options.json)
230
+ console.log("Offline task description preview (unverified snapshot)");
231
+ console.log(JSON.stringify(result, null, 2));
232
+ } catch (error) {
233
+ printSnapshotError(error, options);
234
+ }
235
+ });
236
+
77
237
  // ===== init =====
78
238
  cmd
79
239
  .command("init <name>")
@@ -255,4 +415,6 @@ export function registerProjectCommand(program) {
255
415
  // 暴露给单测
256
416
  export const _projectInternals = {
257
417
  defaultProjectDbPath,
418
+ readProjectSnapshot,
419
+ MAX_PROJECT_SNAPSHOT_BYTES,
258
420
  };
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "source": "CHANGELOG.md",
3
3
  "releases": [
4
+ {
5
+ "productVersion": null,
6
+ "cliVersion": "0.166.91",
7
+ "cliVersions": ["0.166.91"],
8
+ "date": null,
9
+ "title": "",
10
+ "sections": [
11
+ {
12
+ "heading": "Fixed - cc CLI 0.166.91: cross-platform release validation",
13
+ "body": "- Accept verified directory identities through the Windows Server 2025 native\n file-information API, while retaining handle binding and reparse-point checks.\n- Preserve Windows native evaluator failure and cleanup evidence when the helper\n cannot publish a settlement. Compare journal identities within their pathname\n and descriptor domains on supported Node versions.\n- Keep literal audit search assertions independent of redacted operation text;\n verify that unsafe legacy text remains omitted from query results.\n- Give the receipt signer deadline test enough admission time on hosted runners\n and verify that the signer is actually invoked before its bounded timeout.\n- Regenerate the bundled CLI changelog from its canonical source.\n- Capture JetBrains transcript snapshots on the event dispatch thread during\n cross-platform host validation, retaining the full transcript assertions.\n- Preserve equivalent protected Windows evaluator ACLs across .NET Framework\n and PowerShell's .NET runtime through the native security API.\n- Retry cooperative lock release during nested safe owner reads without treating\n it as corruption; losing a held lock still fails closed.\n- Pin the patched `shell-quote` dependency in both workspace and standalone\n desktop installs to reject command injection after shell comment tokens.\n- Publish Session Core `0.3.16` and Personal Data Hub `0.4.64` before CLI\n `0.166.91`, with exact dependency pins and public package verification.\n- Pair VS Code `0.37.136` and JetBrains `0.4.154` with CLI `0.166.91` after\n the full exact-commit CLI and IDE validation workflows pass."
14
+ }
15
+ ]
16
+ },
17
+ {
18
+ "productVersion": null,
19
+ "cliVersion": "0.166.90",
20
+ "cliVersions": ["0.166.90"],
21
+ "date": "2026-10-06",
22
+ "title": "",
23
+ "sections": [
24
+ {
25
+ "heading": "Added - cc CLI 0.166.90: recoverable projections and project risk evidence",
26
+ "body": "- Verified on 2026-10-06: exact release commit `28cff6adc8` passed complete\n CLI CI, Strict Sandbox, IDE host and security gates. Session Core `0.3.15`,\n Agent SDK `0.2.13`, PDH `0.4.63` and CLI `0.166.90` were published through\n GitHub Actions OIDC with independent public archive verification. Open VSX\n `0.37.135` and JetBrains `0.4.153` are public; both publication workflows\n succeeded, and JetBrains approval/listing was independently read back.\n Desktop workbench changes are outside the separate v5.0.3.138 installer.\n- Publish Personal Data Hub `0.4.63` and Session Core `0.3.15` before the CLI,\n with exact dependency pins and public tarball verification. Require the full\n PDH suite with its declared native SQLCipher driver on Linux, Windows and macOS.\n- Publish Agent SDK `0.2.13` with Vitest `4.1.11` test tooling to remove the\n vulnerable Tinypool dependency, and upgrade the workspace proxy-addr to\n `2.0.8`. Require SDK build and tests on the exact Linux, Windows and macOS\n release commit before OIDC publication.\n- Persist PDH projection receipts, recover incomplete derivations and support\n bounded receipt retention. Harden RAG updates, audit redaction and capability\n reporting so unavailable sources do not appear as successful live collection.\n- Add offline project risk evaluation and version-bound task description\n previews. Session Core also supplies native SQLite action/read services and\n saved rule/source reviews for the desktop project workbench; CLI previews\n carry unverified snapshot authority and do not execute those desktop actions.\n- Pair VS Code `0.37.135` and JetBrains `0.4.153` with CLI `0.166.90` after\n exact-commit release checks and public npm readback."
27
+ }
28
+ ]
29
+ },
4
30
  {
5
31
  "productVersion": null,
6
32
  "cliVersion": "0.166.89",
@@ -193,7 +193,8 @@ async function withHub(fn, loadHub = getHub) {
193
193
  }
194
194
 
195
195
  function governedHubLoader(factory) {
196
- if (typeof factory === "function") return () => getGovernedAnalysisHub(factory);
196
+ if (typeof factory === "function")
197
+ return () => getGovernedAnalysisHub(factory);
197
198
  const error = new Error(
198
199
  "Personal Data Hub model egress requires an authenticated evolution composition factory",
199
200
  );
@@ -201,16 +202,24 @@ function governedHubLoader(factory) {
201
202
  throw error;
202
203
  }
203
204
 
205
+ function validateEntityReference(entityType, entityId) {
206
+ if (
207
+ !["event", "person", "place", "item", "topic"].includes(entityType) ||
208
+ typeof entityId !== "string" ||
209
+ !entityId.trim() ||
210
+ entityId.length > 1024
211
+ ) {
212
+ throw new Error("A valid entityType and entityId are required");
213
+ }
214
+ }
215
+
204
216
  export const PERSONAL_DATA_HUB_HANDLERS = {
205
217
  "personal-data-hub.ask": async (msg, context = {}) => {
206
218
  const factory = context.server?.evolutionCompositionFactory;
207
- return withHub(
208
- async (hub) => {
209
- if (!hub.engine) throw new Error("Analysis engine unavailable");
210
- return await hub.engine.ask(msg.question, msg.options || {});
211
- },
212
- governedHubLoader(factory),
213
- );
219
+ return withHub(async (hub) => {
220
+ if (!hub.engine) throw new Error("Analysis engine unavailable");
221
+ return await hub.engine.ask(msg.question, msg.options || {});
222
+ }, governedHubLoader(factory));
214
223
  },
215
224
 
216
225
  // Path Y: prompt context only, no LLM call. Lets web-shell / mobile host
@@ -250,6 +259,43 @@ export const PERSONAL_DATA_HUB_HANDLERS = {
250
259
  "personal-data-hub.list-adapters": async () =>
251
260
  withHub((hub) => hub.registry.list()),
252
261
 
262
+ "personal-data-hub.derivation-status": async (msg) =>
263
+ withHub((hub) =>
264
+ hub.registry.getDerivationStatus({
265
+ adapter: msg.adapter,
266
+ scope: msg.scope,
267
+ }),
268
+ ),
269
+
270
+ "personal-data-hub.derivation-state": async (msg) =>
271
+ withHub((hub) => {
272
+ validateEntityReference(msg.entityType, msg.entityId);
273
+ return hub.vault
274
+ .getDerivationStore()
275
+ .getState(msg.entityType, msg.entityId, {
276
+ consumerId: hub.registry.consumerId,
277
+ });
278
+ }),
279
+
280
+ "personal-data-hub.retry-derivations": async (msg) =>
281
+ withHub((hub) =>
282
+ hub.registry.retryDerivations({
283
+ adapter: msg.adapter,
284
+ scope: msg.scope,
285
+ limit: msg.limit,
286
+ }),
287
+ ),
288
+
289
+ "personal-data-hub.delete-entity": async (msg) =>
290
+ withHub(async (hub) => {
291
+ if (msg.confirm !== true)
292
+ throw new Error("Entity deletion requires confirm: true");
293
+ validateEntityReference(msg.entityType, msg.entityId);
294
+ const deleted = hub.vault.deleteEntity(msg.entityType, msg.entityId);
295
+ const derivations = await hub.registry.retryDerivations({ limit: 1000 });
296
+ return { deleted, derivations };
297
+ }),
298
+
253
299
  // Per-adapter readiness ("能否采集 + 不能的原因"). Probes each adapter's
254
300
  // authenticate({ readinessOnly: true }) — see AdapterRegistry.readiness().
255
301
  // The web-shell PersonalDataHub view renders this as a 就绪状态 column so