chainlesschain 0.162.197 → 0.162.200
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.
- package/bin/chainlesschain.js +14 -6
- package/package.json +4 -1
- package/scripts/command-lifecycle-report.mjs +94 -0
- package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-DcQ0bWKy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-GecwfFPt.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-CD6iSt9v.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-CDEtuEYf.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-DS3jAjeW.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-CcSJA048.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DRo9Morb.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Vw5MrWft.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-DNHIu823.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-DvAsO8-b.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-9aDuObay.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-CKCa7tvn.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-CIFvZdaT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C79yz7bK.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-DVvZskLJ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-oaew61hV.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-DqA7wmRx.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-B-qGadxa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-CUlCl4sS.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-CNOlr9DU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-DJqFCT_3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-CznGpphf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-_cJw218E.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DOiG3i_1.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-BzbMcFB9.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer-VbBrYttP.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-CLG8E6ED.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-LGJQfk_q.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-DlQKx9lF.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-DU8vEouV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-FZIQOdln.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-C_xd-zZI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-q-YktphS.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Cq9OhDin.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-B03_R98T.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DZrk-qmF.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-BidCKW28.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-r-iaMVM7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-CgTUFvff.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B7NvzfAV.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-80CWNqJI.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-0H6xdiY3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B8sxCV_h.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CW9JBBhQ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-bdSQV7oZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-DQad42nW.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-CueexxTR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-fqxflhR8.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-KFwwnIMC.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-ClnD9buY.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-CZEz6sm3.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-B6NzpmOI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-DYyuwPCs.js} +1 -1
- package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-BzuOBbqB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-CmNO9qSj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-VJNj3_NF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-CrbdbSBF.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-DTyMd45j.js} +1 -1
- package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-DHrQ-Icz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-DqWxY9c5.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-ctF1Ks3J.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-BrQz8uo5.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-D4scVFar.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-oUScaOjv.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-CL-y0eLt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-DQExhwXj.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-iNp_I7kN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-CTDlMo0A.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-4kb8l3sc.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BXcL9oXW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-DLE8eS0D.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-DGpUZPPK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-C1pWXGPC.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-BYfbfqhZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-K9YfLOCw.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-Ctkq77Hy.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-C6_CSe9J.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-Be3rpOWs.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-D0UIplxk.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-CF9bM9I3.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-D0H1XVPY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-Cgzzbe0o.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-BwNxEVS0.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-D60Z4Hhs.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-MFk58XB0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-CRj2SvGO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index--s45_1cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index--tquQ2ZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-1T1rhokn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-B-M82_rx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-BE_el1Zs.js} +1 -1
- package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BhRkR7IO.js} +1 -1
- package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Bo0y96-K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-CJgu5JUK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-CLWwdebO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-CNAK5QG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-CQjJjPRD.js} +1 -1
- package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-CTDbAfae.js} +1 -1
- package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-CVI_9sRK.js} +1 -1
- package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-CY14oMQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-CbiTJkZf.js} +1 -1
- package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
- package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-CqWpxMqx.js} +1 -1
- package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-CvB8lYUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-D51XwtCY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-D6HvK_1O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-D9jVIwLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-DA4tE98u.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-DBwOtXw0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-DKdNzTIb.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DRySdmvN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-DWzyTev7.js} +1 -1
- package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
- package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-DYjs7jAP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLc19alH.js → index-DbROzMBp.js} +1 -1
- package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-DhFtk5PR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-Di2AbMLg.js} +1 -1
- package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-DvmocQsM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-Dw-o0zEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DysPoP38.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-LX9pJxm_.js} +1 -1
- package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-OI_fXWx0.js} +3 -3
- package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-eDTOX8Xj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-gWKDsTzF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpumS98o.js → index-q_GDUVAA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-C61kZqEd.js} +1 -1
- package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-DZnT5U1L.js} +1 -1
- package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-L8wzwbel.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-DLdYSejc.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-D53cbS59.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-Bbc5HPtu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-BkvmO860.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-u2y1ryS1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-BBqj7svU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-GN0mqu2d.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-BvwPKoBT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-DXAxl2SV.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-DihlR2dj.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-D7BOX2gi.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-CVbO-nL7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +4 -4
- package/src/commands/agent.js +3 -3
- package/src/commands/background-session.js +145 -0
- package/src/commands/mcp.js +244 -7
- package/src/commands/serve.js +1 -1
- package/src/commands/session-show.js +129 -0
- package/src/commands/session.js +97 -145
- package/src/commands/skill.js +87 -50
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/session-protocol.js +14 -4
- package/src/gateways/ws/ws-agent-handler.js +39 -1
- package/src/harness/jsonl-session-store.js +1547 -127
- package/src/harness/mcp-client.js +2690 -409
- package/src/harness/session-index.js +80 -80
- package/src/harness/session-list-index.js +210 -7
- package/src/lazy-dispatch.js +76 -8
- package/src/lib/abort-utils.js +68 -0
- package/src/lib/agent-core.js +1 -59
- package/src/lib/background-interaction-journal.js +2 -2
- package/src/lib/chat-core.js +24 -6
- package/src/lib/command-lifecycle-report.js +516 -0
- package/src/lib/cowork-mcp-tools.js +47 -2
- package/src/lib/cowork-task-runner.js +11 -3
- package/src/lib/doctor-checkup.js +9 -7
- package/src/lib/learning/skill-improver.js +21 -2
- package/src/lib/mcp-call-ledger-store.js +116 -3
- package/src/lib/mcp-call-ledger.js +59 -14
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-stdio-environment.js +48 -0
- package/src/lib/mcp-stdio-executable-identity.js +1133 -0
- package/src/lib/mcp-stdio-execution-authority.js +363 -0
- package/src/lib/mcp-stdio-package-materialization.js +1424 -0
- package/src/lib/mcp-tool-metadata.js +436 -0
- package/src/lib/mcp-tool-result.js +367 -0
- package/src/lib/observability/index.js +71 -0
- package/src/lib/packer/native-update-state.js +979 -1
- package/src/lib/packer/pack-update-applier.js +1050 -125
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/paths.js +53 -0
- package/src/lib/pr-link-ledger.js +8 -27
- package/src/lib/pr-link-store.js +26 -0
- package/src/lib/process-execution-broker/index.js +192 -35
- package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
- package/src/lib/process-tree-termination.js +253 -0
- package/src/lib/recent-session.js +17 -17
- package/src/lib/secure-file-identity.js +47 -0
- package/src/lib/secure-fs.js +21 -2
- package/src/lib/session-anti-rollback-anchor.js +766 -0
- package/src/lib/session-host-lease.js +492 -0
- package/src/lib/session-host-snapshot.js +9 -5
- package/src/lib/session-persistence-failure.js +109 -0
- package/src/lib/session-picker.js +26 -3
- package/src/lib/session-projection.js +5 -1
- package/src/lib/session-search.js +25 -11
- package/src/lib/session-tail.js +31 -1
- package/src/lib/side-effect-ledger-store.js +2 -2
- package/src/lib/skill-budget.js +222 -0
- package/src/lib/skill-execution-authority.js +385 -0
- package/src/lib/skill-execution-identity.js +39 -2
- package/src/lib/skill-loader.js +322 -86
- package/src/lib/skill-mcp.js +43 -1
- package/src/lib/turn-binding-store.js +2 -2
- package/src/repl/agent-repl.js +483 -77
- package/src/repl/bg-dashboard.js +81 -28
- package/src/repl/chat-repl.js +77 -12
- package/src/runtime/agent-core.js +428 -113
- package/src/runtime/agent-runtime.js +26 -3
- package/src/runtime/cleanup-deadline.js +143 -0
- package/src/runtime/headless-runner.js +494 -149
- package/src/runtime/headless-stream.js +504 -75
- package/src/runtime/mcp-config.js +157 -10
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/output-backpressure.js +419 -0
- package/src/runtime/pipe-safety.js +56 -21
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
- package/src/assets/web-panel/assets/Providers-uO-10aP1.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
- package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
- package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
- package/src/lib/skill-process-broker.js +0 -85
|
@@ -21,8 +21,8 @@ import { existsSync, readdirSync, statSync } from "node:fs";
|
|
|
21
21
|
import { join, basename } from "node:path";
|
|
22
22
|
import { createRequire } from "node:module";
|
|
23
23
|
import { getHomeDir } from "../lib/paths.js";
|
|
24
|
-
import { iterateFileLinesSync } from "../lib/file-lines.js";
|
|
25
24
|
import { ensurePrivateDirectory, ensurePrivateFile } from "../lib/secure-fs.js";
|
|
25
|
+
import { readVerifiedProjection } from "./jsonl-session-store.js";
|
|
26
26
|
|
|
27
27
|
const requireCjs = createRequire(import.meta.url);
|
|
28
28
|
|
|
@@ -98,84 +98,74 @@ function toIsoSafe(value) {
|
|
|
98
98
|
return Number.isNaN(date.getTime()) ? "" : date.toISOString();
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
? ""
|
|
132
|
-
: JSON.stringify(content);
|
|
133
|
-
if (text) {
|
|
134
|
-
const bounded = text.slice(0, CONTENT_CAP - used);
|
|
135
|
-
parts.push(bounded);
|
|
136
|
-
used += bounded.length;
|
|
101
|
+
function summarizeVerifiedSession(id) {
|
|
102
|
+
return readVerifiedProjection(id, () => {
|
|
103
|
+
let startEvent = null;
|
|
104
|
+
let lastEvent = null;
|
|
105
|
+
let renamedTitle = null;
|
|
106
|
+
let messageCount = 0;
|
|
107
|
+
let eventCount = 0;
|
|
108
|
+
let chainHash = "";
|
|
109
|
+
const parts = [];
|
|
110
|
+
let used = 0;
|
|
111
|
+
const acceptContent = (content) => {
|
|
112
|
+
if (used >= CONTENT_CAP) return;
|
|
113
|
+
const text =
|
|
114
|
+
typeof content === "string"
|
|
115
|
+
? content
|
|
116
|
+
: content == null
|
|
117
|
+
? ""
|
|
118
|
+
: JSON.stringify(content);
|
|
119
|
+
if (!text) return;
|
|
120
|
+
const bounded = text.slice(0, CONTENT_CAP - used);
|
|
121
|
+
parts.push(bounded);
|
|
122
|
+
used += bounded.length;
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
accept(event) {
|
|
126
|
+
eventCount += 1;
|
|
127
|
+
lastEvent = event;
|
|
128
|
+
if (!startEvent && event.type === "session_start") startEvent = event;
|
|
129
|
+
if (event.type === "session_rename" && event.data?.title) {
|
|
130
|
+
renamedTitle = String(event.data.title);
|
|
137
131
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
? ""
|
|
155
|
-
: JSON.stringify(content);
|
|
156
|
-
if (text) {
|
|
157
|
-
const bounded = text.slice(0, CONTENT_CAP - used);
|
|
158
|
-
parts.push(bounded);
|
|
159
|
-
used += bounded.length;
|
|
132
|
+
if (
|
|
133
|
+
event.type === "user_message" ||
|
|
134
|
+
event.type === "assistant_message"
|
|
135
|
+
) {
|
|
136
|
+
messageCount += 1;
|
|
137
|
+
acceptContent(event.data?.content);
|
|
138
|
+
} else if (
|
|
139
|
+
event.type === "ws_turn" &&
|
|
140
|
+
event.data?.schemaVersion === 1 &&
|
|
141
|
+
event.data?.outcome === "completed" &&
|
|
142
|
+
event.data?.user?.role === "user" &&
|
|
143
|
+
event.data?.assistant?.role === "assistant"
|
|
144
|
+
) {
|
|
145
|
+
messageCount += 2;
|
|
146
|
+
acceptContent(event.data.user.content);
|
|
147
|
+
acceptContent(event.data.assistant.content);
|
|
160
148
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
149
|
+
if (typeof event.hash === "string") chainHash = event.hash;
|
|
150
|
+
},
|
|
151
|
+
finish() {
|
|
152
|
+
if (!lastEvent) return null;
|
|
153
|
+
return {
|
|
154
|
+
id,
|
|
155
|
+
title: renamedTitle || startEvent?.data?.title || "Untitled",
|
|
156
|
+
provider: startEvent?.data?.provider || "",
|
|
157
|
+
model: startEvent?.data?.model || "",
|
|
158
|
+
message_count: messageCount,
|
|
159
|
+
event_count: eventCount,
|
|
160
|
+
created_at: toIsoSafe(startEvent?.timestamp),
|
|
161
|
+
updated_at: toIsoSafe(lastEvent?.timestamp),
|
|
162
|
+
last_ts: lastEvent?.timestamp || 0,
|
|
163
|
+
content: parts.join("\n").slice(0, CONTENT_CAP),
|
|
164
|
+
chain_hash: chainHash,
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
});
|
|
179
169
|
}
|
|
180
170
|
|
|
181
171
|
const UPSERT_SESSION = `
|
|
@@ -195,7 +185,7 @@ ON CONFLICT(id) DO UPDATE SET
|
|
|
195
185
|
export function indexOneSession(db, id, { mtimeMs = 0, sizeBytes = 0 } = {}) {
|
|
196
186
|
const filePath = join(sessionsDir(), `${id}.jsonl`);
|
|
197
187
|
if (!existsSync(filePath)) return false;
|
|
198
|
-
const s =
|
|
188
|
+
const s = summarizeVerifiedSession(id);
|
|
199
189
|
if (!s) return false;
|
|
200
190
|
db.prepare(UPSERT_SESSION).run({
|
|
201
191
|
id: s.id,
|
|
@@ -228,6 +218,7 @@ export function syncIndex(db, { force = false } = {}) {
|
|
|
228
218
|
let scanned = 0;
|
|
229
219
|
let updated = 0;
|
|
230
220
|
let removed = 0;
|
|
221
|
+
let rejected = 0;
|
|
231
222
|
const seen = new Set();
|
|
232
223
|
|
|
233
224
|
if (existsSync(dir)) {
|
|
@@ -251,7 +242,16 @@ export function syncIndex(db, { force = false } = {}) {
|
|
|
251
242
|
) {
|
|
252
243
|
continue; // unchanged
|
|
253
244
|
}
|
|
254
|
-
|
|
245
|
+
try {
|
|
246
|
+
if (indexOneSession(db, id, { mtimeMs, sizeBytes: size })) updated++;
|
|
247
|
+
} catch {
|
|
248
|
+
// The index is disposable. A damaged canonical source invalidates any
|
|
249
|
+
// older cached content immediately and is reported without exposing
|
|
250
|
+
// transcript text or local paths.
|
|
251
|
+
db.prepare("DELETE FROM sessions WHERE id=?").run(id);
|
|
252
|
+
db.prepare("DELETE FROM session_content WHERE id=?").run(id);
|
|
253
|
+
rejected++;
|
|
254
|
+
}
|
|
255
255
|
}
|
|
256
256
|
});
|
|
257
257
|
const entries = [];
|
|
@@ -278,7 +278,7 @@ export function syncIndex(db, { force = false } = {}) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
const total = db.prepare("SELECT COUNT(*) c FROM sessions").get().c;
|
|
281
|
-
return { scanned, updated, removed, total };
|
|
281
|
+
return { scanned, updated, removed, rejected, total };
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
const LIST_COLUMNS =
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
appendFileSync,
|
|
12
12
|
existsSync,
|
|
13
13
|
readFileSync,
|
|
14
|
+
rmSync,
|
|
14
15
|
writeFileSync,
|
|
15
16
|
} from "node:fs";
|
|
16
17
|
import { join } from "node:path";
|
|
@@ -19,6 +20,12 @@ import { ensurePrivateFile } from "../lib/secure-fs.js";
|
|
|
19
20
|
|
|
20
21
|
export const SESSION_INDEX_SCHEMA = 2;
|
|
21
22
|
export const SESSION_INDEX_FILE = ".sessions-index-v2.ndjson";
|
|
23
|
+
export const SESSION_TOMBSTONE_MARKER_SUFFIX = ".tombstone";
|
|
24
|
+
export const SESSION_TOMBSTONE_MARKER_SCHEMA =
|
|
25
|
+
"chainlesschain.session-tombstone/v1";
|
|
26
|
+
export const SESSION_GENERATION_AUTHORITY_FIELD = "_sessionGeneration";
|
|
27
|
+
export const SESSION_GENERATION_AUTHORITY_SCHEMA =
|
|
28
|
+
"chainlesschain.session-generation-authority/v1";
|
|
22
29
|
|
|
23
30
|
// Used only by an opted-in child in the independent session-scale crash gate.
|
|
24
31
|
// Keeping the injection immediately around the production sidecar/journal
|
|
@@ -41,6 +48,10 @@ export function sessionIndexPath(dir) {
|
|
|
41
48
|
return join(dir, SESSION_INDEX_FILE);
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
export function sessionTombstoneMarkerPath(dir, sessionId) {
|
|
52
|
+
return join(dir, `${sessionId}${SESSION_TOMBSTONE_MARKER_SUFFIX}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
export function emptySessionMeta(sessionId) {
|
|
45
56
|
return {
|
|
46
57
|
schema: SESSION_INDEX_SCHEMA,
|
|
@@ -53,10 +64,67 @@ export function emptySessionMeta(sessionId) {
|
|
|
53
64
|
created_at_ms: 0,
|
|
54
65
|
updated_at_ms: 0,
|
|
55
66
|
last_hash: null,
|
|
67
|
+
transcript: null,
|
|
68
|
+
generation: null,
|
|
69
|
+
deleted_at_ms: null,
|
|
56
70
|
deleted: false,
|
|
57
71
|
};
|
|
58
72
|
}
|
|
59
73
|
|
|
74
|
+
export function normalizeSessionGenerationAuthority(value) {
|
|
75
|
+
if (
|
|
76
|
+
!value ||
|
|
77
|
+
typeof value !== "object" ||
|
|
78
|
+
Array.isArray(value) ||
|
|
79
|
+
value.schema !== SESSION_GENERATION_AUTHORITY_SCHEMA ||
|
|
80
|
+
typeof value.sessionId !== "string" ||
|
|
81
|
+
value.sessionId.length === 0 ||
|
|
82
|
+
typeof value.generationId !== "string" ||
|
|
83
|
+
!/^generation-[0-9a-f-]{32,36}$/.test(value.generationId) ||
|
|
84
|
+
!Number.isSafeInteger(value.ordinal) ||
|
|
85
|
+
value.ordinal < 1
|
|
86
|
+
) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
let predecessor = null;
|
|
90
|
+
if (value.predecessor !== null) {
|
|
91
|
+
const previous = value.predecessor;
|
|
92
|
+
if (
|
|
93
|
+
!previous ||
|
|
94
|
+
typeof previous !== "object" ||
|
|
95
|
+
Array.isArray(previous) ||
|
|
96
|
+
!["tombstone", "legacy-tombstone"].includes(previous.kind) ||
|
|
97
|
+
(previous.generationId !== null &&
|
|
98
|
+
(typeof previous.generationId !== "string" ||
|
|
99
|
+
!/^generation-[0-9a-f-]{32,36}$/.test(previous.generationId))) ||
|
|
100
|
+
(previous.headHash !== null &&
|
|
101
|
+
(typeof previous.headHash !== "string" ||
|
|
102
|
+
!/^[0-9a-f]{64}$/.test(previous.headHash))) ||
|
|
103
|
+
!Number.isSafeInteger(previous.eventCount) ||
|
|
104
|
+
previous.eventCount < 0 ||
|
|
105
|
+
(previous.tombstonedAtMs !== null &&
|
|
106
|
+
(!Number.isSafeInteger(previous.tombstonedAtMs) ||
|
|
107
|
+
previous.tombstonedAtMs < 0))
|
|
108
|
+
) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
predecessor = {
|
|
112
|
+
kind: previous.kind,
|
|
113
|
+
generationId: previous.generationId,
|
|
114
|
+
headHash: previous.headHash,
|
|
115
|
+
eventCount: previous.eventCount,
|
|
116
|
+
tombstonedAtMs: previous.tombstonedAtMs,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
schema: SESSION_GENERATION_AUTHORITY_SCHEMA,
|
|
121
|
+
sessionId: value.sessionId,
|
|
122
|
+
generationId: value.generationId,
|
|
123
|
+
ordinal: value.ordinal,
|
|
124
|
+
predecessor,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
60
128
|
export function readSessionMeta(dir, sessionId) {
|
|
61
129
|
const filePath = sessionMetaPath(dir, sessionId);
|
|
62
130
|
if (!existsSync(filePath)) return null;
|
|
@@ -102,12 +170,48 @@ export function applyEventToSessionMeta(meta, event, lastHash) {
|
|
|
102
170
|
) {
|
|
103
171
|
next.message_count = Math.max(0, Number(next.message_count) || 0) + 2;
|
|
104
172
|
}
|
|
173
|
+
const generation = normalizeSessionGenerationAuthority(
|
|
174
|
+
event?.data?.[SESSION_GENERATION_AUTHORITY_FIELD],
|
|
175
|
+
);
|
|
176
|
+
if (generation?.sessionId === next.id) next.generation = generation;
|
|
177
|
+
next.deleted_at_ms = null;
|
|
105
178
|
next.last_hash = typeof lastHash === "string" ? lastHash : null;
|
|
106
179
|
return next;
|
|
107
180
|
}
|
|
108
181
|
|
|
109
182
|
function writeMetaSnapshot(dir, meta) {
|
|
110
183
|
const filePath = sessionMetaPath(dir, meta.id);
|
|
184
|
+
const tombstoneMarker = sessionTombstoneMarkerPath(dir, meta.id);
|
|
185
|
+
// The marker is the durable per-session namespace witness that makes a
|
|
186
|
+
// tombstoned identity discoverable without reading every live sidecar on
|
|
187
|
+
// `--continue`; the meta snapshot remains the content/status authority.
|
|
188
|
+
// Publish the marker before the tombstone snapshot, and fail the delete if
|
|
189
|
+
// that publication fails. Remove it only after a live generation snapshot
|
|
190
|
+
// commits, so crashes can cause an extra candidate read but never hide a
|
|
191
|
+
// successfully committed tombstone.
|
|
192
|
+
if (meta.deleted === true) {
|
|
193
|
+
const generation = normalizeSessionGenerationAuthority(meta.generation);
|
|
194
|
+
const marker = {
|
|
195
|
+
schema: SESSION_TOMBSTONE_MARKER_SCHEMA,
|
|
196
|
+
id: meta.id,
|
|
197
|
+
generation: generation?.sessionId === meta.id ? generation : null,
|
|
198
|
+
last_hash:
|
|
199
|
+
typeof meta.last_hash === "string" &&
|
|
200
|
+
/^[0-9a-f]{64}$/.test(meta.last_hash)
|
|
201
|
+
? meta.last_hash
|
|
202
|
+
: null,
|
|
203
|
+
event_count: Math.max(0, Number(meta.event_count) || 0),
|
|
204
|
+
deleted_at_ms: Math.max(
|
|
205
|
+
0,
|
|
206
|
+
Number(meta.deleted_at_ms || meta.updated_at_ms) || 0,
|
|
207
|
+
),
|
|
208
|
+
};
|
|
209
|
+
writeFileSync(tombstoneMarker, `${JSON.stringify(marker)}\n`, {
|
|
210
|
+
encoding: "utf8",
|
|
211
|
+
mode: 0o600,
|
|
212
|
+
});
|
|
213
|
+
ensurePrivateFile(tombstoneMarker);
|
|
214
|
+
}
|
|
111
215
|
// The owning transcript lock serializes this derived snapshot. It need not
|
|
112
216
|
// use a second temp+rename protocol: interruption can only corrupt a cache,
|
|
113
217
|
// which readSessionMeta rejects and rebuildSessionMeta regenerates.
|
|
@@ -116,6 +220,40 @@ function writeMetaSnapshot(dir, meta) {
|
|
|
116
220
|
mode: 0o600,
|
|
117
221
|
});
|
|
118
222
|
ensurePrivateFile(filePath);
|
|
223
|
+
if (meta.deleted !== true) rmSync(tombstoneMarker, { force: true });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Read the durable namespace marker. Legacy empty/invalid markers still count
|
|
228
|
+
* as deletion evidence, but deliberately expose no predecessor authority.
|
|
229
|
+
*/
|
|
230
|
+
export function readSessionTombstoneMarker(dir, sessionId) {
|
|
231
|
+
const filePath = sessionTombstoneMarkerPath(dir, sessionId);
|
|
232
|
+
if (!existsSync(filePath)) return null;
|
|
233
|
+
try {
|
|
234
|
+
const value = JSON.parse(readFileSync(filePath, "utf8"));
|
|
235
|
+
if (
|
|
236
|
+
value?.schema !== SESSION_TOMBSTONE_MARKER_SCHEMA ||
|
|
237
|
+
value?.id !== sessionId
|
|
238
|
+
) {
|
|
239
|
+
return { id: sessionId, legacy: true };
|
|
240
|
+
}
|
|
241
|
+
const generation = normalizeSessionGenerationAuthority(value.generation);
|
|
242
|
+
return {
|
|
243
|
+
schema: SESSION_TOMBSTONE_MARKER_SCHEMA,
|
|
244
|
+
id: sessionId,
|
|
245
|
+
generation: generation?.sessionId === sessionId ? generation : null,
|
|
246
|
+
last_hash:
|
|
247
|
+
typeof value.last_hash === "string" &&
|
|
248
|
+
/^[0-9a-f]{64}$/.test(value.last_hash)
|
|
249
|
+
? value.last_hash
|
|
250
|
+
: null,
|
|
251
|
+
event_count: Math.max(0, Number(value.event_count) || 0),
|
|
252
|
+
deleted_at_ms: Math.max(0, Number(value.deleted_at_ms) || 0),
|
|
253
|
+
};
|
|
254
|
+
} catch {
|
|
255
|
+
return { id: sessionId, legacy: true };
|
|
256
|
+
}
|
|
119
257
|
}
|
|
120
258
|
|
|
121
259
|
function appendActivity(dir, meta) {
|
|
@@ -135,11 +273,46 @@ function appendActivity(dir, meta) {
|
|
|
135
273
|
}
|
|
136
274
|
|
|
137
275
|
/** Called while the owning transcript lock is held. */
|
|
138
|
-
export function recordSessionEvent(
|
|
139
|
-
|
|
140
|
-
|
|
276
|
+
export function recordSessionEvent(
|
|
277
|
+
dir,
|
|
278
|
+
sessionId,
|
|
279
|
+
event,
|
|
280
|
+
lastHash,
|
|
281
|
+
{ resetGeneration = false, transcriptState = null } = {},
|
|
282
|
+
) {
|
|
283
|
+
const existing = readSessionMeta(dir, sessionId);
|
|
284
|
+
// Only the transcript writer may authorize a new generation after checking
|
|
285
|
+
// the tombstone and physical file under its lock. The index cannot infer
|
|
286
|
+
// that authority from an attacker-controlled genesis-shaped event alone.
|
|
287
|
+
const current = resetGeneration
|
|
288
|
+
? emptySessionMeta(sessionId)
|
|
289
|
+
: existing || emptySessionMeta(sessionId);
|
|
141
290
|
current.id = sessionId;
|
|
142
291
|
const next = applyEventToSessionMeta(current, event, lastHash);
|
|
292
|
+
next.transcript = transcriptState
|
|
293
|
+
? {
|
|
294
|
+
dev: String(transcriptState.dev),
|
|
295
|
+
ino: String(transcriptState.ino),
|
|
296
|
+
size: Number(transcriptState.size),
|
|
297
|
+
mtimeMs: Number(transcriptState.mtimeMs),
|
|
298
|
+
ctimeMs: Number(transcriptState.ctimeMs),
|
|
299
|
+
...(transcriptState.devExact != null
|
|
300
|
+
? { devExact: String(transcriptState.devExact) }
|
|
301
|
+
: {}),
|
|
302
|
+
...(transcriptState.inoExact != null
|
|
303
|
+
? { inoExact: String(transcriptState.inoExact) }
|
|
304
|
+
: {}),
|
|
305
|
+
...(transcriptState.sizeExact != null
|
|
306
|
+
? { sizeExact: String(transcriptState.sizeExact) }
|
|
307
|
+
: {}),
|
|
308
|
+
...(transcriptState.mtimeNs != null
|
|
309
|
+
? { mtimeNs: String(transcriptState.mtimeNs) }
|
|
310
|
+
: {}),
|
|
311
|
+
...(transcriptState.ctimeNs != null
|
|
312
|
+
? { ctimeNs: String(transcriptState.ctimeNs) }
|
|
313
|
+
: {}),
|
|
314
|
+
}
|
|
315
|
+
: null;
|
|
143
316
|
writeMetaSnapshot(dir, next);
|
|
144
317
|
runSessionScaleFaultHook("afterMetaSnapshot", {
|
|
145
318
|
dir,
|
|
@@ -171,7 +344,9 @@ export function recordSessionDeleted(dir, sessionId, timestamp = Date.now()) {
|
|
|
171
344
|
const tombstone = {
|
|
172
345
|
...current,
|
|
173
346
|
updated_at_ms: timestamp,
|
|
347
|
+
deleted_at_ms: timestamp,
|
|
174
348
|
deleted: true,
|
|
349
|
+
transcript: null,
|
|
175
350
|
};
|
|
176
351
|
writeMetaSnapshot(dir, tombstone);
|
|
177
352
|
appendActivity(dir, tombstone);
|
|
@@ -224,13 +399,29 @@ export function publicSessionMeta(meta) {
|
|
|
224
399
|
*/
|
|
225
400
|
export function listIndexedSessions(
|
|
226
401
|
dir,
|
|
227
|
-
{
|
|
402
|
+
{
|
|
403
|
+
limit = 20,
|
|
404
|
+
hasSession = () => true,
|
|
405
|
+
includeDeleted = () => false,
|
|
406
|
+
onScanComplete = null,
|
|
407
|
+
} = {},
|
|
228
408
|
) {
|
|
229
409
|
const filePath = sessionIndexPath(dir);
|
|
230
|
-
if (!existsSync(filePath))
|
|
410
|
+
if (!existsSync(filePath)) {
|
|
411
|
+
if (typeof onScanComplete === "function") {
|
|
412
|
+
onScanComplete({
|
|
413
|
+
exhausted: true,
|
|
414
|
+
seenSessionIds: new Set(),
|
|
415
|
+
latestBySessionId: new Map(),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return [];
|
|
419
|
+
}
|
|
231
420
|
const wanted = Math.max(0, Number(limit) || 0);
|
|
232
421
|
const seen = new Set();
|
|
422
|
+
const latestBySessionId = new Map();
|
|
233
423
|
const result = [];
|
|
424
|
+
let exhausted = true;
|
|
234
425
|
for (const { line } of iterateFileLinesReverseSync(filePath)) {
|
|
235
426
|
let meta;
|
|
236
427
|
try {
|
|
@@ -246,9 +437,21 @@ export function listIndexedSessions(
|
|
|
246
437
|
continue;
|
|
247
438
|
}
|
|
248
439
|
seen.add(meta.id);
|
|
249
|
-
|
|
440
|
+
latestBySessionId.set(meta.id, meta);
|
|
441
|
+
if (
|
|
442
|
+
(meta.deleted && !includeDeleted(meta.id, meta)) ||
|
|
443
|
+
!hasSession(meta.id)
|
|
444
|
+
) {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
250
447
|
result.push(publicSessionMeta(meta));
|
|
251
|
-
if (wanted > 0 && result.length >= wanted)
|
|
448
|
+
if (wanted > 0 && result.length >= wanted) {
|
|
449
|
+
exhausted = false;
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (typeof onScanComplete === "function") {
|
|
454
|
+
onScanComplete({ exhausted, seenSessionIds: seen, latestBySessionId });
|
|
252
455
|
}
|
|
253
456
|
return result;
|
|
254
457
|
}
|
package/src/lazy-dispatch.js
CHANGED
|
@@ -337,6 +337,43 @@ export function resolveCommandLifecycleInvocation(
|
|
|
337
337
|
};
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Build the bounded, content-free lifecycle usage dimensions for a migrated
|
|
342
|
+
* command. The original argv is inspected only to distinguish the retained
|
|
343
|
+
* top-level spelling from its virtual namespace replacement; arguments and
|
|
344
|
+
* nested command names are never copied into telemetry.
|
|
345
|
+
*/
|
|
346
|
+
export function resolveCommandLifecycleTelemetry(
|
|
347
|
+
argv,
|
|
348
|
+
manifestData = manifest,
|
|
349
|
+
) {
|
|
350
|
+
const invocation = resolveCommandLifecycleInvocation(argv, manifestData);
|
|
351
|
+
let entry = null;
|
|
352
|
+
let route = null;
|
|
353
|
+
if (invocation.kind === "namespace-rewrite") {
|
|
354
|
+
entry = invocation.entry;
|
|
355
|
+
route = "replacement";
|
|
356
|
+
} else if (invocation.kind === "passthrough") {
|
|
357
|
+
const commandName = resolveCommandToken(argv);
|
|
358
|
+
entry = findManifestEntry(commandName, manifestData);
|
|
359
|
+
route = "legacy";
|
|
360
|
+
}
|
|
361
|
+
if (
|
|
362
|
+
entry?.lifecycle?.state !== "deprecated" ||
|
|
363
|
+
typeof entry.name !== "string" ||
|
|
364
|
+
!entry.replacement
|
|
365
|
+
) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
return Object.freeze({
|
|
369
|
+
command: entry.name,
|
|
370
|
+
route,
|
|
371
|
+
version: packageMetadata.version,
|
|
372
|
+
deprecatedSince: entry.lifecycle.deprecatedSince,
|
|
373
|
+
removalNotBefore: entry.lifecycle.removalNotBefore,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
340
377
|
export function formatCommandDeprecationWarning(entry, invokedName) {
|
|
341
378
|
const lifecycle = entry?.lifecycle;
|
|
342
379
|
if (lifecycle?.state !== "deprecated" || !entry.replacement) return null;
|
|
@@ -691,7 +728,7 @@ export async function dispatchCli(
|
|
|
691
728
|
{ manifestData = manifest, ...dispatchOptions } = {},
|
|
692
729
|
) {
|
|
693
730
|
const commandName = resolveCommandToken(argv);
|
|
694
|
-
|
|
731
|
+
let entry = findManifestEntry(commandName, manifestData);
|
|
695
732
|
if (!entry) {
|
|
696
733
|
const program = await (
|
|
697
734
|
dispatchOptions.loadFullProgram || defaultLoadFullProgram
|
|
@@ -699,20 +736,35 @@ export async function dispatchCli(
|
|
|
699
736
|
await program.parseAsync(argv);
|
|
700
737
|
return;
|
|
701
738
|
}
|
|
739
|
+
const commandLocation = findCommandTokenLocation(argv);
|
|
740
|
+
if (entry.name === "session" && argv[commandLocation?.index + 1] === "show") {
|
|
741
|
+
entry = {
|
|
742
|
+
...entry,
|
|
743
|
+
module: "./commands/session-show.js",
|
|
744
|
+
register: "registerSessionShowCommand",
|
|
745
|
+
};
|
|
746
|
+
}
|
|
702
747
|
await dispatchManifestEntry(argv, entry, dispatchOptions);
|
|
703
748
|
}
|
|
704
749
|
|
|
705
750
|
export function isFastReadOnlyInvocation(argv, env = process.env) {
|
|
706
751
|
const args = argv.slice(2);
|
|
707
|
-
|
|
752
|
+
const explicitOtlp =
|
|
753
|
+
args.includes("--otlp-endpoint") ||
|
|
754
|
+
args.some((token) => token.startsWith("--otlp-endpoint=")) ||
|
|
755
|
+
env.OTEL_EXPORTER_OTLP_ENDPOINT ||
|
|
756
|
+
env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||
|
|
757
|
+
env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT;
|
|
758
|
+
const quickStatus =
|
|
708
759
|
resolveCommandToken(argv) === "status" &&
|
|
709
760
|
!args.includes("--deep") &&
|
|
710
|
-
!
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
761
|
+
!explicitOtlp;
|
|
762
|
+
const commandLocation = findCommandTokenLocation(argv);
|
|
763
|
+
const sessionShow =
|
|
764
|
+
commandLocation?.token === "session" &&
|
|
765
|
+
argv[commandLocation.index + 1] === "show" &&
|
|
766
|
+
!explicitOtlp;
|
|
767
|
+
return quickStatus || sessionShow;
|
|
716
768
|
}
|
|
717
769
|
|
|
718
770
|
let processHandlersInstalled = false;
|
|
@@ -767,6 +819,10 @@ async function withInvocationOutputContext(argv, task) {
|
|
|
767
819
|
}
|
|
768
820
|
|
|
769
821
|
export async function runCli(argv, options = {}) {
|
|
822
|
+
const lifecycleTelemetry = resolveCommandLifecycleTelemetry(
|
|
823
|
+
argv,
|
|
824
|
+
options.manifestData || manifest,
|
|
825
|
+
);
|
|
770
826
|
const prepared = await prepareInvocation(argv, options);
|
|
771
827
|
if (prepared.handled) {
|
|
772
828
|
if (prepared.exitCode) {
|
|
@@ -799,12 +855,24 @@ export async function runCli(argv, options = {}) {
|
|
|
799
855
|
}
|
|
800
856
|
|
|
801
857
|
const observability = await initializeCommandRuntime(dispatchArgv);
|
|
858
|
+
const lifecycleStartedAt = performance.now();
|
|
859
|
+
let lifecycleOutcome = "completed";
|
|
802
860
|
try {
|
|
803
861
|
return await withDefaultEventRuntimeLifecycle(
|
|
804
862
|
() => dispatchCli(dispatchArgv, options),
|
|
805
863
|
options,
|
|
806
864
|
);
|
|
865
|
+
} catch (error) {
|
|
866
|
+
lifecycleOutcome = "error";
|
|
867
|
+
throw error;
|
|
807
868
|
} finally {
|
|
869
|
+
if (lifecycleTelemetry) {
|
|
870
|
+
observability.exportCommandLifecycleInvocation({
|
|
871
|
+
...lifecycleTelemetry,
|
|
872
|
+
outcome: lifecycleOutcome,
|
|
873
|
+
durationMs: performance.now() - lifecycleStartedAt,
|
|
874
|
+
});
|
|
875
|
+
}
|
|
808
876
|
await observability.shutdown().catch(() => {});
|
|
809
877
|
}
|
|
810
878
|
});
|