chainlesschain 0.162.198 → 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-CSN-D2xb.js → AIOps-DcQ0bWKy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CBSMlGzv.js → ActionButton-GecwfFPt.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-3yr3Nt2t.js → Analytics-CD6iSt9v.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-1b-o3lMH.js → AppLayout-CDEtuEYf.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Dr8rJi17.js → Artifacts-DS3jAjeW.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-2V689HC2.js → Audit-CcSJA048.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DIxkNrD_.js → BackgroundAgents-DRo9Morb.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Pg6BcwrE.js → Backup-Vw5MrWft.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CLUpqyfH.js → BaseInput-DNHIu823.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-qVS8rD4G.js → Chat-DvAsO8-b.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-ti49X12Q.js → ChatBubbleRenderer-9aDuObay.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Bs9AaEay.js → Checkbox-CKCa7tvn.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Dvc1mq8q.js → Codegen-CIFvZdaT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C4_biO7A.js → Col-C79yz7bK.js} +1 -1
- package/src/assets/web-panel/assets/{Community-al25XQUV.js → Community-DVvZskLJ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-D-ZDB8M1.js → Compact-oaew61hV.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-6lIfDz1W.js → Compliance-DqA7wmRx.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DdI48XMJ.js → Cowork-B-qGadxa.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DF5HZd2g.js → Cron-CUlCl4sS.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DuxeSvt3.js → Crosschain-CNOlr9DU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B9yHkUTd.js → DID-DJqFCT_3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Z5EuI3IM.js → Dashboard-CznGpphf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-vuRfO3dY.js → Dropdown-_cJw218E.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-QFLCc1uL.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BZ7EXkFJ.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DycIEg2s.js → Federation-DOiG3i_1.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Ba0H_7yG.js → FormItemContext-BzbMcFB9.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer--JgSTK-C.js → GenericCardRenderer-VbBrYttP.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DEvTbldE.js → Git-CLG8E6ED.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BJIljy18.js → Governance-LGJQfk_q.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CVyW3G3q.js → Inference-DlQKx9lF.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-v8-borge.js → KnowledgeGraph-DU8vEouV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BCdS7gGo.js → Logs-FZIQOdln.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-AN6tGA2B.js → Marketplace-C_xd-zZI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DGViXASN.js → McpTools-q-YktphS.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-Bpvmx9X4.js → Memory-Cq9OhDin.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CTP-DOTC.js → MobileBridge-B03_R98T.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-C8qfktxn.js → MobileProjects-DZrk-qmF.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-ndYr0M1s.js → Mtc-BidCKW28.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Ci0-YK7W.js → MtcAudit-r-iaMVM7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BehSTFW7.js → Multisig-CgTUFvff.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-B91_YBLv.js → NLProgramming-B7NvzfAV.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BQlJ0-gq.js → Notes-80CWNqJI.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CDgYMjYK.js → NotificationSettings-0H6xdiY3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BJkSlKeH.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B-b3cWCp.js → Organization-B8sxCV_h.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CILUL4nL.js → Overflow-CW9JBBhQ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BTCFBkF0.js → P2P-bdSQV7oZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BAR6AUx5.js → PdhVaultBrowser-DQad42nW.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-RRf6HbWJ.js → Permissions-CueexxTR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BGTMiICa.js → PersonalDataHub-fqxflhR8.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-945qY9YF.js → Pipeline-KFwwnIMC.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DPZwI6lJ.js → Privacy-ClnD9buY.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BPH2NRKc.js → ProjectInit-CZEz6sm3.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BZCRNCvb.js → ProjectSettings-B6NzpmOI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BTI__tBt.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-N6rbqt1r.js → QrScannerModal-BzuOBbqB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DrwjPS7M.js → QuickAsk-CmNO9qSj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cog9Wd99.js → Recommend-VJNj3_NF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DC9pynjM.js → RemoteSession-CrbdbSBF.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D4th4gKS.js → Reputation-DTyMd45j.js} +1 -1
- package/src/assets/web-panel/assets/{Row-ogiWR6v9.js → Row-DHrQ-Icz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-uYlk-2Oj.js → RssFeed-DqWxY9c5.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DYzzwvtM.js → Search-ctF1Ks3J.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Da7YOyX6.js → Security-BrQz8uo5.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CLI1VM1X.js → Services-D4scVFar.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DK77dzDC.js → Skeleton-oUScaOjv.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C_z7Lmhl.js → Skills-CL-y0eLt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-D6413Q8L.js → Sla-DQExhwXj.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C07ydbj2.js → SpeechSettings-iNp_I7kN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DGOm2W22.js → SyncSettings-CTDlMo0A.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Cr_PVyLM.js → Tasks-4kb8l3sc.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BhL2mZ0t.js → Templates-BXcL9oXW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CPk5oyUr.js → Tenant-DLE8eS0D.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-ClhqUsqV.js → Terminal-DGpUZPPK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BCC7MV5a.js → TimelineRenderer-C1pWXGPC.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DD1Jt4oO.js → Tokens-BYfbfqhZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BCydFvN2.js → Trigger-K9YfLOCw.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DDHT1noa.js → Trust-Ctkq77Hy.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CWPZC7oI.js → UkeySign-C6_CSe9J.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9Ea0nJR0.js → VideoEditing-Be3rpOWs.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BjxhLxTf.js → Wallet-D0UIplxk.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C6uCye67.js → WebAuthn-CF9bM9I3.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-d2g4reYo.js → WorkflowEditor-D0H1XVPY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-frTc6ScX.js → chat-Cgzzbe0o.js} +1 -1
- package/src/assets/web-panel/assets/{colors-B5K6lG3v.js → colors-BwNxEVS0.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cdn46r8D.js → compact-item-D60Z4Hhs.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DU1jqVQi.js → createContext-MFk58XB0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DdNH-aW_.js → hasIn-CRj2SvGO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM5FmPZU.js → index--s45_1cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4l82Me1.js → index--tquQ2ZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQorP1Ng.js → index-1T1rhokn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHmkkdfT.js → index-B-M82_rx.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGiwfwB9.js → index-BE_el1Zs.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwlIxAmX.js → index-BhRkR7IO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cj6P9Nst.js → index-Bo0y96-K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoFak7le.js → index-CJgu5JUK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dca_i7H8.js → index-CLWwdebO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVLL-mq_.js → index-CNAK5QG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-LaivuXyF.js → index-CQjJjPRD.js} +1 -1
- package/src/assets/web-panel/assets/{index-t_OBzIP4.js → index-CTDbAfae.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcGwGIaR.js → index-CVI_9sRK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D23xGYjM.js → index-CY14oMQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-VDM2KKo9.js → index-CbiTJkZf.js} +1 -1
- package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
- package/src/assets/web-panel/assets/{index-32ajXmTb.js → index-CqWpxMqx.js} +1 -1
- package/src/assets/web-panel/assets/{index-PjAS0sIZ.js → index-CvB8lYUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-7ehytj1K.js → index-D51XwtCY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtBCCkC4.js → index-D6HvK_1O.js} +1 -1
- package/src/assets/web-panel/assets/{index-Be4OtL-N.js → index-D9jVIwLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUoNAmE8.js → index-DA4tE98u.js} +1 -1
- package/src/assets/web-panel/assets/{index-cYaWV4Mq.js → index-DBwOtXw0.js} +1 -1
- package/src/assets/web-panel/assets/{index-MM4Zz2OE.js → index-DKdNzTIb.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIVyTmZ3.js → index-DRySdmvN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtRPi4YC.js → index-DWzyTev7.js} +1 -1
- package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
- package/src/assets/web-panel/assets/{index-kVO_MDm-.js → index-DYjs7jAP.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4miNkWv.js → index-DbROzMBp.js} +1 -1
- package/src/assets/web-panel/assets/{index-yZRuZpwK.js → index-DhFtk5PR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXKhhx9V.js → index-Di2AbMLg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BC4eGkar.js → index-DvmocQsM.js} +1 -1
- package/src/assets/web-panel/assets/{index-NmEXVjzt.js → index-Dw-o0zEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRzBBdQ0.js → index-DysPoP38.js} +1 -1
- package/src/assets/web-panel/assets/{index-HjCvXHf5.js → index-LX9pJxm_.js} +1 -1
- package/src/assets/web-panel/assets/{index-gg3QPC3i.js → index-OI_fXWx0.js} +3 -3
- package/src/assets/web-panel/assets/{index-mgU3Q-lN.js → index-eDTOX8Xj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1qIC4GR.js → index-gWKDsTzF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DftZuyA7.js → index-q_GDUVAA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DwLTRNdo.js → initDefaultProps-C61kZqEd.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BchZDXnh.js → motion-DZnT5U1L.js} +1 -1
- package/src/assets/web-panel/assets/{move-e8M-zZFl.js → move-L8wzwbel.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ci40fQb3.js → mtc-parser-DLdYSejc.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C7110_f2.js → omit-D53cbS59.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-skteMgnM.js → pickAttrs-Bbc5HPtu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-MGZ-lh2B.js → placementArrow-BkvmO860.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-N4Sd7uy-.js → responsiveObserve-u2y1ryS1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-C7HDGRaa.js → slide-BBqj7svU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BhRexlgy.js → statusUtils-GN0mqu2d.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-ChEoQkN2.js → styleChecker-BvwPKoBT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CDbG1s2Y.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CUIx0tcJ.js → useFs-DXAxl2SV.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-bkO7L7ec.js → usePersonalDataHub-DihlR2dj.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B_ZvABIG.js → vnode-D7BOX2gi.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D5shjpS8.js → zoom-CVbO-nL7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/mcp.js +119 -0
- package/src/commands/session-show.js +8 -10
- package/src/commands/session.js +60 -52
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/session-protocol.js +14 -4
- package/src/gateways/ws/ws-agent-handler.js +31 -0
- package/src/harness/jsonl-session-store.js +1147 -130
- package/src/harness/mcp-client.js +44 -11
- package/src/harness/session-index.js +80 -80
- package/src/harness/session-list-index.js +147 -2
- package/src/lib/background-interaction-journal.js +2 -2
- package/src/lib/command-lifecycle-report.js +516 -0
- package/src/lib/mcp-stdio-environment.js +48 -0
- package/src/lib/mcp-stdio-executable-identity.js +552 -17
- package/src/lib/mcp-stdio-package-materialization.js +1424 -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/process-execution-broker/index.js +180 -37
- package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
- 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-persistence-failure.js +109 -0
- package/src/lib/session-picker.js +26 -3
- package/src/lib/session-search.js +25 -11
- package/src/lib/side-effect-ledger-store.js +2 -2
- package/src/lib/skill-execution-authority.js +13 -9
- package/src/lib/turn-binding-store.js +2 -2
- package/src/repl/agent-repl.js +309 -39
- package/src/runtime/agent-core.js +88 -5
- package/src/runtime/cleanup-deadline.js +143 -0
- package/src/runtime/headless-runner.js +357 -139
- package/src/runtime/headless-stream.js +207 -28
- package/src/runtime/output-backpressure.js +53 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-CU-JB2Ns.js +0 -1
- package/src/assets/web-panel/assets/Providers-DDCf_nIw.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CP-jEUyw.js +0 -1
- package/src/assets/web-panel/assets/index-CzrCHrFy.js +0 -1
- package/src/assets/web-panel/assets/index-OJsGskZw.js +0 -1
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
|
-
|
|
14
|
+
readVerifiedEvents,
|
|
15
15
|
listJsonlSessions,
|
|
16
16
|
} from "../harness/jsonl-session-store.js";
|
|
17
17
|
|
|
@@ -54,7 +54,7 @@ export class SessionSearchIndex {
|
|
|
54
54
|
* @returns {Array<{role: string, content: string, timestamp: number}>}
|
|
55
55
|
*/
|
|
56
56
|
extractMessages(sessionId) {
|
|
57
|
-
const events =
|
|
57
|
+
const events = readVerifiedEvents(sessionId);
|
|
58
58
|
const messages = [];
|
|
59
59
|
|
|
60
60
|
for (const event of events) {
|
|
@@ -86,13 +86,22 @@ export class SessionSearchIndex {
|
|
|
86
86
|
if (!this._db) return { indexed: 0 };
|
|
87
87
|
if (!this._initialized) this.ensureTables();
|
|
88
88
|
|
|
89
|
-
const
|
|
90
|
-
|
|
89
|
+
const deleteExisting = () =>
|
|
90
|
+
this._db.exec(
|
|
91
|
+
`DELETE FROM session_fts WHERE session_id = '${sessionId.replace(/'/g, "''")}'`,
|
|
92
|
+
);
|
|
93
|
+
let messages;
|
|
94
|
+
try {
|
|
95
|
+
messages = this.extractMessages(sessionId);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
deleteExisting();
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
91
100
|
|
|
92
|
-
// Remove existing entries
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
);
|
|
101
|
+
// Remove existing entries before publishing the newly verified sample.
|
|
102
|
+
// Empty and damaged sessions must not leave older searchable content.
|
|
103
|
+
deleteExisting();
|
|
104
|
+
if (messages.length === 0) return { indexed: 0 };
|
|
96
105
|
|
|
97
106
|
const insert = this._db.prepare(
|
|
98
107
|
`INSERT INTO session_fts (session_id, role, content, timestamp) VALUES (?, ?, ?, ?)`,
|
|
@@ -164,13 +173,18 @@ export class SessionSearchIndex {
|
|
|
164
173
|
|
|
165
174
|
const sessions = listJsonlSessions({ limit: 10000 });
|
|
166
175
|
let totalMessages = 0;
|
|
176
|
+
let rejected = 0;
|
|
167
177
|
|
|
168
178
|
for (const session of sessions) {
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
try {
|
|
180
|
+
const result = this.indexSession(session.id);
|
|
181
|
+
totalMessages += result.indexed;
|
|
182
|
+
} catch {
|
|
183
|
+
rejected += 1;
|
|
184
|
+
}
|
|
171
185
|
}
|
|
172
186
|
|
|
173
|
-
return { sessions: sessions.length, messages: totalMessages };
|
|
187
|
+
return { sessions: sessions.length, messages: totalMessages, rejected };
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
/**
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
appendAuthorityEvent as storeAppendAuthorityEvent,
|
|
14
14
|
readEvents as storeReadEvents,
|
|
15
15
|
findLatestEvent as storeFindLatestEvent,
|
|
16
16
|
} from "../harness/jsonl-session-store.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
export const SIDE_EFFECT_LEDGER_EVENT = "side_effect_ledger";
|
|
24
24
|
|
|
25
25
|
export const _deps = {
|
|
26
|
-
appendEvent:
|
|
26
|
+
appendEvent: storeAppendAuthorityEvent,
|
|
27
27
|
readEvents: storeReadEvents,
|
|
28
28
|
findLatestEvent: storeFindLatestEvent,
|
|
29
29
|
};
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Durable, same-machine Skill execution authority.
|
|
3
3
|
*
|
|
4
|
-
* Every CLI process
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Every CLI process for the same OS user observes the same monotonically
|
|
5
|
+
* increasing generation, even when processes use different
|
|
6
|
+
* CHAINLESSCHAIN_HOME roots. Revocation is serialized by the canonical
|
|
7
|
+
* cross-process state lock in independent OS user security state and persisted
|
|
8
|
+
* with an atomic rename before any caller reports success. Active leases poll
|
|
9
|
+
* while they are alive, and every authority-sensitive transition also re-reads
|
|
10
|
+
* the store as a hard fence. Corruption, rollback observed by a live host, and
|
|
11
|
+
* lock/write failures fail closed.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import fs from "node:fs";
|
|
14
15
|
import path from "node:path";
|
|
15
16
|
import { randomUUID } from "node:crypto";
|
|
16
17
|
import { threadId } from "node:worker_threads";
|
|
17
|
-
import {
|
|
18
|
+
import { getMachineSecurityAnchorDir } from "./paths.js";
|
|
18
19
|
import {
|
|
19
20
|
mutateSecurityStore,
|
|
20
21
|
readSecurityStore,
|
|
@@ -172,7 +173,10 @@ function safeMessage(options) {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
export function getSkillExecutionAuthorityPath() {
|
|
175
|
-
return path.join(
|
|
176
|
+
return path.join(
|
|
177
|
+
getMachineSecurityAnchorDir(),
|
|
178
|
+
"skill-execution-authority-v1.json",
|
|
179
|
+
);
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
export class DurableSkillExecutionAuthority {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
|
-
|
|
19
|
+
appendAuthorityEvent as storeAppendAuthorityEvent,
|
|
20
20
|
readEvents as storeReadEvents,
|
|
21
21
|
findLatestEvent as storeFindLatestEvent,
|
|
22
22
|
} from "../harness/jsonl-session-store.js";
|
|
@@ -33,7 +33,7 @@ export const TURN_BINDING_TIMELINE_EVENT = "checkpoint_timeline_commit";
|
|
|
33
33
|
|
|
34
34
|
// Injected so tests can drive persistence without touching the real sessions dir.
|
|
35
35
|
export const _deps = {
|
|
36
|
-
appendEvent:
|
|
36
|
+
appendEvent: storeAppendAuthorityEvent,
|
|
37
37
|
readEvents: storeReadEvents,
|
|
38
38
|
findLatestEvent: storeFindLatestEvent,
|
|
39
39
|
};
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -69,6 +69,17 @@ import {
|
|
|
69
69
|
isVerifiedSessionHostSnapshot,
|
|
70
70
|
readSessionHostResumeState,
|
|
71
71
|
} from "../lib/session-host-snapshot.js";
|
|
72
|
+
import { acquireSessionHostLease } from "../lib/session-host-lease.js";
|
|
73
|
+
import {
|
|
74
|
+
SideEffectLedger,
|
|
75
|
+
classifyToolSideEffect,
|
|
76
|
+
reconcileSideEffects,
|
|
77
|
+
} from "../lib/side-effect-ledger.js";
|
|
78
|
+
import {
|
|
79
|
+
loadSideEffectLedger,
|
|
80
|
+
persistSideEffectLedger,
|
|
81
|
+
} from "../lib/side-effect-ledger-store.js";
|
|
82
|
+
import { operationIdempotencyKey } from "../lib/idempotency.js";
|
|
72
83
|
import {
|
|
73
84
|
preserveDurableSystemMessageProvenance,
|
|
74
85
|
projectCanonicalResumeMessages,
|
|
@@ -359,6 +370,9 @@ export async function agentLoop(messages, options) {
|
|
|
359
370
|
// The tool-result event carries no args; remember the last tool-executing
|
|
360
371
|
// pair so a recorded denial can show what was attempted (/permissions denials).
|
|
361
372
|
let _lastExec = null;
|
|
373
|
+
// The core loop runs tools serially. A classified non-MCP side effect stays
|
|
374
|
+
// live from its yielded `tool-executing` boundary until the matching result.
|
|
375
|
+
let _currentSideEffectOpId = null;
|
|
362
376
|
for await (const event of runCoreLoop(messages, {
|
|
363
377
|
...options,
|
|
364
378
|
// FORCE in-loop compaction off — the REPL runs its OWN post-turn compaction
|
|
@@ -407,12 +421,55 @@ export async function agentLoop(messages, options) {
|
|
|
407
421
|
args: event.args,
|
|
408
422
|
startedAt: options.now ? options.now() : Date.now(),
|
|
409
423
|
};
|
|
424
|
+
_currentSideEffectOpId = null;
|
|
425
|
+
if (options.sideEffects) {
|
|
426
|
+
const sideEffect = classifyToolSideEffect(event.tool, event.args);
|
|
427
|
+
if (sideEffect) {
|
|
428
|
+
const opId = options.sideEffects.nextOpId();
|
|
429
|
+
_currentSideEffectOpId = opId;
|
|
430
|
+
options.sideEffects.ledger
|
|
431
|
+
.prepare(opId, {
|
|
432
|
+
kind: sideEffect.kind,
|
|
433
|
+
key: sideEffect.key,
|
|
434
|
+
meta: {
|
|
435
|
+
tool: event.tool,
|
|
436
|
+
idempotencyKey: operationIdempotencyKey({
|
|
437
|
+
tool: event.tool,
|
|
438
|
+
args: event.args,
|
|
439
|
+
}),
|
|
440
|
+
},
|
|
441
|
+
})
|
|
442
|
+
.start(opId);
|
|
443
|
+
// The generator has yielded before executing the tool. Persist the
|
|
444
|
+
// started marker and recheck the host lease before resuming it.
|
|
445
|
+
options.sideEffects.persist();
|
|
446
|
+
options.sideEffects.assert?.();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
410
449
|
writeOut(
|
|
411
450
|
chalk.gray(
|
|
412
451
|
` [${event.tool}] ${formatToolArgs(event.tool, event.args)}\n`,
|
|
413
452
|
),
|
|
414
453
|
);
|
|
415
454
|
} else if (event.type === "tool-result") {
|
|
455
|
+
if (options.sideEffects && _currentSideEffectOpId) {
|
|
456
|
+
const sideEffectError = event.error || event.result?.error || null;
|
|
457
|
+
if (event.permission_decision) {
|
|
458
|
+
options.sideEffects.ledger.annotate(_currentSideEffectOpId, {
|
|
459
|
+
permissionDecision: event.permission_decision,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
if (sideEffectError) {
|
|
463
|
+
options.sideEffects.ledger.fail(
|
|
464
|
+
_currentSideEffectOpId,
|
|
465
|
+
String(sideEffectError).slice(0, 200),
|
|
466
|
+
);
|
|
467
|
+
} else {
|
|
468
|
+
options.sideEffects.ledger.commit(_currentSideEffectOpId);
|
|
469
|
+
}
|
|
470
|
+
options.sideEffects.persist();
|
|
471
|
+
_currentSideEffectOpId = null;
|
|
472
|
+
}
|
|
416
473
|
const durationMs =
|
|
417
474
|
event.result?.toolTelemetryRecord?.durationMs ??
|
|
418
475
|
(_lastExec?.tool === event.tool
|
|
@@ -2058,6 +2115,21 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2058
2115
|
"CC_REPL_STARTUP_DEPENDENCY_INVALID",
|
|
2059
2116
|
);
|
|
2060
2117
|
}
|
|
2118
|
+
const acquireHostLease = dependencyDataFunction(
|
|
2119
|
+
startupDependencies,
|
|
2120
|
+
"acquireSessionHostLease",
|
|
2121
|
+
null,
|
|
2122
|
+
);
|
|
2123
|
+
const leaseScope = options._sessionHostLeaseScope || null;
|
|
2124
|
+
const leaseSessionId = startupCandidate?.sessionId || options.sessionId;
|
|
2125
|
+
if (
|
|
2126
|
+
leaseScope &&
|
|
2127
|
+
!leaseScope.lease &&
|
|
2128
|
+
leaseSessionId &&
|
|
2129
|
+
typeof acquireHostLease === "function"
|
|
2130
|
+
) {
|
|
2131
|
+
leaseScope.lease = acquireHostLease(leaseSessionId, { hostKind: "repl" });
|
|
2132
|
+
}
|
|
2061
2133
|
const trustedWorkspaceRoot = readCwd();
|
|
2062
2134
|
return enterWorkspace(trustedWorkspaceRoot, () =>
|
|
2063
2135
|
startWorkspace(options, startupAdmission),
|
|
@@ -2066,13 +2138,26 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2066
2138
|
|
|
2067
2139
|
/** Start the agentic REPL with non-overridable production bindings. */
|
|
2068
2140
|
export async function startAgentRepl(options = {}) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2141
|
+
const sessionHostLeaseScope = { lease: null };
|
|
2142
|
+
const runtimeOptions = {
|
|
2143
|
+
...options,
|
|
2144
|
+
_sessionHostLeaseScope: sessionHostLeaseScope,
|
|
2145
|
+
};
|
|
2146
|
+
try {
|
|
2147
|
+
const result = await runReplStartupBoundary(runtimeOptions, {
|
|
2148
|
+
prepareReplStartupResume,
|
|
2149
|
+
refuseReplStartupResume,
|
|
2150
|
+
acquireSessionHostLease,
|
|
2151
|
+
cwd: () => process.cwd(),
|
|
2152
|
+
runWithHostHooksV2Workspace,
|
|
2153
|
+
startAgentReplInWorkspace,
|
|
2154
|
+
});
|
|
2155
|
+
if (result?.started === false) sessionHostLeaseScope.lease?.release?.();
|
|
2156
|
+
return result;
|
|
2157
|
+
} catch (error) {
|
|
2158
|
+
sessionHostLeaseScope.lease?.release?.();
|
|
2159
|
+
throw error;
|
|
2160
|
+
}
|
|
2076
2161
|
}
|
|
2077
2162
|
|
|
2078
2163
|
async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
@@ -2147,6 +2232,45 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2147
2232
|
}
|
|
2148
2233
|
}
|
|
2149
2234
|
};
|
|
2235
|
+
const _sessionHostLeaseScope = options._sessionHostLeaseScope || null;
|
|
2236
|
+
let _sessionHostLeaseAbortListener = null;
|
|
2237
|
+
let _sessionHostLeaseAbortSignal = null;
|
|
2238
|
+
const _detachSessionHostLease = () => {
|
|
2239
|
+
if (_sessionHostLeaseAbortListener && _sessionHostLeaseAbortSignal) {
|
|
2240
|
+
_sessionHostLeaseAbortSignal.removeEventListener(
|
|
2241
|
+
"abort",
|
|
2242
|
+
_sessionHostLeaseAbortListener,
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
_sessionHostLeaseAbortListener = null;
|
|
2246
|
+
_sessionHostLeaseAbortSignal = null;
|
|
2247
|
+
};
|
|
2248
|
+
const _attachSessionHostLease = () => {
|
|
2249
|
+
const signal = _sessionHostLeaseScope?.lease?.signal;
|
|
2250
|
+
if (!signal || _sessionHostLeaseAbortListener) return;
|
|
2251
|
+
_sessionHostLeaseAbortListener = () =>
|
|
2252
|
+
_requestReplOutputClose(
|
|
2253
|
+
signal.reason ||
|
|
2254
|
+
Object.assign(new Error("Session host lease was lost"), {
|
|
2255
|
+
code: "CC_SESSION_HOST_LEASE_FENCED",
|
|
2256
|
+
}),
|
|
2257
|
+
);
|
|
2258
|
+
_sessionHostLeaseAbortSignal = signal;
|
|
2259
|
+
signal.addEventListener("abort", _sessionHostLeaseAbortListener, {
|
|
2260
|
+
once: true,
|
|
2261
|
+
});
|
|
2262
|
+
if (signal.aborted) _sessionHostLeaseAbortListener();
|
|
2263
|
+
};
|
|
2264
|
+
const _replaceSessionHostLease = (lease) => {
|
|
2265
|
+
if (!_sessionHostLeaseScope) return null;
|
|
2266
|
+
const previous = _sessionHostLeaseScope.lease;
|
|
2267
|
+
if (previous === lease) return previous;
|
|
2268
|
+
_detachSessionHostLease();
|
|
2269
|
+
_sessionHostLeaseScope.lease = lease;
|
|
2270
|
+
_attachSessionHostLease();
|
|
2271
|
+
return previous;
|
|
2272
|
+
};
|
|
2273
|
+
_attachSessionHostLease();
|
|
2150
2274
|
const _replOutputFlow = outputScope.flow;
|
|
2151
2275
|
outputScope.setFailureHandler(_requestReplOutputClose);
|
|
2152
2276
|
const _disposeReplPipeSafety = installPipeSafety(undefined, () =>
|
|
@@ -2704,10 +2828,20 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2704
2828
|
};
|
|
2705
2829
|
if (useJsonl) {
|
|
2706
2830
|
try {
|
|
2707
|
-
sessionId = jsonlStartSession(null, meta);
|
|
2831
|
+
sessionId = jsonlStartSession(options.sessionId || null, meta);
|
|
2708
2832
|
} catch (_err) {
|
|
2709
2833
|
// Non-critical
|
|
2710
2834
|
}
|
|
2835
|
+
if (
|
|
2836
|
+
sessionId &&
|
|
2837
|
+
_sessionHostLeaseScope &&
|
|
2838
|
+
!_sessionHostLeaseScope.lease
|
|
2839
|
+
) {
|
|
2840
|
+
_sessionHostLeaseScope.lease = acquireSessionHostLease(sessionId, {
|
|
2841
|
+
hostKind: "repl",
|
|
2842
|
+
});
|
|
2843
|
+
_attachSessionHostLease();
|
|
2844
|
+
}
|
|
2711
2845
|
} else if (db) {
|
|
2712
2846
|
try {
|
|
2713
2847
|
const session = createSession(db, meta);
|
|
@@ -2845,6 +2979,79 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2845
2979
|
let _replBaseSystem = _buildReplBaseSystem();
|
|
2846
2980
|
let _activeOutputStyle = null; // { name, body }
|
|
2847
2981
|
const messages = [{ role: "system", content: _replBaseSystem }];
|
|
2982
|
+
let _replSideEffects = null;
|
|
2983
|
+
const _prepareReplSideEffects = (
|
|
2984
|
+
targetSessionId,
|
|
2985
|
+
{ recover = false } = {},
|
|
2986
|
+
) => {
|
|
2987
|
+
if (!useJsonl || !targetSessionId) {
|
|
2988
|
+
return Object.freeze({
|
|
2989
|
+
sideEffects: null,
|
|
2990
|
+
noticeMessage: null,
|
|
2991
|
+
warning: null,
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2994
|
+
let ledger;
|
|
2995
|
+
let loadError = null;
|
|
2996
|
+
try {
|
|
2997
|
+
ledger = loadSideEffectLedger(targetSessionId);
|
|
2998
|
+
} catch (error) {
|
|
2999
|
+
ledger = new SideEffectLedger();
|
|
3000
|
+
loadError = error;
|
|
3001
|
+
}
|
|
3002
|
+
const runNonce = `${Date.now()}:${randomUUID()}`;
|
|
3003
|
+
let sequence = 0;
|
|
3004
|
+
let noticeMessage = null;
|
|
3005
|
+
let warning = null;
|
|
3006
|
+
if (recover && !loadError) {
|
|
3007
|
+
const plan = reconcileSideEffects(ledger);
|
|
3008
|
+
if (plan.inspect.length > 0) {
|
|
3009
|
+
const lines = plan.plans
|
|
3010
|
+
.filter((entry) => entry.action === "inspect")
|
|
3011
|
+
.map((entry) => {
|
|
3012
|
+
const operation = ledger.get(entry.opId);
|
|
3013
|
+
const key = operation?.key ? ` (${operation.key})` : "";
|
|
3014
|
+
return ` - [${operation?.kind || "unknown"}]${key} - ${entry.reason}`;
|
|
3015
|
+
});
|
|
3016
|
+
noticeMessage = Object.freeze({
|
|
3017
|
+
role: "system",
|
|
3018
|
+
content:
|
|
3019
|
+
"Recovery notice: the previous REPL host stopped while irreversible operations were in flight. Their outcome is UNKNOWN. Do not blindly repeat them; verify whether each operation already took effect and ask the user when uncertain:\n" +
|
|
3020
|
+
lines.join("\n"),
|
|
3021
|
+
});
|
|
3022
|
+
warning = `Recovery: ${plan.inspect.length} interrupted non-MCP side effect(s) require verification before replay.`;
|
|
3023
|
+
}
|
|
3024
|
+
} else if (recover && loadError) {
|
|
3025
|
+
noticeMessage = Object.freeze({
|
|
3026
|
+
role: "system",
|
|
3027
|
+
content:
|
|
3028
|
+
"Recovery notice: the durable non-MCP side-effect ledger is unavailable. Read-only work may continue, but irreversible tools are blocked until recovery authority is restored.",
|
|
3029
|
+
});
|
|
3030
|
+
warning = `Recovery: non-MCP side-effect ledger is unavailable for ${targetSessionId}; irreversible tools are fail-closed.`;
|
|
3031
|
+
}
|
|
3032
|
+
const sideEffects = Object.freeze({
|
|
3033
|
+
ledger,
|
|
3034
|
+
nextOpId: () => `${runNonce}:${sequence++}`,
|
|
3035
|
+
persist: () => {
|
|
3036
|
+
if (loadError) throw loadError;
|
|
3037
|
+
const persisted = persistSideEffectLedger(targetSessionId, ledger);
|
|
3038
|
+
if (persisted === false) {
|
|
3039
|
+
const error = new Error(
|
|
3040
|
+
`Side-effect ledger persistence was rejected for ${targetSessionId}`,
|
|
3041
|
+
);
|
|
3042
|
+
error.code = "SIDE_EFFECT_LEDGER_PERSIST_FAILED";
|
|
3043
|
+
throw error;
|
|
3044
|
+
}
|
|
3045
|
+
return persisted;
|
|
3046
|
+
},
|
|
3047
|
+
assert: () => _sessionHostLeaseScope?.lease?.assert?.(),
|
|
3048
|
+
});
|
|
3049
|
+
return Object.freeze({ sideEffects, noticeMessage, warning });
|
|
3050
|
+
};
|
|
3051
|
+
const _startupReplSideEffects = _prepareReplSideEffects(sessionId, {
|
|
3052
|
+
recover: Boolean(options.sessionId && _startupJsonlResume?.ok),
|
|
3053
|
+
});
|
|
3054
|
+
_replSideEffects = _startupReplSideEffects.sideEffects;
|
|
2848
3055
|
let _mcpLedgerRecovery = null;
|
|
2849
3056
|
let _mcpLedgerRecoveryError = null;
|
|
2850
3057
|
const _prepareJsonlResumeCandidate = (targetSessionId) =>
|
|
@@ -3362,6 +3569,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
3362
3569
|
throw error;
|
|
3363
3570
|
}
|
|
3364
3571
|
messages.push(...prepared.canonicalSystemMessages);
|
|
3572
|
+
if (_startupReplSideEffects.noticeMessage) {
|
|
3573
|
+
messages.push(_startupReplSideEffects.noticeMessage);
|
|
3574
|
+
}
|
|
3575
|
+
if (_startupReplSideEffects.warning) {
|
|
3576
|
+
logger.warn(_startupReplSideEffects.warning);
|
|
3577
|
+
}
|
|
3365
3578
|
_commitMcpRecoveryCandidate(messages, prepared.mcp);
|
|
3366
3579
|
if (prepared.replayMessages.length > 0) {
|
|
3367
3580
|
messages.push(...prepared.conversationMessages);
|
|
@@ -5835,39 +6048,87 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
5835
6048
|
const resumeId = sessionArg.slice(7).trim();
|
|
5836
6049
|
try {
|
|
5837
6050
|
if (useJsonl) {
|
|
5838
|
-
const
|
|
5839
|
-
if (!
|
|
5840
|
-
const
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
);
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
canonicalSystemMessages: prepared.canonicalSystemMessages,
|
|
5851
|
-
conversationMessages: prepared.conversationMessages,
|
|
5852
|
-
mcpCommit: preparedMcpCommit,
|
|
5853
|
-
mcpRuntime: preparedMcpRuntime,
|
|
5854
|
-
sanitizeRolesNextTurn:
|
|
5855
|
-
prepared.conversationMessages.at(-1)?.role === "user",
|
|
5856
|
-
logMessage: `Resumed JSONL session ${prepared.sessionId} (${prepared.rebuiltMessages.length} messages)`,
|
|
5857
|
-
});
|
|
5858
|
-
const committed = commitPreparedReplJsonlResume(
|
|
5859
|
-
prepared,
|
|
5860
|
-
() => _applyPreparedResumeState(preparedState),
|
|
5861
|
-
() => _restoreResumeState(previousState),
|
|
5862
|
-
);
|
|
5863
|
-
if (!committed) {
|
|
5864
|
-
const error = new Error(
|
|
5865
|
-
"Prepared JSONL session resume was not committed",
|
|
6051
|
+
const initialCandidate = _prepareJsonlResumeCandidate(resumeId);
|
|
6052
|
+
if (!initialCandidate.ok) throw initialCandidate.error;
|
|
6053
|
+
const currentLease = _sessionHostLeaseScope?.lease || null;
|
|
6054
|
+
const reuseCurrentLease = initialCandidate.sessionId === sessionId;
|
|
6055
|
+
let targetLease = reuseCurrentLease ? currentLease : null;
|
|
6056
|
+
let adoptedTargetLease = reuseCurrentLease && Boolean(currentLease);
|
|
6057
|
+
if (!targetLease) {
|
|
6058
|
+
targetLease = acquireSessionHostLease(
|
|
6059
|
+
initialCandidate.sessionId,
|
|
6060
|
+
{
|
|
6061
|
+
hostKind: "repl",
|
|
6062
|
+
},
|
|
5866
6063
|
);
|
|
5867
|
-
error.code = "CC_REPL_SESSION_RESUME_NOT_COMMITTED";
|
|
5868
|
-
throw error;
|
|
5869
6064
|
}
|
|
5870
|
-
|
|
6065
|
+
let prepared;
|
|
6066
|
+
try {
|
|
6067
|
+
// Re-sample after acquiring the target's write authority. The
|
|
6068
|
+
// first sample resolves/refuses the request; this one is the
|
|
6069
|
+
// exact snapshot committed into the live REPL.
|
|
6070
|
+
prepared = _prepareJsonlResumeCandidate(
|
|
6071
|
+
initialCandidate.sessionId,
|
|
6072
|
+
);
|
|
6073
|
+
if (!prepared.ok) throw prepared.error;
|
|
6074
|
+
const preparedSideEffects = _prepareReplSideEffects(
|
|
6075
|
+
prepared.sessionId,
|
|
6076
|
+
{ recover: true },
|
|
6077
|
+
);
|
|
6078
|
+
const preparedMcpRuntime = _prepareMcpHostRuntime(
|
|
6079
|
+
prepared.sessionId,
|
|
6080
|
+
prepared.mcp,
|
|
6081
|
+
);
|
|
6082
|
+
const preparedMcpCommit = _prepareMcpRecoveryCommit(prepared.mcp);
|
|
6083
|
+
const hostSystemMessages = _refreshHostSystemMessages();
|
|
6084
|
+
const previousState = _captureResumeState();
|
|
6085
|
+
const preparedState = Object.freeze({
|
|
6086
|
+
sessionId: prepared.sessionId,
|
|
6087
|
+
hostSystemMessages,
|
|
6088
|
+
canonicalSystemMessages: Object.freeze([
|
|
6089
|
+
...prepared.canonicalSystemMessages,
|
|
6090
|
+
...(preparedSideEffects.noticeMessage
|
|
6091
|
+
? [preparedSideEffects.noticeMessage]
|
|
6092
|
+
: []),
|
|
6093
|
+
]),
|
|
6094
|
+
conversationMessages: prepared.conversationMessages,
|
|
6095
|
+
mcpCommit: preparedMcpCommit,
|
|
6096
|
+
mcpRuntime: preparedMcpRuntime,
|
|
6097
|
+
sanitizeRolesNextTurn:
|
|
6098
|
+
prepared.conversationMessages.at(-1)?.role === "user",
|
|
6099
|
+
logMessage: `Resumed JSONL session ${prepared.sessionId} (${prepared.rebuiltMessages.length} messages)`,
|
|
6100
|
+
});
|
|
6101
|
+
const committed = commitPreparedReplJsonlResume(
|
|
6102
|
+
prepared,
|
|
6103
|
+
() => _applyPreparedResumeState(preparedState),
|
|
6104
|
+
() => _restoreResumeState(previousState),
|
|
6105
|
+
);
|
|
6106
|
+
if (!committed) {
|
|
6107
|
+
const error = new Error(
|
|
6108
|
+
"Prepared JSONL session resume was not committed",
|
|
6109
|
+
);
|
|
6110
|
+
error.code = "CC_REPL_SESSION_RESUME_NOT_COMMITTED";
|
|
6111
|
+
throw error;
|
|
6112
|
+
}
|
|
6113
|
+
const previousLease = _replaceSessionHostLease(targetLease);
|
|
6114
|
+
adoptedTargetLease = true;
|
|
6115
|
+
_replSideEffects = preparedSideEffects.sideEffects;
|
|
6116
|
+
if (preparedSideEffects.warning) {
|
|
6117
|
+
logger.warn(preparedSideEffects.warning);
|
|
6118
|
+
}
|
|
6119
|
+
if (previousLease && previousLease !== targetLease) {
|
|
6120
|
+
try {
|
|
6121
|
+
previousLease.release?.();
|
|
6122
|
+
} catch (releaseError) {
|
|
6123
|
+
logger.warn(
|
|
6124
|
+
`Session switch committed, but the prior host lease could not be released: ${releaseError.message}`,
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
_replCompactPersistence.replace(prepared.rebuiltMessages);
|
|
6129
|
+
} finally {
|
|
6130
|
+
if (!adoptedTargetLease) targetLease?.release?.();
|
|
6131
|
+
}
|
|
5871
6132
|
} else if (db) {
|
|
5872
6133
|
const existing = getSession(db, resumeId);
|
|
5873
6134
|
if (existing && existing.messages) {
|
|
@@ -7913,6 +8174,9 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
7913
8174
|
// Explicit turn-binding producer (null unless a JSONL session): the
|
|
7914
8175
|
// wrapper folds every loop event into the live table.
|
|
7915
8176
|
turnBindingFeed: _turnBindingProducer,
|
|
8177
|
+
// Non-MCP irreversible tools use the same prepare/start/settle ledger
|
|
8178
|
+
// and final lease assertion as headless, stream, and WebSocket hosts.
|
|
8179
|
+
sideEffects: _replSideEffects,
|
|
7916
8180
|
denialLog: _recentDenials,
|
|
7917
8181
|
persistRecentDenials: true,
|
|
7918
8182
|
permissionMode: _sessionTier,
|
|
@@ -8497,6 +8761,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8497
8761
|
}
|
|
8498
8762
|
|
|
8499
8763
|
// Shutdown runtime
|
|
8764
|
+
_detachSessionHostLease();
|
|
8765
|
+
try {
|
|
8766
|
+
_sessionHostLeaseScope?.lease?.release?.();
|
|
8767
|
+
} catch (error) {
|
|
8768
|
+
_replOutputFailure ||= error;
|
|
8769
|
+
}
|
|
8500
8770
|
try {
|
|
8501
8771
|
await shutdown();
|
|
8502
8772
|
} catch (_e) {
|