chainlesschain 0.162.198 → 0.163.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/bin/chainlesschain.js +14 -6
  2. package/package.json +5 -1
  3. package/scripts/command-lifecycle-report.mjs +94 -0
  4. package/scripts/postinstall.mjs +19 -3
  5. package/scripts/repair-node-pty.mjs +74 -0
  6. package/src/assets/web-panel/assets/{AIOps-CSN-D2xb.js → AIOps-CSy9BB6Z.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-CBSMlGzv.js → ActionButton-CFyrEVfq.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-3yr3Nt2t.js → Analytics-8419vb47.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-1b-o3lMH.js → AppLayout-CHu3Hkdx.js} +5 -5
  10. package/src/assets/web-panel/assets/{Artifacts-Dr8rJi17.js → Artifacts-DJnt57Fs.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-2V689HC2.js → Audit-CHMq9ajE.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-DIxkNrD_.js → BackgroundAgents-Cyfa4ub2.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-Pg6BcwrE.js → Backup-ACXUrUv7.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-CLUpqyfH.js → BaseInput-DjC-3qRE.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-qVS8rD4G.js → Chat-7_VDQ851.js} +6 -6
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-ti49X12Q.js → ChatBubbleRenderer-B4zct0dY.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-Bs9AaEay.js → Checkbox-DxbDl_rk.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-Dvc1mq8q.js → Codegen-BvZa5854.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-C4_biO7A.js → Col-CX5Ow2Zl.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-al25XQUV.js → Community-wFun-jSg.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-D-ZDB8M1.js → Compact-C6vJDuSn.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-6lIfDz1W.js → Compliance-Cm4sBytH.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-DdI48XMJ.js → Cowork-DiEcMwE8.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-DF5HZd2g.js → Cron-RbeexsSQ.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-DuxeSvt3.js → Crosschain-BBsyCKOp.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-B9yHkUTd.js → DID-DE36g7Hz.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-Z5EuI3IM.js → Dashboard-CdfLSTz1.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-vuRfO3dY.js → Dropdown-CyaT6SyW.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-QFLCc1uL.js → EmailListRenderer-Nv_66bkM.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BZ7EXkFJ.js → FamilyGuardDashboard-Di-Sb-Ad.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-DycIEg2s.js → Federation-B3mdht-U.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-Ba0H_7yG.js → FormItemContext-BeP93u4f.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer--JgSTK-C.js → GenericCardRenderer-CETLayUr.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-DEvTbldE.js → Git-Bsat6hgI.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-BJIljy18.js → Governance-YVmA7SwN.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-CVyW3G3q.js → Inference-DCa94nGl.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-v8-borge.js → KnowledgeGraph-CIKEU7T0.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BCdS7gGo.js → Logs-DUxP0MnS.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-CU-JB2Ns.js → MarkdownRenderer-Mw5o3e7M.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-AN6tGA2B.js → Marketplace-BU0X2lqu.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-DGViXASN.js → McpTools-BSsg58nZ.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-Bpvmx9X4.js → Memory-CjqNIXlO.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-CTP-DOTC.js → MobileBridge-DSsa4doG.js} +1 -1
  44. package/src/assets/web-panel/assets/MobileProjects-DLl1qzid.js +1 -0
  45. package/src/assets/web-panel/assets/{Mtc-ndYr0M1s.js → Mtc-Du080G7t.js} +5 -5
  46. package/src/assets/web-panel/assets/{MtcAudit-Ci0-YK7W.js → MtcAudit-JzQk-arw.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-BehSTFW7.js → Multisig-BMVT5Uln.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-B91_YBLv.js → NLProgramming-D_38QYjs.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-BQlJ0-gq.js → Notes-DvbdjNm5.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-CDgYMjYK.js → NotificationSettings-DVHCW6ii.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-BJkSlKeH.js → OrderTableRenderer-DmMBFD3g.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-B-b3cWCp.js → Organization-DC-9pAmP.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-CILUL4nL.js → Overflow-BRxWq0Qq.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-BTCFBkF0.js → P2P-CUdzhyLH.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-BAR6AUx5.js → PdhVaultBrowser-CwG21s9P.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-RRf6HbWJ.js → Permissions-6bHd4zgK.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-BGTMiICa.js → PersonalDataHub-BXgTDCba.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-945qY9YF.js → Pipeline-BFhKCBNj.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-DPZwI6lJ.js → Privacy-Byz9IqUF.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-BPH2NRKc.js → ProjectInit-B9LNoyoN.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-BZCRNCvb.js → ProjectSettings-DEj4eVdl.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-BTI__tBt.js → Projects-BAAvus06.js} +1 -1
  63. package/src/assets/web-panel/assets/Providers-Bu_pQsk6.js +1 -0
  64. package/src/assets/web-panel/assets/{QrScannerModal-N6rbqt1r.js → QrScannerModal-CeDey0SJ.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-DrwjPS7M.js → QuickAsk-exUvRIgX.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-Cog9Wd99.js → Recommend-4hJWmtSI.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-DC9pynjM.js → RemoteSession-BmYUpl0m.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-D4th4gKS.js → Reputation-B_txYAyY.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-ogiWR6v9.js → Row-BPtqOqGh.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-uYlk-2Oj.js → RssFeed-CyWTxmq0.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-DYzzwvtM.js → Search-cItU1tmC.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-Da7YOyX6.js → Security-B0Z9_BUt.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-CLI1VM1X.js → Services-Dzpz2uFp.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-DK77dzDC.js → Skeleton-CBtoylP8.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-C_z7Lmhl.js → Skills-Cw9RJiVn.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-D6413Q8L.js → Sla-D2vLfvgl.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-C07ydbj2.js → SpeechSettings-I9dKbcOU.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-DGOm2W22.js → SyncSettings-BOju53RT.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-Cr_PVyLM.js → Tasks-C3LBy_7x.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-BhL2mZ0t.js → Templates-C2ttpPql.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-CPk5oyUr.js → Tenant-XQ6Qg8-Q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-ClhqUsqV.js → Terminal-DYB9dUnS.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-BCC7MV5a.js → TimelineRenderer-gShtO4I8.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-DD1Jt4oO.js → Tokens-BvoJTCJg.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-BCydFvN2.js → Trigger-BwYRTMY_.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-DDHT1noa.js → Trust-C5rt6fCF.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CWPZC7oI.js → UkeySign-DPBrHUgL.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-9Ea0nJR0.js → VideoEditing-BcxywO_K.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-BjxhLxTf.js → Wallet-CZvTpsPz.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-C6uCye67.js → WebAuthn-LI_jAuOx.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-d2g4reYo.js → WorkflowEditor-B2a6bANB.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-frTc6ScX.js → chat-B6DPMfRB.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-B5K6lG3v.js → colors-IpLhw9T8.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-Cdn46r8D.js → compact-item-BzodimsI.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-DU1jqVQi.js → createContext-DL2jaWH5.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CZB0EDsa.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-DdNH-aW_.js → hasIn-C4Geudre.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CHmkkdfT.js → index-B5Sn7CtW.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Cj6P9Nst.js → index-B6w4fpSI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQorP1Ng.js → index-BRj6YKuI.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-cYaWV4Mq.js → index-BX4pKudW.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-kVO_MDm-.js → index-BaTvPxY0.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D23xGYjM.js → index-BbWRxWM2.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Be4OtL-N.js → index-BeZhISVl.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-32ajXmTb.js → index-Bi6Zkv5M.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-NmEXVjzt.js → index-BvKoSvko.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-7ehytj1K.js → index-C3LzRvkw.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-gg3QPC3i.js → index-CAjyUjZl.js} +3 -3
  109. package/src/assets/web-panel/assets/index-CI7k8Sk9.js +1 -0
  110. package/src/assets/web-panel/assets/{index-CGiwfwB9.js → index-COxGCo8v.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DIVyTmZ3.js → index-CQBPhJlk.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CUoNAmE8.js → index-CQPOCB4h.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-t_OBzIP4.js → index-CTlmw_cr.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-VDM2KKo9.js → index-CVFXYmUe.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DftZuyA7.js → index-C_SxaIPI.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BcGwGIaR.js → index-CaKKxqCI.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-HjCvXHf5.js → index-CcgoKNXN.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-mgU3Q-lN.js → index-CczBR6Du.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DM5FmPZU.js → index-CeUnSSEP.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-D4l82Me1.js → index-CnwHp5Oi.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BwlIxAmX.js → index-DGBRBg3D.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BVLL-mq_.js → index-DHdD0Y7h.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BXKhhx9V.js → index-DMY1waPC.js} +1 -1
  124. package/src/assets/web-panel/assets/index-DPTHBSR8.js +1 -0
  125. package/src/assets/web-panel/assets/{index-LaivuXyF.js → index-DREx4gaS.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CtRPi4YC.js → index-DXQ2OtXt.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DRzBBdQ0.js → index-DZU7Y67X.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-PjAS0sIZ.js → index-DZtKnnTW.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-MM4Zz2OE.js → index-DlABpgCv.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BoFak7le.js → index-Dl_QAtzq.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-D1qIC4GR.js → index-DnBybYhx.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D4miNkWv.js → index-DoyIjk6r.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DtBCCkC4.js → index-DvEnrn8M.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BC4eGkar.js → index-DvOzjf2F.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-yZRuZpwK.js → index-EjW1R_a7.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-Dca_i7H8.js → index-F-SCUTee.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-DwLTRNdo.js → initDefaultProps-CW5mTl3w.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-BchZDXnh.js → motion-BtjIT9np.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-e8M-zZFl.js → move-DZv4fZAV.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-Ci40fQb3.js → mtc-parser-BwCix1O-.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-C7110_f2.js → omit-BW72HDUD.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-skteMgnM.js → pickAttrs-DBW2jcMc.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-MGZ-lh2B.js → placementArrow-D3YmWlIS.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-N4Sd7uy-.js → responsiveObserve-CL4-a-9Q.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-C7HDGRaa.js → slide-Cw9zIbXQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-BhRexlgy.js → statusUtils-mMLVioo-.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-ChEoQkN2.js → styleChecker-BK8857AH.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-CDbG1s2Y.js → useFlexGapSupport-C1iSaJij.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-CUIx0tcJ.js → useFs-D3riGOaP.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-bkO7L7ec.js → usePersonalDataHub-Bwqvmz4X.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-B_ZvABIG.js → vnode-Byk4zzkf.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-D5shjpS8.js → zoom-D7INFTp2.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +1 -1
  155. package/src/commands/mcp.js +119 -0
  156. package/src/commands/session-show.js +8 -10
  157. package/src/commands/session.js +60 -52
  158. package/src/data/changelog.json +40 -1
  159. package/src/gateways/ws/session-protocol.js +14 -4
  160. package/src/gateways/ws/ws-agent-handler.js +31 -0
  161. package/src/harness/jsonl-session-store.js +1147 -130
  162. package/src/harness/mcp-client.js +44 -11
  163. package/src/harness/session-index.js +80 -80
  164. package/src/harness/session-list-index.js +147 -2
  165. package/src/lib/background-interaction-journal.js +2 -2
  166. package/src/lib/command-lifecycle-report.js +516 -0
  167. package/src/lib/mcp-stdio-environment.js +48 -0
  168. package/src/lib/mcp-stdio-executable-identity.js +552 -17
  169. package/src/lib/mcp-stdio-package-materialization.js +1424 -0
  170. package/src/lib/packer/native-update-state.js +979 -1
  171. package/src/lib/packer/pack-update-applier.js +1050 -125
  172. package/src/lib/packer/pkg-config-generator.js +1 -0
  173. package/src/lib/paths.js +53 -0
  174. package/src/lib/process-execution-broker/index.js +180 -37
  175. package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
  176. package/src/lib/recent-session.js +17 -17
  177. package/src/lib/secure-file-identity.js +47 -0
  178. package/src/lib/secure-fs.js +21 -2
  179. package/src/lib/session-anti-rollback-anchor.js +766 -0
  180. package/src/lib/session-host-lease.js +492 -0
  181. package/src/lib/session-persistence-failure.js +109 -0
  182. package/src/lib/session-picker.js +26 -3
  183. package/src/lib/session-search.js +25 -11
  184. package/src/lib/side-effect-ledger-store.js +2 -2
  185. package/src/lib/skill-execution-authority.js +13 -9
  186. package/src/lib/turn-binding-store.js +2 -2
  187. package/src/repl/agent-repl.js +309 -39
  188. package/src/runtime/agent-core.js +88 -5
  189. package/src/runtime/cleanup-deadline.js +143 -0
  190. package/src/runtime/headless-runner.js +357 -139
  191. package/src/runtime/headless-stream.js +207 -28
  192. package/src/runtime/output-backpressure.js +53 -0
  193. package/src/assets/web-panel/assets/MobileProjects-C8qfktxn.js +0 -1
  194. package/src/assets/web-panel/assets/Providers-DDCf_nIw.js +0 -1
  195. package/src/assets/web-panel/assets/devWarning-CP-jEUyw.js +0 -1
  196. package/src/assets/web-panel/assets/index-CzrCHrFy.js +0 -1
  197. package/src/assets/web-panel/assets/index-OJsGskZw.js +0 -1
@@ -0,0 +1,516 @@
1
+ /**
2
+ * Privacy-preserving command lifecycle telemetry aggregation.
3
+ *
4
+ * The runtime emits one content-free OTLP metric for each migrated command
5
+ * invocation. This module consumes those OTLP payloads and combines them with
6
+ * an explicit collector coverage statement. Alias removal is fail-closed:
7
+ * missing release cycles, weak coverage, undocumented sampling bias or invalid
8
+ * metric points can only produce `insufficient-data`.
9
+ */
10
+
11
+ export const COMMAND_LIFECYCLE_REPORT_SCHEMA =
12
+ "chainlesschain.command-lifecycle-report.v1";
13
+ export const COMMAND_LIFECYCLE_COVERAGE_SCHEMA =
14
+ "chainlesschain.command-lifecycle-coverage.v1";
15
+ export const COMMAND_LIFECYCLE_INVOCATION_METRIC =
16
+ "chainlesschain.cli.command.lifecycle.invocations";
17
+
18
+ export const COMMAND_ALIAS_DECISION_POLICY = Object.freeze({
19
+ minimumObservedMinorCycles: 2,
20
+ minimumEligibleInstallations: 50,
21
+ minimumReportingInstallations: 30,
22
+ minimumCollectorCoverageRatio: 0.5,
23
+ minimumSampleRate: 0.1,
24
+ minimumCommandInvocations: 200,
25
+ minimumReplacementInvocations: 100,
26
+ maximumLegacyShareForRemoval: 0.01,
27
+ requiredPlatforms: Object.freeze(["linux", "macos", "windows"]),
28
+ });
29
+
30
+ const REQUIRED_ATTRIBUTES = Object.freeze([
31
+ "command.name",
32
+ "command.route",
33
+ "command.outcome",
34
+ "cli.version",
35
+ "command.deprecated_since",
36
+ "command.removal_not_before",
37
+ ]);
38
+ const ALLOWED_ATTRIBUTES = new Set(REQUIRED_ATTRIBUTES);
39
+ const EXACT_RELEASE = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
40
+ const COMMAND_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
41
+
42
+ function parseRelease(value) {
43
+ if (typeof value !== "string") return null;
44
+ const match = EXACT_RELEASE.exec(value);
45
+ if (!match) return null;
46
+ return {
47
+ value,
48
+ major: Number(match[1]),
49
+ minor: Number(match[2]),
50
+ patch: Number(match[3]),
51
+ prerelease: match[4] || null,
52
+ };
53
+ }
54
+
55
+ function compareReleases(left, right) {
56
+ const a = typeof left === "string" ? parseRelease(left) : left;
57
+ const b = typeof right === "string" ? parseRelease(right) : right;
58
+ if (!a || !b) return null;
59
+ for (const key of ["major", "minor", "patch"]) {
60
+ if (a[key] !== b[key]) return a[key] < b[key] ? -1 : 1;
61
+ }
62
+ if (a.prerelease === b.prerelease) return 0;
63
+ if (a.prerelease === null) return 1;
64
+ if (b.prerelease === null) return -1;
65
+ return a.prerelease.localeCompare(b.prerelease);
66
+ }
67
+
68
+ function otlpValue(value) {
69
+ if (!value || typeof value !== "object") return undefined;
70
+ for (const key of ["stringValue", "intValue", "doubleValue", "boolValue"]) {
71
+ if (Object.hasOwn(value, key)) return value[key];
72
+ }
73
+ return undefined;
74
+ }
75
+
76
+ function attributesFor(point) {
77
+ if (!Array.isArray(point?.attributes)) return null;
78
+ const attributes = {};
79
+ for (const item of point.attributes) {
80
+ if (
81
+ !item ||
82
+ typeof item.key !== "string" ||
83
+ !ALLOWED_ATTRIBUTES.has(item.key) ||
84
+ Object.hasOwn(attributes, item.key)
85
+ ) {
86
+ return null;
87
+ }
88
+ attributes[item.key] = otlpValue(item.value);
89
+ }
90
+ return attributes;
91
+ }
92
+
93
+ function pointCount(point) {
94
+ const raw = Object.hasOwn(point || {}, "asInt")
95
+ ? point.asInt
96
+ : point?.asDouble;
97
+ const value = Number(raw);
98
+ return Number.isSafeInteger(value) && value > 0 ? value : null;
99
+ }
100
+
101
+ function metricPayloads(document) {
102
+ if (Array.isArray(document)) {
103
+ return document.flatMap((entry) => metricPayloads(entry));
104
+ }
105
+ if (!document || typeof document !== "object") return [];
106
+ if (document.body) return metricPayloads(document.body);
107
+ if (Array.isArray(document.requests)) {
108
+ return metricPayloads(document.requests);
109
+ }
110
+ return Array.isArray(document.resourceMetrics) ? [document] : [];
111
+ }
112
+
113
+ function lifecycleEntries(manifest) {
114
+ return (manifest?.commands || [])
115
+ .filter(
116
+ (entry) =>
117
+ entry?.lifecycle?.state === "deprecated" &&
118
+ typeof entry.replacement === "string",
119
+ )
120
+ .sort((left, right) => left.name.localeCompare(right.name));
121
+ }
122
+
123
+ function blankCommand(entry) {
124
+ return {
125
+ command: entry.name,
126
+ replacement: entry.replacement,
127
+ deprecatedSince: entry.lifecycle.deprecatedSince,
128
+ removalNotBefore: entry.lifecycle.removalNotBefore,
129
+ minimumReleaseCycles: entry.lifecycle.minimumReleaseCycles,
130
+ legacy: { invocations: 0, completed: 0, error: 0 },
131
+ replacementRoute: { invocations: 0, completed: 0, error: 0 },
132
+ versions: new Set(),
133
+ };
134
+ }
135
+
136
+ function validateCoverage(coverage, policy) {
137
+ const blockers = [];
138
+ if (coverage?.schema !== COMMAND_LIFECYCLE_COVERAGE_SCHEMA) {
139
+ blockers.push("coverage-schema-invalid");
140
+ }
141
+
142
+ const decisionVersion = parseRelease(coverage?.decisionVersion);
143
+ if (!decisionVersion) blockers.push("decision-version-invalid");
144
+
145
+ const observedReleases = Array.isArray(coverage?.observedReleases)
146
+ ? coverage.observedReleases.map(parseRelease)
147
+ : [];
148
+ if (
149
+ observedReleases.length === 0 ||
150
+ observedReleases.some((release) => !release)
151
+ ) {
152
+ blockers.push("observed-releases-invalid");
153
+ }
154
+ const observedMinorCycles = new Set(
155
+ observedReleases
156
+ .filter(Boolean)
157
+ .map((release) => `${release.major}.${release.minor}`),
158
+ );
159
+ if (observedMinorCycles.size < policy.minimumObservedMinorCycles) {
160
+ blockers.push("release-observation-window-incomplete");
161
+ }
162
+
163
+ const startMs = Date.parse(coverage?.window?.startedAt || "");
164
+ const endMs = Date.parse(coverage?.window?.endedAt || "");
165
+ if (
166
+ !Number.isFinite(startMs) ||
167
+ !Number.isFinite(endMs) ||
168
+ endMs <= startMs
169
+ ) {
170
+ blockers.push("observation-window-invalid");
171
+ }
172
+
173
+ const collector = coverage?.collector || {};
174
+ const eligibleInstallations = Number(collector.eligibleInstallations);
175
+ const reportingInstallations = Number(collector.reportingInstallations);
176
+ const sampleRate = Number(collector.sampleRate);
177
+ const coverageRatio =
178
+ Number.isFinite(eligibleInstallations) && eligibleInstallations > 0
179
+ ? reportingInstallations / eligibleInstallations
180
+ : 0;
181
+ if (
182
+ !Number.isSafeInteger(eligibleInstallations) ||
183
+ eligibleInstallations < policy.minimumEligibleInstallations
184
+ ) {
185
+ blockers.push("eligible-installation-cohort-too-small");
186
+ }
187
+ if (
188
+ !Number.isSafeInteger(reportingInstallations) ||
189
+ reportingInstallations < policy.minimumReportingInstallations ||
190
+ reportingInstallations > eligibleInstallations
191
+ ) {
192
+ blockers.push("reporting-installation-cohort-too-small");
193
+ }
194
+ if (coverageRatio < policy.minimumCollectorCoverageRatio) {
195
+ blockers.push("collector-coverage-too-low");
196
+ }
197
+ if (
198
+ !Number.isFinite(sampleRate) ||
199
+ sampleRate < policy.minimumSampleRate ||
200
+ sampleRate > 1
201
+ ) {
202
+ blockers.push("sample-rate-too-low-or-invalid");
203
+ }
204
+
205
+ const platforms = collector.platforms || {};
206
+ for (const platform of policy.requiredPlatforms) {
207
+ if (
208
+ !Number.isSafeInteger(platforms[platform]) ||
209
+ platforms[platform] <= 0
210
+ ) {
211
+ blockers.push(`platform-coverage-missing:${platform}`);
212
+ }
213
+ }
214
+
215
+ const knownBiases = Array.isArray(collector.knownBiases)
216
+ ? collector.knownBiases
217
+ : [];
218
+ if (knownBiases.length === 0) {
219
+ blockers.push("collector-bias-not-documented");
220
+ }
221
+ for (const bias of knownBiases) {
222
+ if (
223
+ !bias ||
224
+ typeof bias.id !== "string" ||
225
+ typeof bias.description !== "string"
226
+ ) {
227
+ blockers.push("collector-bias-entry-invalid");
228
+ continue;
229
+ }
230
+ if (bias.blocking === true) {
231
+ blockers.push(`collector-bias-blocking:${bias.id}`);
232
+ }
233
+ }
234
+
235
+ return {
236
+ ready: blockers.length === 0,
237
+ blockers: [...new Set(blockers)].sort(),
238
+ decisionVersion: decisionVersion?.value || null,
239
+ observedReleases: observedReleases
240
+ .filter(Boolean)
241
+ .map((release) => release.value),
242
+ observedMinorCycles: [...observedMinorCycles].sort(),
243
+ window: {
244
+ startedAt: Number.isFinite(startMs)
245
+ ? new Date(startMs).toISOString()
246
+ : null,
247
+ endedAt: Number.isFinite(endMs) ? new Date(endMs).toISOString() : null,
248
+ },
249
+ collector: {
250
+ eligibleInstallations:
251
+ Number.isSafeInteger(eligibleInstallations) &&
252
+ eligibleInstallations >= 0
253
+ ? eligibleInstallations
254
+ : null,
255
+ reportingInstallations:
256
+ Number.isSafeInteger(reportingInstallations) &&
257
+ reportingInstallations >= 0
258
+ ? reportingInstallations
259
+ : null,
260
+ coverageRatio,
261
+ sampleRate: Number.isFinite(sampleRate) ? sampleRate : null,
262
+ platforms: Object.fromEntries(
263
+ policy.requiredPlatforms.map((platform) => [
264
+ platform,
265
+ Number.isSafeInteger(platforms[platform]) && platforms[platform] >= 0
266
+ ? platforms[platform]
267
+ : 0,
268
+ ]),
269
+ ),
270
+ knownBiases: knownBiases
271
+ .filter(
272
+ (bias) =>
273
+ bias &&
274
+ typeof bias.id === "string" &&
275
+ typeof bias.description === "string",
276
+ )
277
+ .map((bias) => ({
278
+ id: bias.id,
279
+ description: bias.description,
280
+ blocking: bias.blocking === true,
281
+ })),
282
+ },
283
+ };
284
+ }
285
+
286
+ function decisionFor(command, coverage, ingestionReady, policy) {
287
+ const total =
288
+ command.legacy.invocations + command.replacementRoute.invocations;
289
+ const legacyShare = total > 0 ? command.legacy.invocations / total : null;
290
+ const reasons = [];
291
+ const removalComparison = compareReleases(
292
+ coverage.decisionVersion,
293
+ command.removalNotBefore,
294
+ );
295
+ if (!coverage.ready) reasons.push(...coverage.blockers);
296
+ if (!ingestionReady) reasons.push("telemetry-input-invalid");
297
+ if (removalComparison === null || removalComparison < 0) {
298
+ reasons.push("removal-version-not-reached");
299
+ }
300
+
301
+ const observedForCommand = coverage.observedReleases.filter((version) => {
302
+ const afterDeprecation = compareReleases(version, command.deprecatedSince);
303
+ const beforeDecision = compareReleases(version, coverage.decisionVersion);
304
+ return (
305
+ afterDeprecation !== null && afterDeprecation >= 0 && beforeDecision <= 0
306
+ );
307
+ });
308
+ const observedCycles = new Set(
309
+ observedForCommand.map((version) => {
310
+ const parsed = parseRelease(version);
311
+ return `${parsed.major}.${parsed.minor}`;
312
+ }),
313
+ );
314
+ if (observedCycles.size < command.minimumReleaseCycles) {
315
+ reasons.push("command-release-window-incomplete");
316
+ }
317
+ if (total < policy.minimumCommandInvocations) {
318
+ reasons.push("command-sample-too-small");
319
+ }
320
+
321
+ if (reasons.length > 0) {
322
+ return {
323
+ decision: "insufficient-data",
324
+ reasons: [...new Set(reasons)].sort(),
325
+ totalInvocations: total,
326
+ legacyShare,
327
+ observedMinorCycles: [...observedCycles].sort(),
328
+ };
329
+ }
330
+
331
+ if (legacyShare > policy.maximumLegacyShareForRemoval) {
332
+ return {
333
+ decision: "retain",
334
+ reasons: ["legacy-usage-above-removal-threshold"],
335
+ totalInvocations: total,
336
+ legacyShare,
337
+ observedMinorCycles: [...observedCycles].sort(),
338
+ };
339
+ }
340
+ if (
341
+ command.replacementRoute.invocations < policy.minimumReplacementInvocations
342
+ ) {
343
+ return {
344
+ decision: "insufficient-data",
345
+ reasons: ["replacement-sample-too-small"],
346
+ totalInvocations: total,
347
+ legacyShare,
348
+ observedMinorCycles: [...observedCycles].sort(),
349
+ };
350
+ }
351
+ return {
352
+ decision: "remove",
353
+ reasons: ["compatibility-window-and-usage-thresholds-satisfied"],
354
+ totalInvocations: total,
355
+ legacyShare,
356
+ observedMinorCycles: [...observedCycles].sort(),
357
+ };
358
+ }
359
+
360
+ export function buildCommandLifecycleReport({
361
+ documents = [],
362
+ manifest,
363
+ coverage,
364
+ generatedAt = new Date().toISOString(),
365
+ policy = COMMAND_ALIAS_DECISION_POLICY,
366
+ } = {}) {
367
+ const entries = lifecycleEntries(manifest);
368
+ if (entries.length === 0) {
369
+ throw new Error("command manifest has no deprecated compatibility entries");
370
+ }
371
+ const byCommand = new Map(
372
+ entries.map((entry) => [entry.name, blankCommand(entry)]),
373
+ );
374
+ const violations = [];
375
+ let acceptedPoints = 0;
376
+ let rejectedPoints = 0;
377
+ let payloadCount = 0;
378
+
379
+ for (const payload of metricPayloads(documents)) {
380
+ payloadCount += 1;
381
+ for (const resource of payload.resourceMetrics || []) {
382
+ for (const scope of resource.scopeMetrics || []) {
383
+ for (const metric of scope.metrics || []) {
384
+ if (metric?.name !== COMMAND_LIFECYCLE_INVOCATION_METRIC) continue;
385
+ for (const point of metric?.sum?.dataPoints || []) {
386
+ const attributes = attributesFor(point);
387
+ const count = pointCount(point);
388
+ const command = attributes
389
+ ? byCommand.get(attributes["command.name"])
390
+ : null;
391
+ const valid =
392
+ attributes &&
393
+ REQUIRED_ATTRIBUTES.every((key) =>
394
+ Object.hasOwn(attributes, key),
395
+ ) &&
396
+ Object.keys(attributes).length === REQUIRED_ATTRIBUTES.length &&
397
+ count !== null &&
398
+ command &&
399
+ COMMAND_NAME.test(attributes["command.name"]) &&
400
+ ["legacy", "replacement"].includes(attributes["command.route"]) &&
401
+ ["completed", "error"].includes(attributes["command.outcome"]) &&
402
+ parseRelease(attributes["cli.version"]) &&
403
+ attributes["command.deprecated_since"] ===
404
+ command?.deprecatedSince &&
405
+ attributes["command.removal_not_before"] ===
406
+ command?.removalNotBefore;
407
+ if (!valid) {
408
+ rejectedPoints += 1;
409
+ violations.push("invalid-lifecycle-metric-point");
410
+ continue;
411
+ }
412
+
413
+ acceptedPoints += 1;
414
+ const bucket =
415
+ attributes["command.route"] === "legacy"
416
+ ? command.legacy
417
+ : command.replacementRoute;
418
+ bucket.invocations += count;
419
+ bucket[attributes["command.outcome"]] += count;
420
+ command.versions.add(attributes["cli.version"]);
421
+ }
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ const coverageResult = validateCoverage(coverage, policy);
428
+ const ingestionReady = rejectedPoints === 0 && acceptedPoints > 0;
429
+ if (acceptedPoints === 0) violations.push("no-lifecycle-metric-points");
430
+
431
+ const decisions = [...byCommand.values()].map((command) => {
432
+ const recommendation = decisionFor(
433
+ command,
434
+ coverageResult,
435
+ ingestionReady,
436
+ policy,
437
+ );
438
+ return {
439
+ command: command.command,
440
+ replacement: command.replacement,
441
+ deprecatedSince: command.deprecatedSince,
442
+ removalNotBefore: command.removalNotBefore,
443
+ legacy: command.legacy,
444
+ replacementRoute: command.replacementRoute,
445
+ observedVersions: [...command.versions].sort((left, right) =>
446
+ compareReleases(left, right),
447
+ ),
448
+ ...recommendation,
449
+ };
450
+ });
451
+ const summary = decisions.reduce(
452
+ (result, item) => {
453
+ result[item.decision] += 1;
454
+ return result;
455
+ },
456
+ { retain: 0, remove: 0, "insufficient-data": 0 },
457
+ );
458
+
459
+ return {
460
+ schema: COMMAND_LIFECYCLE_REPORT_SCHEMA,
461
+ generatedAt: new Date(generatedAt).toISOString(),
462
+ manifestSchema: manifest?.schema || null,
463
+ policy: {
464
+ ...policy,
465
+ requiredPlatforms: [...policy.requiredPlatforms],
466
+ },
467
+ coverage: coverageResult,
468
+ ingestion: {
469
+ payloadCount,
470
+ acceptedPoints,
471
+ rejectedPoints,
472
+ ready: ingestionReady,
473
+ violations: [...new Set(violations)].sort(),
474
+ },
475
+ summary,
476
+ decisions,
477
+ };
478
+ }
479
+
480
+ export function renderCommandLifecycleReportMarkdown(report) {
481
+ const lines = [
482
+ "# CLI command lifecycle decision report",
483
+ "",
484
+ `Generated: ${report.generatedAt}`,
485
+ "",
486
+ `Coverage ready: **${report.coverage.ready ? "yes" : "no"}**`,
487
+ `Telemetry input ready: **${report.ingestion.ready ? "yes" : "no"}**`,
488
+ `Decisions: ${report.summary.remove} remove, ${report.summary.retain} retain, ${report.summary["insufficient-data"]} insufficient-data.`,
489
+ "",
490
+ ];
491
+ if (report.coverage.blockers.length > 0) {
492
+ lines.push(
493
+ "Coverage blockers: " +
494
+ report.coverage.blockers.map((item) => `\`${item}\``).join(", "),
495
+ "",
496
+ );
497
+ }
498
+ if (report.ingestion.violations.length > 0) {
499
+ lines.push(
500
+ "Input violations: " +
501
+ report.ingestion.violations.map((item) => `\`${item}\``).join(", "),
502
+ "",
503
+ );
504
+ }
505
+ lines.push(
506
+ "| Legacy entry | Replacement | Legacy | Replacement | Legacy share | Decision | Reasons |",
507
+ "| --- | --- | ---: | ---: | ---: | --- | --- |",
508
+ );
509
+ for (const item of report.decisions) {
510
+ lines.push(
511
+ `| \`${item.command}\` | \`${item.replacement}\` | ${item.legacy.invocations} | ${item.replacementRoute.invocations} | ${item.legacyShare === null ? "n/a" : `${(item.legacyShare * 100).toFixed(2)}%`} | **${item.decision}** | ${item.reasons.join(", ")} |`,
512
+ );
513
+ }
514
+ lines.push("");
515
+ return lines.join("\n");
516
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Environment policy shared by MCP stdio materialization and runtime launch.
3
+ * These variables can cause a language runtime or native loader to execute
4
+ * bytes that are outside the approved executable/package identity.
5
+ */
6
+
7
+ const CODE_INJECTION_ENV_KEYS = new Set([
8
+ "CLASSPATH",
9
+ "DOTNET_ADDITIONAL_DEPS",
10
+ "DOTNET_ROOT",
11
+ "JAVA_TOOL_OPTIONS",
12
+ "LD_AUDIT",
13
+ "LD_LIBRARY_PATH",
14
+ "LD_PRELOAD",
15
+ "NODE_OPTIONS",
16
+ "NODE_PATH",
17
+ "NPM_CONFIG_NODE_OPTIONS",
18
+ "PERL5LIB",
19
+ "PERL5OPT",
20
+ "PYTHONHOME",
21
+ "PYTHONPATH",
22
+ "RUBYLIB",
23
+ "RUBYOPT",
24
+ "_JAVA_OPTIONS",
25
+ ]);
26
+
27
+ export function isMcpStdioCodeInjectionEnvironmentKey(key) {
28
+ const normalized = String(key || "").toUpperCase();
29
+ return (
30
+ CODE_INJECTION_ENV_KEYS.has(normalized) ||
31
+ normalized.startsWith("DYLD_") ||
32
+ normalized.startsWith("COMPLUS_") ||
33
+ normalized.startsWith("CORECLR_")
34
+ );
35
+ }
36
+
37
+ export function sanitizeMcpStdioHostEnvironment(env) {
38
+ const safe = {};
39
+ for (const [key, value] of Object.entries(env || {})) {
40
+ if (
41
+ !isMcpStdioCodeInjectionEnvironmentKey(key) &&
42
+ typeof value === "string"
43
+ ) {
44
+ safe[key] = value;
45
+ }
46
+ }
47
+ return safe;
48
+ }