@svenroth-ai/shipwright 0.28.0 → 0.29.1
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/client/dist/apple-touch-icon.png +0 -0
- package/client/dist/assets/{EmbeddedTerminal-4xgNUBUu.js → EmbeddedTerminal-BXosRYLy.js} +30 -30
- package/client/dist/assets/{abnfDiagram-VRR7QNED-BdCNbaqc.js → abnfDiagram-VCTEODGH-BGxuVEiU.js} +1 -1
- package/client/dist/assets/arc-o82bcJs8.js +1 -0
- package/client/dist/assets/architectureDiagram-5GKGNRK7-CaeUIM7e.js +36 -0
- package/client/dist/assets/blockDiagram-I7D4REHJ-DtWpTjgT.js +129 -0
- package/client/dist/assets/c4Diagram-7LVT6UL2-sJULbaUv.js +38 -0
- package/client/dist/assets/channel-CLBQbfQb.js +1 -0
- package/client/dist/assets/{chunk-2Q5K7J3B-4N6AnmBJ.js → chunk-2Q5K7J3B-CPeH4xHb.js} +1 -1
- package/client/dist/assets/{chunk-5VM5RSS4-Bwd7rtD3.js → chunk-5VM5RSS4-DxiKB3qZ.js} +1 -1
- package/client/dist/assets/{chunk-32BRIVSS-Cs67LiCy.js → chunk-F27PBJKO-B8V1zhCX.js} +1 -1
- package/client/dist/assets/{chunk-EX3LRPZG-CQqGfptD.js → chunk-IMKFNOWR-BtXet829.js} +5 -5
- package/client/dist/assets/{chunk-JWPE2WC7-ClvKd4PN.js → chunk-JWPE2WC7-BaQYKssR.js} +1 -1
- package/client/dist/assets/chunk-POPQ4Y6H-I1x_vfH3.js +1 -0
- package/client/dist/assets/{chunk-MOJQB5TN-Cwvj8GE1.js → chunk-SVP7TREG-Bvt8jrSp.js} +1 -1
- package/client/dist/assets/{chunk-V7JOEXUC-CYFfa4PY.js → chunk-TICWLB2K--9ywNq1F.js} +1 -1
- package/client/dist/assets/{chunk-XXDRQBXY-BQAZ6Our.js → chunk-XXDRQBXY-DrIyrBs1.js} +1 -1
- package/client/dist/assets/classDiagram-ZZMXUADV-D8z-o3xu.js +1 -0
- package/client/dist/assets/classDiagram-v2-VYDZK3BY-D8z-o3xu.js +1 -0
- package/client/dist/assets/{cose-bilkent-JH36ORCC-C76Yia6h.js → cose-bilkent-JH36ORCC-DISm8_p0.js} +1 -1
- package/client/dist/assets/{cynefin-VYW2F7L2-pJe7rdTi.js → cynefin-OW5HDTMX-wyDjqucU.js} +3 -3
- package/client/dist/assets/{cynefinDiagram-TSTJHNR4-EeHQ7dYV.js → cynefinDiagram-5FMLGOSQ-CN-IKDQ6.js} +1 -1
- package/client/dist/assets/dagre-GXQ25YYZ-QY0m5eSL.js +4 -0
- package/client/dist/assets/diagram-S7CK7UJ4-DhjaAe2g.js +30 -0
- package/client/dist/assets/diagram-UQ7AKVKN-D-3R3axg.js +41 -0
- package/client/dist/assets/{diagram-FQU43EPY-DW_-leqw.js → diagram-VSXAHHWV-BxXEtjRu.js} +2 -2
- package/client/dist/assets/{diagram-G47NLZAW-C_hsLD4u.js → diagram-VX7I27RA-DkbXkJpd.js} +1 -1
- package/client/dist/assets/{diagram-NH7WQ7WH-CbeQuO_f.js → diagram-Z3DM3KII-DQGRD9gQ.js} +1 -1
- package/client/dist/assets/{ebnfDiagram-CCIWWBDH-B8Z8WHF6.js → ebnfDiagram-PWID7BFC-C_XxskCm.js} +1 -1
- package/client/dist/assets/erDiagram-RLTQ6QDP-BhBsYQ7c.js +99 -0
- package/client/dist/assets/flowDiagram-HODETNUW-D7fXEPrM.js +168 -0
- package/client/dist/assets/{ganttDiagram-NO4QXBWP-K3X0DYBa.js → ganttDiagram-EL5Y4UJY-Bwf8EtWr.js} +4 -4
- package/client/dist/assets/{gitGraphDiagram-IHSO6WYX-B2SEx0xa.js → gitGraphDiagram-WWUBYQGX-C3_ixsOl.js} +1 -1
- package/client/dist/assets/index-DWrPE3aq.css +1 -0
- package/client/dist/assets/index-DwRlIUrK.js +924 -0
- package/client/dist/assets/infoDiagram-27XIBGKW-BpcHmgOL.js +2 -0
- package/client/dist/assets/{ishikawaDiagram-FXEZZL3T-CrN7QJzt.js → ishikawaDiagram-5VMMS53U-DzSGmhT5.js} +4 -4
- package/client/dist/assets/{journeyDiagram-5HDEW3XC-XHIsl7rM.js → journeyDiagram-3NMN7TZE-CT1CrVQO.js} +2 -2
- package/client/dist/assets/{kanban-definition-HUTT4EX6-A6HJqHw7.js → kanban-definition-UXKFOSKX-N1CNMAOm.js} +8 -8
- package/client/dist/assets/katex-C5jXJg4s.js +257 -0
- package/client/dist/assets/layout-CR8gdfo4.js +1 -0
- package/client/dist/assets/{linear-D1vF9IQB.js → linear-CfLRjQgX.js} +1 -1
- package/client/dist/assets/mermaid.core-Bnqt31Q7.js +312 -0
- package/client/dist/assets/{mindmap-definition-LN4V7U3C-CxRkUj6Z.js → mindmap-definition-YA3MSWOX-Brc-v1M4.js} +2 -2
- package/client/dist/assets/{pegDiagram-2B236MQR-Bs9dp-8a.js → pegDiagram-XKGWAZYB-D8jUV01U.js} +1 -1
- package/client/dist/assets/{pieDiagram-ENE6RG2P-DBWILzB8.js → pieDiagram-E7YTZNPT-BiSkIsrz.js} +3 -3
- package/client/dist/assets/{quadrantDiagram-ABIIQ3AL-DrCVJJx6.js → quadrantDiagram-AXDQQJYC-CJetqQxd.js} +1 -1
- package/client/dist/assets/{railroadDiagram-RFXS5EU6-BdPW2dNf.js → railroadDiagram-O6MQD6OU-DTTtZpGO.js} +1 -1
- package/client/dist/assets/{requirementDiagram-TGXJPOKE-Bj_g3tC5.js → requirementDiagram-BXWQKSXE-meFCoLtR.js} +5 -5
- package/client/dist/assets/{sankeyDiagram-HTMAVEWB-BGL9NnsS.js → sankeyDiagram-P5KCCOFB-BR9eN4Do.js} +4 -4
- package/client/dist/assets/{sequenceDiagram-DBY2YBRQ-DEirxTZY.js → sequenceDiagram-WJ2MYXX4-BdVzFsCC.js} +1 -1
- package/client/dist/assets/{sizeCapture-X5ZJPWSS-BtLrvrea.js → sizeCapture-INFHLROL-CZoZ7r-1.js} +1 -1
- package/client/dist/assets/stateDiagram-D77RDMKH-Cmc-iYtm.js +1 -0
- package/client/dist/assets/stateDiagram-v2-MP3YSRHH-Cj-hQ4qB.js +1 -0
- package/client/dist/assets/swimlanes-42K2YHIH-DN4MssUX.js +1 -0
- package/client/dist/assets/swimlanesDiagram-VR7AAH4N-DFxrYFKF.js +8 -0
- package/client/dist/assets/{timeline-definition-FHXFAJF6-CnBKJtD_.js → timeline-definition-24CTP7MA-pxxqlxwt.js} +3 -3
- package/client/dist/assets/{vennDiagram-L72KCM5P-BYmiJYoh.js → vennDiagram-4TSXK5OY-DiItNcze.js} +5 -5
- package/client/dist/assets/{wardleyDiagram-EHGQE667-DU7vW8q3.js → wardleyDiagram-VM6X3IG4-Dfvub75z.js} +1 -1
- package/client/dist/assets/xychartDiagram-S5SC5T6Z-Bx83X515.js +7 -0
- package/client/dist/favicon-16.png +0 -0
- package/client/dist/favicon-32.png +0 -0
- package/client/dist/icon-192.png +0 -0
- package/client/dist/icon-512.png +0 -0
- package/client/dist/icon-maskable-512.png +0 -0
- package/client/dist/index.html +11 -2
- package/client/dist/manifest.json +13 -0
- package/package.json +2 -2
- package/server/dist/config.d.ts.map +1 -1
- package/server/dist/config.js +7 -2
- package/server/dist/config.js.map +1 -1
- package/server/dist/core/adopt-scan-findings.d.ts +12 -0
- package/server/dist/core/adopt-scan-findings.d.ts.map +1 -0
- package/server/dist/core/adopt-scan-findings.js +96 -0
- package/server/dist/core/adopt-scan-findings.js.map +1 -0
- package/server/dist/core/adopt-scan.d.ts +49 -0
- package/server/dist/core/adopt-scan.d.ts.map +1 -0
- package/server/dist/core/adopt-scan.js +201 -0
- package/server/dist/core/adopt-scan.js.map +1 -0
- package/server/dist/core/custom-profile-command-policy.d.ts +6 -0
- package/server/dist/core/custom-profile-command-policy.d.ts.map +1 -0
- package/server/dist/core/custom-profile-command-policy.js +110 -0
- package/server/dist/core/custom-profile-command-policy.js.map +1 -0
- package/server/dist/core/custom-profile-loader.d.ts +34 -0
- package/server/dist/core/custom-profile-loader.d.ts.map +1 -0
- package/server/dist/core/custom-profile-loader.js +225 -0
- package/server/dist/core/custom-profile-loader.js.map +1 -0
- package/server/dist/core/preview-child-lifecycle.d.ts +7 -2
- package/server/dist/core/preview-child-lifecycle.d.ts.map +1 -1
- package/server/dist/core/preview-child-lifecycle.js +17 -5
- package/server/dist/core/preview-child-lifecycle.js.map +1 -1
- package/server/dist/core/preview-session-manager.d.ts +1 -0
- package/server/dist/core/preview-session-manager.d.ts.map +1 -1
- package/server/dist/core/preview-session-manager.js +2 -2
- package/server/dist/core/preview-session-manager.js.map +1 -1
- package/server/dist/core/project-actions-loader.d.ts +13 -0
- package/server/dist/core/project-actions-loader.d.ts.map +1 -1
- package/server/dist/core/project-actions-loader.js +28 -6
- package/server/dist/core/project-actions-loader.js.map +1 -1
- package/server/dist/core/project-data-dir.d.ts +41 -0
- package/server/dist/core/project-data-dir.d.ts.map +1 -0
- package/server/dist/core/project-data-dir.js +64 -0
- package/server/dist/core/project-data-dir.js.map +1 -0
- package/server/dist/core/project-data-migrate.d.ts +14 -0
- package/server/dist/core/project-data-migrate.d.ts.map +1 -0
- package/server/dist/core/project-data-migrate.js +94 -0
- package/server/dist/core/project-data-migrate.js.map +1 -0
- package/server/dist/core/project-manager.d.ts.map +1 -1
- package/server/dist/core/project-manager.js +9 -10
- package/server/dist/core/project-manager.js.map +1 -1
- package/server/dist/core/session-file/access.d.ts +26 -0
- package/server/dist/core/session-file/access.d.ts.map +1 -0
- package/server/dist/core/session-file/access.js +143 -0
- package/server/dist/core/session-file/access.js.map +1 -0
- package/server/dist/core/session-file/asset-access.d.ts +15 -0
- package/server/dist/core/session-file/asset-access.d.ts.map +1 -0
- package/server/dist/core/session-file/asset-access.js +141 -0
- package/server/dist/core/session-file/asset-access.js.map +1 -0
- package/server/dist/core/session-file/evidence.d.ts +25 -0
- package/server/dist/core/session-file/evidence.d.ts.map +1 -0
- package/server/dist/core/session-file/evidence.js +201 -0
- package/server/dist/core/session-file/evidence.js.map +1 -0
- package/server/dist/core/session-file/probe.d.ts +16 -0
- package/server/dist/core/session-file/probe.d.ts.map +1 -0
- package/server/dist/core/session-file/probe.js +63 -0
- package/server/dist/core/session-file/probe.js.map +1 -0
- package/server/dist/core/session-file/safe-read.d.ts +33 -0
- package/server/dist/core/session-file/safe-read.d.ts.map +1 -0
- package/server/dist/core/session-file/safe-read.js +103 -0
- package/server/dist/core/session-file/safe-read.js.map +1 -0
- package/server/dist/core/session-file/sensitive.d.ts +5 -0
- package/server/dist/core/session-file/sensitive.d.ts.map +1 -0
- package/server/dist/core/session-file/sensitive.js +52 -0
- package/server/dist/core/session-file/sensitive.js.map +1 -0
- package/server/dist/core/session-info/collect.d.ts +70 -0
- package/server/dist/core/session-info/collect.d.ts.map +1 -0
- package/server/dist/core/session-info/collect.js +248 -0
- package/server/dist/core/session-info/collect.js.map +1 -0
- package/server/dist/core/session-info/line-scan.d.ts +20 -0
- package/server/dist/core/session-info/line-scan.d.ts.map +1 -0
- package/server/dist/core/session-info/line-scan.js +109 -0
- package/server/dist/core/session-info/line-scan.js.map +1 -0
- package/server/dist/core/session-info/remote-control.d.ts +9 -0
- package/server/dist/core/session-info/remote-control.d.ts.map +1 -0
- package/server/dist/core/session-info/remote-control.js +64 -0
- package/server/dist/core/session-info/remote-control.js.map +1 -0
- package/server/dist/core/session-info/session-info.d.ts +18 -0
- package/server/dist/core/session-info/session-info.d.ts.map +1 -0
- package/server/dist/core/session-info/session-info.js +170 -0
- package/server/dist/core/session-info/session-info.js.map +1 -0
- package/server/dist/core/session-info/small-file.d.ts +2 -0
- package/server/dist/core/session-info/small-file.d.ts.map +1 -0
- package/server/dist/core/session-info/small-file.js +42 -0
- package/server/dist/core/session-info/small-file.js.map +1 -0
- package/server/dist/core/session-info/subagent-transcript.d.ts +12 -0
- package/server/dist/core/session-info/subagent-transcript.d.ts.map +1 -0
- package/server/dist/core/session-info/subagent-transcript.js +78 -0
- package/server/dist/core/session-info/subagent-transcript.js.map +1 -0
- package/server/dist/core/session-info/subagents.d.ts +14 -0
- package/server/dist/core/session-info/subagents.d.ts.map +1 -0
- package/server/dist/core/session-info/subagents.js +92 -0
- package/server/dist/core/session-info/subagents.js.map +1 -0
- package/server/dist/core/session-info/test-fixtures.d.ts +50 -0
- package/server/dist/core/session-info/test-fixtures.d.ts.map +1 -0
- package/server/dist/core/session-info/test-fixtures.js +43 -0
- package/server/dist/core/session-info/test-fixtures.js.map +1 -0
- package/server/dist/core/session-info/types.d.ts +77 -0
- package/server/dist/core/session-info/types.d.ts.map +1 -0
- package/server/dist/core/session-info/types.js +14 -0
- package/server/dist/core/session-info/types.js.map +1 -0
- package/server/dist/core/stack-profiles-create.d.ts +31 -0
- package/server/dist/core/stack-profiles-create.d.ts.map +1 -0
- package/server/dist/core/stack-profiles-create.js +128 -0
- package/server/dist/core/stack-profiles-create.js.map +1 -0
- package/server/dist/core/stack-profiles.d.ts +49 -0
- package/server/dist/core/stack-profiles.d.ts.map +1 -0
- package/server/dist/core/stack-profiles.js +142 -0
- package/server/dist/core/stack-profiles.js.map +1 -0
- package/server/dist/external/_shared/helpers.d.ts +2 -0
- package/server/dist/external/_shared/helpers.d.ts.map +1 -1
- package/server/dist/external/_shared/helpers.js.map +1 -1
- package/server/dist/external/actions/get.d.ts +3 -1
- package/server/dist/external/actions/get.d.ts.map +1 -1
- package/server/dist/external/actions/get.js +15 -4
- package/server/dist/external/actions/get.js.map +1 -1
- package/server/dist/external/actions/routes.d.ts +3 -1
- package/server/dist/external/actions/routes.d.ts.map +1 -1
- package/server/dist/external/actions/routes.js.map +1 -1
- package/server/dist/external/actions/stub.d.ts.map +1 -1
- package/server/dist/external/actions/stub.js +15 -4
- package/server/dist/external/actions/stub.js.map +1 -1
- package/server/dist/external/actions/upload-delete.d.ts.map +1 -1
- package/server/dist/external/actions/upload-delete.js +30 -20
- package/server/dist/external/actions/upload-delete.js.map +1 -1
- package/server/dist/external/actions/upload.d.ts.map +1 -1
- package/server/dist/external/actions/upload.js +5 -4
- package/server/dist/external/actions/upload.js.map +1 -1
- package/server/dist/external/create-external-routes-args.d.ts +3 -1
- package/server/dist/external/create-external-routes-args.d.ts.map +1 -1
- package/server/dist/external/inbox/_phase-gate.d.ts +9 -0
- package/server/dist/external/inbox/_phase-gate.d.ts.map +1 -0
- package/server/dist/external/inbox/_phase-gate.js +87 -0
- package/server/dist/external/inbox/_phase-gate.js.map +1 -0
- package/server/dist/external/inbox/_types.d.ts +7 -0
- package/server/dist/external/inbox/_types.d.ts.map +1 -1
- package/server/dist/external/inbox/routes.d.ts.map +1 -1
- package/server/dist/external/inbox/routes.js +2 -0
- package/server/dist/external/inbox/routes.js.map +1 -1
- package/server/dist/external/launch/action-substitution-branch.js +2 -2
- package/server/dist/external/launch/action-substitution-branch.js.map +1 -1
- package/server/dist/external/mission-context/facts.js +2 -2
- package/server/dist/external/mission-context/facts.js.map +1 -1
- package/server/dist/external/preview/routes.d.ts +3 -1
- package/server/dist/external/preview/routes.d.ts.map +1 -1
- package/server/dist/external/preview/routes.js +8 -1
- package/server/dist/external/preview/routes.js.map +1 -1
- package/server/dist/external/routes.d.ts.map +1 -1
- package/server/dist/external/routes.js +2 -2
- package/server/dist/external/routes.js.map +1 -1
- package/server/dist/external/session-file/probe-route.d.ts +4 -0
- package/server/dist/external/session-file/probe-route.d.ts.map +1 -0
- package/server/dist/external/session-file/probe-route.js +66 -0
- package/server/dist/external/session-file/probe-route.js.map +1 -0
- package/server/dist/external/session-file/routes.d.ts +12 -0
- package/server/dist/external/session-file/routes.d.ts.map +1 -0
- package/server/dist/external/session-file/routes.js +90 -0
- package/server/dist/external/session-file/routes.js.map +1 -0
- package/server/dist/external/session-file/session-file.fixture.d.ts +45 -0
- package/server/dist/external/session-file/session-file.fixture.d.ts.map +1 -0
- package/server/dist/external/session-file/session-file.fixture.js +41 -0
- package/server/dist/external/session-file/session-file.fixture.js.map +1 -0
- package/server/dist/external/session-info/routes.d.ts +15 -0
- package/server/dist/external/session-info/routes.d.ts.map +1 -0
- package/server/dist/external/session-info/routes.js +57 -0
- package/server/dist/external/session-info/routes.js.map +1 -0
- package/server/dist/external/tasks/_phase-helpers.js +2 -2
- package/server/dist/external/tasks/_phase-helpers.js.map +1 -1
- package/server/dist/external/tasks/create.js +2 -2
- package/server/dist/external/tasks/create.js.map +1 -1
- package/server/dist/external-routes-wiring.d.ts.map +1 -1
- package/server/dist/external-routes-wiring.js +10 -1
- package/server/dist/external-routes-wiring.js.map +1 -1
- package/server/dist/index.d.ts.map +1 -1
- package/server/dist/index.js +6 -8
- package/server/dist/index.js.map +1 -1
- package/server/dist/routes/adopt-scan.d.ts +4 -0
- package/server/dist/routes/adopt-scan.d.ts.map +1 -0
- package/server/dist/routes/adopt-scan.js +27 -0
- package/server/dist/routes/adopt-scan.js.map +1 -0
- package/server/dist/routes/profiles.d.ts +7 -0
- package/server/dist/routes/profiles.d.ts.map +1 -1
- package/server/dist/routes/profiles.js +13 -0
- package/server/dist/routes/profiles.js.map +1 -1
- package/server/dist/routes/projects.d.ts.map +1 -1
- package/server/dist/routes/projects.js +58 -16
- package/server/dist/routes/projects.js.map +1 -1
- package/server/dist/routes/stack-profiles.d.ts +10 -0
- package/server/dist/routes/stack-profiles.d.ts.map +1 -0
- package/server/dist/routes/stack-profiles.js +65 -0
- package/server/dist/routes/stack-profiles.js.map +1 -0
- package/server/dist/terminal/data-target.d.ts +17 -0
- package/server/dist/terminal/data-target.d.ts.map +1 -0
- package/server/dist/terminal/data-target.js +56 -0
- package/server/dist/terminal/data-target.js.map +1 -0
- package/server/dist/terminal/image-paste.d.ts +2 -0
- package/server/dist/terminal/image-paste.d.ts.map +1 -1
- package/server/dist/terminal/image-paste.js +11 -12
- package/server/dist/terminal/image-paste.js.map +1 -1
- package/server/dist/terminal/routes.d.ts +5 -0
- package/server/dist/terminal/routes.d.ts.map +1 -1
- package/server/dist/terminal/routes.js +11 -13
- package/server/dist/terminal/routes.js.map +1 -1
- package/server/dist/types/project.d.ts +9 -0
- package/server/dist/types/project.d.ts.map +1 -1
- package/server/dist/types/stack-profile-contract.d.ts +33 -0
- package/server/dist/types/stack-profile-contract.d.ts.map +1 -0
- package/server/dist/types/stack-profile-contract.js +11 -0
- package/server/dist/types/stack-profile-contract.js.map +1 -0
- package/server/package.json +3 -3
- package/client/dist/assets/arc-DoZTTE1N.js +0 -1
- package/client/dist/assets/architectureDiagram-ZJ3FMSHR-DFTG4KtO.js +0 -36
- package/client/dist/assets/blockDiagram-677ZJIJ3-C34UBjOB.js +0 -132
- package/client/dist/assets/c4Diagram-LMCZKHZV-CbqAB1Ou.js +0 -10
- package/client/dist/assets/channel-DBcZw7Kn.js +0 -1
- package/client/dist/assets/chunk-RYQCIY6F-DrWMx37d.js +0 -1
- package/client/dist/assets/chunk-VR4S4FIN-B5eWtesm.js +0 -1
- package/client/dist/assets/classDiagram-OUVF2IWQ-C3Q1V9DU.js +0 -1
- package/client/dist/assets/classDiagram-v2-EOCWNBFH-C3Q1V9DU.js +0 -1
- package/client/dist/assets/dagre-VKFMJZFB-VXOY6IHR.js +0 -4
- package/client/dist/assets/diagram-OA4YK3LP-DRHY5d_c.js +0 -30
- package/client/dist/assets/diagram-WEI45ONY-B87OYR_S.js +0 -41
- package/client/dist/assets/erDiagram-Q63AITRT-DaD7oa9H.js +0 -85
- package/client/dist/assets/flowDiagram-23GEKE2U-GrMVpsea.js +0 -156
- package/client/dist/assets/graph-C9eacEi8.js +0 -1
- package/client/dist/assets/index-CIpLt0ie.js +0 -863
- package/client/dist/assets/index-DGtnTeFd.css +0 -1
- package/client/dist/assets/infoDiagram-FWYZ7A6U-Fi8fQ95G.js +0 -2
- package/client/dist/assets/katex-DkKDou_j.js +0 -257
- package/client/dist/assets/layout-DEXfKzaS.js +0 -1
- package/client/dist/assets/map-Czzmt4hB.js +0 -1
- package/client/dist/assets/mermaid.core-D6w9zlA0.js +0 -314
- package/client/dist/assets/stateDiagram-2N3HPSRC-D3GXIouX.js +0 -1
- package/client/dist/assets/stateDiagram-v2-6OUMAXLB-D3lXe_mJ.js +0 -1
- package/client/dist/assets/swimlanes-5IMT3BWC-PMRQzNhU.js +0 -2
- package/client/dist/assets/swimlanesDiagram-G3AALYLV-DMLbRFiO.js +0 -8
- package/client/dist/assets/xychartDiagram-FW5EYKEG-BEtPvBSU.js +0 -7
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Decision core of GET /tasks/:id/session-file: may this task read this path?
|
|
3
|
+
*
|
|
4
|
+
* project scope — the path lies inside the REGISTERED project root (the client-supplied task cwd is never a root):
|
|
5
|
+
* the existing Smart-Viewer posture (pathGuard + realPathGuard, DO-NOT #10);
|
|
6
|
+
* a symlink that leaves the root is REJECTED, never retried as "session".
|
|
7
|
+
* session scope — outside the root, but THIS session evidences the path
|
|
8
|
+
* (core/session-file/evidence.ts), and so its realpath if that differs.
|
|
9
|
+
*
|
|
10
|
+
* The WebUI is reachable over Tailscale: "any file on the machine" would expose
|
|
11
|
+
* ~/.ssh, tokens and .env, hence the evidence rule plus the sensitive-location
|
|
12
|
+
* denylist. Existence is only disclosed AFTER evidence is proven (an unevidenced
|
|
13
|
+
* path answers 403 whether or not it exists). No directory is ever served.
|
|
14
|
+
*/
|
|
15
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { pathGuard, realPathGuard } from "../path-guard.js";
|
|
18
|
+
import { evidenceKey } from "./evidence.js";
|
|
19
|
+
import { isSensitivePath } from "./sensitive.js";
|
|
20
|
+
const deny = (status, error, detail) => ({ ok: false, status, error, detail });
|
|
21
|
+
export const MAX_PATH_CHARS = 4096;
|
|
22
|
+
const BACKSLASH = String.fromCharCode(92);
|
|
23
|
+
export const WIN_DEVICE = /^(con|prn|aux|nul|com[0-9¹²³]|lpt[0-9¹²³]|conin\$|conout\$)[. ]*(\..*)?$/i;
|
|
24
|
+
/**
|
|
25
|
+
* The registered root that lexically contains `abs`, decided by the shared pathGuard (DO-NOT #10) on the
|
|
26
|
+
* root-relative form: a sibling prefix, `..` hop, other drive (or UNC) all come back !ok. Selection only; the
|
|
27
|
+
* authorising check is realPathGuard below.
|
|
28
|
+
*/
|
|
29
|
+
function containingRoot(roots, abs) {
|
|
30
|
+
return roots.find((r) => pathGuard(r, path.relative(path.resolve(r), abs)).ok);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The guard folds "missing" into symlink_escape. 404 only when the deepest EXISTING ancestor still lies inside the
|
|
34
|
+
* root; a path that hops out through a link answers 400 whether or not its target exists (no existence oracle
|
|
35
|
+
* outside the project, not even through a dangling link).
|
|
36
|
+
*/
|
|
37
|
+
async function classifyProjectMiss(root, realRoot, absolute) {
|
|
38
|
+
let probe = absolute;
|
|
39
|
+
for (;;) {
|
|
40
|
+
try {
|
|
41
|
+
const real = await realpath(probe);
|
|
42
|
+
return realPathGuard(root, real, realRoot).ok ? deny(404, "not_found") : deny(400, "path_traversal", "symlink_escape");
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
// A dangling link (leaf or ancestor) points somewhere we must not describe: treat it as an escape.
|
|
46
|
+
if (await lstat(probe).then((st) => st.isSymbolicLink(), () => false))
|
|
47
|
+
return deny(400, "path_traversal", "symlink_escape");
|
|
48
|
+
const parent = path.dirname(probe);
|
|
49
|
+
const code = err?.code;
|
|
50
|
+
if ((code !== "ENOENT" && code !== "ENOTDIR") || parent === probe)
|
|
51
|
+
return deny(400, "path_traversal", "symlink_escape");
|
|
52
|
+
probe = parent;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function decideSessionFileAccess(args) {
|
|
57
|
+
const { roots, requested } = args;
|
|
58
|
+
if (!requested)
|
|
59
|
+
return deny(400, "path_required");
|
|
60
|
+
if (requested.length > MAX_PATH_CHARS || requested.includes("\0"))
|
|
61
|
+
return deny(400, "invalid_path");
|
|
62
|
+
// UNC / device namespaces would reach network shares and raw devices.
|
|
63
|
+
if (process.platform === "win32" && /^[/\x5c]{2}/.test(requested))
|
|
64
|
+
return deny(400, "invalid_path", "unc_or_device");
|
|
65
|
+
// A foreign drive-letter path is meaningless on a POSIX host (it would resolve as a relative name).
|
|
66
|
+
// (path.win32.isAbsolute is true for "/tmp/x" too, so match the drive-letter form explicitly.)
|
|
67
|
+
if (process.platform !== "win32" && /^[A-Za-z]:([/\\]|$)/.test(requested))
|
|
68
|
+
return deny(400, "invalid_path", "foreign_absolute");
|
|
69
|
+
// Windows device names would make realpath/CreateFileW touch the device itself.
|
|
70
|
+
if (process.platform === "win32" && WIN_DEVICE.test(path.win32.basename(requested.replaceAll("/", BACKSLASH)))) {
|
|
71
|
+
return deny(400, "invalid_path", "device_name");
|
|
72
|
+
}
|
|
73
|
+
let absolute;
|
|
74
|
+
const deviceLike = (p) => process.platform === "win32" && WIN_DEVICE.test(path.win32.basename(p));
|
|
75
|
+
if (path.isAbsolute(requested)) {
|
|
76
|
+
absolute = path.resolve(requested);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Only a relative path needs a project root; an absolute one can still be session-evidenced.
|
|
80
|
+
if (roots.length === 0)
|
|
81
|
+
return deny(400, "project_path_unavailable");
|
|
82
|
+
const g = pathGuard(roots[0], requested);
|
|
83
|
+
if (!g.ok)
|
|
84
|
+
return deny(400, g.reason === "traversal" ? "path_traversal" : g.reason, g.reason);
|
|
85
|
+
absolute = g.absolute;
|
|
86
|
+
}
|
|
87
|
+
if (deviceLike(absolute))
|
|
88
|
+
return deny(400, "invalid_path", "device_name"); // spellings like "COM1\." only surface after resolve
|
|
89
|
+
const root = containingRoot(roots, absolute);
|
|
90
|
+
if (root) {
|
|
91
|
+
let realRoot;
|
|
92
|
+
try {
|
|
93
|
+
realRoot = await realpath(root);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return deny(400, "path_traversal", "symlink_escape");
|
|
97
|
+
}
|
|
98
|
+
// Authorise ONLY the native canonical path (the one safe-read compares against, and the same flavour as
|
|
99
|
+
// realRoot): case, 8.3, subst/mapped-drive and trailing-dot spellings are all judged as the file they really
|
|
100
|
+
// are, through the shared symlink-aware guard (DO-NOT #10, not a re-implementation).
|
|
101
|
+
let canon;
|
|
102
|
+
try {
|
|
103
|
+
canon = await realpath(absolute);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return classifyProjectMiss(root, realRoot, absolute);
|
|
107
|
+
}
|
|
108
|
+
if (!realPathGuard(root, canon, realRoot).ok)
|
|
109
|
+
return deny(400, "path_traversal", "symlink_escape");
|
|
110
|
+
// Unmistakable secret names stay refused even inside a (possibly broad) project root; ordinary project files are untouched.
|
|
111
|
+
const relInRoot = path.relative(realRoot, canon);
|
|
112
|
+
if (relInRoot !== "" && isSensitivePath(relInRoot, "project"))
|
|
113
|
+
return deny(403, "sensitive_location");
|
|
114
|
+
return { ok: true, absolute: canon, scope: "project" };
|
|
115
|
+
}
|
|
116
|
+
// Outside every root: session evidence required. Sensitive locations never qualify.
|
|
117
|
+
if (isSensitivePath(absolute))
|
|
118
|
+
return deny(403, "sensitive_location");
|
|
119
|
+
// Evidence FIRST: an unevidenced path never reaches the filesystem (no network-drive touch, no timing oracle).
|
|
120
|
+
const first = await args.findEvidence([absolute]);
|
|
121
|
+
if (!first.found.has(evidenceKey(absolute))) {
|
|
122
|
+
return deny(403, "path_not_evidenced", first.incomplete ? "evidence_window_truncated" : undefined);
|
|
123
|
+
}
|
|
124
|
+
let real;
|
|
125
|
+
try {
|
|
126
|
+
real = await realpath(absolute);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return deny(404, "not_found");
|
|
130
|
+
}
|
|
131
|
+
// A symlink/junction hop: the session must have named where it really leads.
|
|
132
|
+
if (evidenceKey(real) !== evidenceKey(absolute)) {
|
|
133
|
+
const hop = await args.findEvidence([real]);
|
|
134
|
+
if (!hop.found.has(evidenceKey(real)))
|
|
135
|
+
return deny(403, "path_not_evidenced", "symlink_target");
|
|
136
|
+
}
|
|
137
|
+
// Residual risk (recorded, accepted): a file REPLACED at an evidenced path is served as-is.
|
|
138
|
+
if (isSensitivePath(real))
|
|
139
|
+
return deny(403, "sensitive_location");
|
|
140
|
+
// The real target might sit inside a root that the lexical path did not (a link INTO the project): fine, still evidenced.
|
|
141
|
+
return { ok: true, absolute: real, scope: "session" };
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../../src/core/session-file/access.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AccessArgs, type AccessDecision } from "./access.js";
|
|
2
|
+
/** Served with `?assetOf=`. A frozen literal on purpose: widening it widens what an evidenced page can read. */
|
|
3
|
+
export declare const ASSET_MIME_BY_EXTENSION: Readonly<Record<string, string>>;
|
|
4
|
+
/**
|
|
5
|
+
* A folder too broad to be "the page's own folder": a filesystem root, the home directory or any ancestor of it
|
|
6
|
+
* (the parent of all user profiles), the temp directory itself, or one of the catch-all folders directly under home.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isBroadFolder(dir: string): boolean;
|
|
9
|
+
/** Test hook: forget every memoized owner decision. */
|
|
10
|
+
export declare function resetOwnerMemo(): void;
|
|
11
|
+
export declare function decideAssetAccess(args: AccessArgs & {
|
|
12
|
+
owner: string;
|
|
13
|
+
memoKey?: string;
|
|
14
|
+
}): Promise<AccessDecision>;
|
|
15
|
+
//# sourceMappingURL=asset-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-access.d.ts","sourceRoot":"","sources":["../../../src/core/session-file/asset-access.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAuD,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAGxH,gHAAgH;AAChH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUnE,CAAC;AAWH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQlD;AA4BD,uDAAuD;AACvD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CA0CvH"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Decision core of GET /tasks/:id/session-file?path=<asset>&assetOf=<html page>.
|
|
3
|
+
*
|
|
4
|
+
* A rendered HTML page that lives OUTSIDE the project is served only because the session evidences it
|
|
5
|
+
* (access.ts). Its relative images / stylesheets / fonts are NOT individually named in the transcript, so
|
|
6
|
+
* the per-path evidence rule refuses every one of them and the page renders without pictures. This is the
|
|
7
|
+
* one extra link in that chain: an asset is served when
|
|
8
|
+
* - the owner page itself passes the normal decision (evidenced, not sensitive) and is a .html/.htm file,
|
|
9
|
+
* - the asset is an image / stylesheet / font (ASSET_MIME_BY_EXTENSION) - never a script, page, text or data file,
|
|
10
|
+
* - it lies inside the owner's own directory tree, by its lexical path AND by its realpath (a symlink that
|
|
11
|
+
* leaves the folder is refused), and that folder is not a filesystem root, the home directory or an ancestor of
|
|
12
|
+
* it, the temp directory, or Desktop / Documents / Downloads / Pictures (a page dropped there must not open a
|
|
13
|
+
* whole drive / profile to its images),
|
|
14
|
+
* - no path segment starts with "." (.git, .ssh, .env, hidden folders) and it is not a sensitive location.
|
|
15
|
+
* Existence is disclosed only after the owner's evidence is proven, like the rest of the route. Pure
|
|
16
|
+
* extension + containment checks run before any filesystem access beyond the owner's.
|
|
17
|
+
*/
|
|
18
|
+
import { realpath } from "node:fs/promises";
|
|
19
|
+
import os from "node:os";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { WIN_DEVICE, decideSessionFileAccess, MAX_PATH_CHARS } from "./access.js";
|
|
22
|
+
import { isSensitivePath } from "./sensitive.js";
|
|
23
|
+
/** Served with `?assetOf=`. A frozen literal on purpose: widening it widens what an evidenced page can read. */
|
|
24
|
+
export const ASSET_MIME_BY_EXTENSION = Object.freeze({
|
|
25
|
+
png: "image/png",
|
|
26
|
+
jpg: "image/jpeg",
|
|
27
|
+
jpeg: "image/jpeg",
|
|
28
|
+
gif: "image/gif",
|
|
29
|
+
webp: "image/webp",
|
|
30
|
+
svg: "image/svg+xml",
|
|
31
|
+
css: "text/plain; charset=utf-8",
|
|
32
|
+
woff: "font/woff",
|
|
33
|
+
woff2: "font/woff2",
|
|
34
|
+
});
|
|
35
|
+
const deny = (status, error) => ({ ok: false, status, error });
|
|
36
|
+
const BACKSLASH = String.fromCharCode(92);
|
|
37
|
+
const HTML_PAGE = /\.html?$/i;
|
|
38
|
+
const within = (rel) => rel !== "" && rel !== ".." && !rel.startsWith(".." + path.sep) && !path.isAbsolute(rel);
|
|
39
|
+
/** Catch-all folders directly under the home directory: a page dropped there must not open everything below it. */
|
|
40
|
+
const BROAD_HOME_CHILDREN = new Set(["desktop", "documents", "downloads", "pictures", "onedrive", "dropbox"]);
|
|
41
|
+
/**
|
|
42
|
+
* A folder too broad to be "the page's own folder": a filesystem root, the home directory or any ancestor of it
|
|
43
|
+
* (the parent of all user profiles), the temp directory itself, or one of the catch-all folders directly under home.
|
|
44
|
+
*/
|
|
45
|
+
export function isBroadFolder(dir) {
|
|
46
|
+
if (path.parse(dir).root === dir)
|
|
47
|
+
return true;
|
|
48
|
+
const home = os.homedir();
|
|
49
|
+
const homeFromDir = path.relative(dir, home);
|
|
50
|
+
if (homeFromDir === "" || within(homeFromDir))
|
|
51
|
+
return true; // dir is home, or home lies below it
|
|
52
|
+
if (path.relative(dir, os.tmpdir()) === "")
|
|
53
|
+
return true;
|
|
54
|
+
const fromHome = path.relative(home, dir);
|
|
55
|
+
return within(fromHome) && !fromHome.includes(path.sep) && BROAD_HOME_CHILDREN.has(fromHome.toLowerCase());
|
|
56
|
+
}
|
|
57
|
+
const hasDotSegment = (rel) => rel.split(path.sep).some((seg) => seg.startsWith("."));
|
|
58
|
+
/**
|
|
59
|
+
* The owner page's evidence decision is the expensive part (an uncached, process-serialized transcript scan) and a page
|
|
60
|
+
* with many images asks for it once per image. A short-lived memo of POSITIVE decisions, shared by a burst of requests
|
|
61
|
+
* (the in-flight promise is stored, so concurrent requests join it), keeps that to one scan. Evidence in an append-only
|
|
62
|
+
* transcript is never withdrawn; a failed decision is never kept, so the next request re-checks.
|
|
63
|
+
*/
|
|
64
|
+
const OWNER_TTL_MS = 15_000;
|
|
65
|
+
const OWNER_MEMO_MAX = 64;
|
|
66
|
+
const ownerMemo = new Map();
|
|
67
|
+
function decideOwner(args) {
|
|
68
|
+
const run = () => decideSessionFileAccess({ roots: args.roots, requested: args.owner, findEvidence: args.findEvidence });
|
|
69
|
+
const key = args.memoKey ? `${args.memoKey}\0${args.owner}` : null;
|
|
70
|
+
if (!key)
|
|
71
|
+
return run();
|
|
72
|
+
const hit = ownerMemo.get(key);
|
|
73
|
+
if (hit && Date.now() - hit.at < OWNER_TTL_MS)
|
|
74
|
+
return hit.decision;
|
|
75
|
+
const decision = run();
|
|
76
|
+
if (ownerMemo.size >= OWNER_MEMO_MAX)
|
|
77
|
+
ownerMemo.delete(ownerMemo.keys().next().value);
|
|
78
|
+
ownerMemo.set(key, { at: Date.now(), decision });
|
|
79
|
+
void decision.then((d) => {
|
|
80
|
+
if (!d.ok && ownerMemo.get(key)?.decision === decision)
|
|
81
|
+
ownerMemo.delete(key);
|
|
82
|
+
}, () => ownerMemo.delete(key));
|
|
83
|
+
return decision;
|
|
84
|
+
}
|
|
85
|
+
/** Test hook: forget every memoized owner decision. */
|
|
86
|
+
export function resetOwnerMemo() {
|
|
87
|
+
ownerMemo.clear();
|
|
88
|
+
}
|
|
89
|
+
export async function decideAssetAccess(args) {
|
|
90
|
+
const { requested, owner } = args;
|
|
91
|
+
if (!requested)
|
|
92
|
+
return deny(400, "path_required");
|
|
93
|
+
if (requested.length > MAX_PATH_CHARS || requested.includes("\0") || owner.length > MAX_PATH_CHARS || owner.includes("\0")) {
|
|
94
|
+
return deny(400, "invalid_path");
|
|
95
|
+
}
|
|
96
|
+
const ext = path.extname(requested).toLowerCase().slice(1);
|
|
97
|
+
if (!Object.hasOwn(ASSET_MIME_BY_EXTENSION, ext))
|
|
98
|
+
return deny(403, "asset_type_not_allowed");
|
|
99
|
+
if (!path.isAbsolute(owner) || !HTML_PAGE.test(owner))
|
|
100
|
+
return deny(403, "asset_owner_invalid");
|
|
101
|
+
if (!path.isAbsolute(requested))
|
|
102
|
+
return deny(403, "asset_outside_page_folder");
|
|
103
|
+
// UNC / device namespaces would reach network shares and raw devices.
|
|
104
|
+
if (process.platform === "win32" && (/^[/\x5c]{2}/.test(requested) || WIN_DEVICE.test(path.win32.basename(requested.replaceAll("/", BACKSLASH))))) {
|
|
105
|
+
return deny(400, "invalid_path");
|
|
106
|
+
}
|
|
107
|
+
// An NTFS alternate data stream (`notes.txt:evil.png`) would pass the extension check: no ':' after the drive letter.
|
|
108
|
+
if (process.platform === "win32" && requested.replace(/^[a-zA-Z]:/, "").includes(":"))
|
|
109
|
+
return deny(400, "invalid_path");
|
|
110
|
+
const page = await decideOwner(args);
|
|
111
|
+
if (!page.ok)
|
|
112
|
+
return page;
|
|
113
|
+
const pageDir = path.dirname(page.absolute); // already a realpath
|
|
114
|
+
if (isBroadFolder(pageDir))
|
|
115
|
+
return deny(403, "asset_page_folder_too_broad");
|
|
116
|
+
const abs = path.resolve(requested);
|
|
117
|
+
// The requested spelling is the client's lexical one: when the page's folder is reached through a symlink / junction
|
|
118
|
+
// / subst drive it differs from the realpath `pageDir`, so either spelling of the folder may contain it. The
|
|
119
|
+
// authority is the realpath containment below.
|
|
120
|
+
let lexical = path.relative(pageDir, abs);
|
|
121
|
+
if (!within(lexical))
|
|
122
|
+
lexical = path.relative(path.dirname(path.resolve(owner)), abs);
|
|
123
|
+
if (!within(lexical))
|
|
124
|
+
return deny(403, "asset_outside_page_folder");
|
|
125
|
+
if (hasDotSegment(lexical))
|
|
126
|
+
return deny(403, "asset_hidden_path");
|
|
127
|
+
let real;
|
|
128
|
+
try {
|
|
129
|
+
real = await realpath(abs);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return deny(404, "not_found");
|
|
133
|
+
}
|
|
134
|
+
const actual = path.relative(pageDir, real);
|
|
135
|
+
if (!within(actual))
|
|
136
|
+
return deny(403, "asset_outside_page_folder");
|
|
137
|
+
if (hasDotSegment(actual) || isSensitivePath(real))
|
|
138
|
+
return deny(403, "sensitive_location");
|
|
139
|
+
return { ok: true, absolute: real, scope: "session" };
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=asset-access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-access.js","sourceRoot":"","sources":["../../../src/core/session-file/asset-access.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type SessionInfoDeps } from "../session-info/session-info.js";
|
|
2
|
+
import type { JsonlLocation } from "../session-watcher.js";
|
|
3
|
+
/** Comparison key: Windows paths are case-insensitive and may use either slash. */
|
|
4
|
+
export declare const evidenceKey: (p: string) => string;
|
|
5
|
+
/** True when `hay` names `needle` as a complete path (see file header). */
|
|
6
|
+
export declare function mentionsWholePath(hay: string, needle: string): boolean;
|
|
7
|
+
export interface EvidenceDeps {
|
|
8
|
+
infoDeps?: SessionInfoDeps;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The subset of `candidates` (absolute paths) this session evidences (as
|
|
12
|
+
* evidenceKey()s), plus whether the search window was incomplete. The window is
|
|
13
|
+
* the newest SESSION_SCAN_BYTES (48 MB) of the session file; older mentions are
|
|
14
|
+
* a documented false negative (fail closed), reported as `incomplete` so the
|
|
15
|
+
* caller can tell "not evidenced" from "not searched". An unreadable/missing
|
|
16
|
+
* session evidences nothing. Evidence is bound to ONE session: the task's own
|
|
17
|
+
* sessionUuid, located by the watcher — no other transcript is ever consulted.
|
|
18
|
+
*/
|
|
19
|
+
export interface EvidenceResult {
|
|
20
|
+
found: Set<string>;
|
|
21
|
+
/** The transcript was larger than the scan window: older history was NOT searched. */
|
|
22
|
+
incomplete: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function findSessionEvidence(sessionUuid: string, loc: JsonlLocation | null, candidates: string[], deps?: EvidenceDeps): Promise<EvidenceResult>;
|
|
25
|
+
//# sourceMappingURL=evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../../src/core/session-file/evidence.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAuC,KAAK,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC5G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D,mFAAmF;AACnF,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,KAAG,MAAyD,CAAC;AAWlG,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAetE;AAyDD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,sFAAsF;IACtF,UAAU,EAAE,OAAO,CAAC;CACrB;AAaD,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,aAAa,GAAG,IAAI,EACzB,UAAU,EAAE,MAAM,EAAE,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,cAAc,CAAC,CAgBzB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Session evidence for GET /tasks/:id/session-file: which absolute paths did
|
|
3
|
+
* THIS session itself touch or name? A path is evidenced when
|
|
4
|
+
* 1. it is an Output (Write/Edit/NotebookEdit/MultiEdit target, incl. its
|
|
5
|
+
* subagents) per core/session-info, or
|
|
6
|
+
* 2. it is named, as a whole path, in a chat text block or in a tool_use
|
|
7
|
+
* input of the session JSONL.
|
|
8
|
+
* tool_result bodies, attachments and thinking are NEVER evidence: they quote
|
|
9
|
+
* arbitrary file content and command output, not the session's intent.
|
|
10
|
+
*
|
|
11
|
+
* Stateless (CLAUDE.md rule 4): every call is a fresh bounded positional scan
|
|
12
|
+
* via scanLines; the only cache is session-info's pure per-file memo.
|
|
13
|
+
* Read-only (DO-NOT #1). A whole-path match means the char before is not a path
|
|
14
|
+
* character and the char after does not continue the path, so a mention of a
|
|
15
|
+
* directory never evidences its children and `/a/b` never evidences `/a/b.txt`.
|
|
16
|
+
*/
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { scanLines } from "../session-info/line-scan.js";
|
|
19
|
+
import { SESSION_SCAN_BYTES, readSessionInfo } from "../session-info/session-info.js";
|
|
20
|
+
const CI = process.platform === "win32";
|
|
21
|
+
/** Comparison key: Windows paths are case-insensitive and may use either slash. */
|
|
22
|
+
export const evidenceKey = (p) => (CI ? p.replace(/\//g, "\\").toLowerCase() : p);
|
|
23
|
+
// Before-set: '=' is left out on purpose so `--out=/x/y.md` still evidences /x/y.md.
|
|
24
|
+
// ')' '}' '*' ':' end shell expressions / remote specs (`$(pwd)/x`, `host:/x`): the path after them is a suffix, not a mention.
|
|
25
|
+
const BEFORE_BAD = /[\p{L}\p{N}_\-./\x5c~+@%#$)}*:]/u;
|
|
26
|
+
// '~', '+', '@', '%', '#', '$', '=' are valid filename characters: they continue a path, never end it.
|
|
27
|
+
// (A space inside a quoted filename stays ambiguous; the extension allowlist bounds that residual.)
|
|
28
|
+
const AFTER_BAD = /[\p{L}\p{N}_\-/\x5c~+@%#$=]/u;
|
|
29
|
+
const MAX_STRINGS_PER_LINE = 2000;
|
|
30
|
+
const MAX_DEPTH = 8;
|
|
31
|
+
/** True when `hay` names `needle` as a complete path (see file header). */
|
|
32
|
+
export function mentionsWholePath(hay, needle) {
|
|
33
|
+
if (!needle)
|
|
34
|
+
return false;
|
|
35
|
+
const h = CI ? hay.replace(/\//g, "\\").toLowerCase() : hay;
|
|
36
|
+
const n = evidenceKey(needle);
|
|
37
|
+
for (let i = h.indexOf(n); i !== -1; i = h.indexOf(n, i + 1)) {
|
|
38
|
+
const before = i > 0 ? h[i - 1] : "";
|
|
39
|
+
if (before && BEFORE_BAD.test(before))
|
|
40
|
+
continue;
|
|
41
|
+
const end = i + n.length;
|
|
42
|
+
const after = h[end] ?? "";
|
|
43
|
+
if (after && AFTER_BAD.test(after))
|
|
44
|
+
continue;
|
|
45
|
+
// A '.' ends a sentence, unless it starts an extension ("a.txt" vs "a.txt.bak").
|
|
46
|
+
if (after === "." && h[end + 1] !== undefined && AFTER_BAD.test(h[end + 1]))
|
|
47
|
+
continue;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
function collectStrings(v, out, depth = 0) {
|
|
53
|
+
if (out.length >= MAX_STRINGS_PER_LINE || depth > MAX_DEPTH)
|
|
54
|
+
return;
|
|
55
|
+
if (typeof v === "string")
|
|
56
|
+
out.push(v);
|
|
57
|
+
else if (Array.isArray(v))
|
|
58
|
+
for (const x of v)
|
|
59
|
+
collectStrings(x, out, depth + 1);
|
|
60
|
+
else if (v && typeof v === "object")
|
|
61
|
+
for (const x of Object.values(v))
|
|
62
|
+
collectStrings(x, out, depth + 1);
|
|
63
|
+
}
|
|
64
|
+
// Command output AND harness-generated wrappers the CLI echoes into user records: none of it is something the
|
|
65
|
+
// user typed or the assistant chose to name (a file or background agent could smuggle a path through them).
|
|
66
|
+
const OUTPUT_SECTIONS = [
|
|
67
|
+
"bash-stdout", "bash-stderr", "local-command-stdout", "local-command-stderr", "command-stdout", "command-stderr",
|
|
68
|
+
"system-reminder", "task-notification", "user-prompt-submit-hook", "tool-use-error",
|
|
69
|
+
];
|
|
70
|
+
/** Drop `<name>…</name>` sections (command output echoed into user records) by plain string search. */
|
|
71
|
+
function stripSections(text, names) {
|
|
72
|
+
let out = text;
|
|
73
|
+
for (const name of names) {
|
|
74
|
+
const open = `<${name}>`;
|
|
75
|
+
const close = `</${name}>`;
|
|
76
|
+
for (let s = out.indexOf(open); s !== -1; s = out.indexOf(open)) {
|
|
77
|
+
const e = out.indexOf(close, s);
|
|
78
|
+
out = out.slice(0, s) + (e === -1 ? "" : out.slice(e + close.length));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
/** Text a user could have SEEN or the assistant DID: chat text + tool_use inputs. Never command output or injected meta. */
|
|
84
|
+
function evidenceStrings(rec) {
|
|
85
|
+
if (rec.type !== "user" && rec.type !== "assistant")
|
|
86
|
+
return [];
|
|
87
|
+
if (rec.isMeta === true || rec.isCompactSummary === true)
|
|
88
|
+
return [];
|
|
89
|
+
// A user record that answers a tool call (or carries its structured result) is tool output, not a prompt.
|
|
90
|
+
if (rec.type === "user" && (rec.toolUseResult !== undefined || rec.sourceToolUseID !== undefined))
|
|
91
|
+
return [];
|
|
92
|
+
const msg = rec.message;
|
|
93
|
+
const content = msg?.content;
|
|
94
|
+
const out = [];
|
|
95
|
+
if (typeof content === "string")
|
|
96
|
+
out.push(stripSections(content, OUTPUT_SECTIONS));
|
|
97
|
+
else if (Array.isArray(content)) {
|
|
98
|
+
for (const b of content) {
|
|
99
|
+
if (!b || typeof b !== "object")
|
|
100
|
+
continue;
|
|
101
|
+
if (b.type === "text" && typeof b.text === "string")
|
|
102
|
+
out.push(stripSections(b.text, OUTPUT_SECTIONS));
|
|
103
|
+
else if (b.type === "tool_use")
|
|
104
|
+
collectStrings(b.input, out);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
/** Cheap raw-line pre-filter token: the basename, unless JSON could have escaped it. */
|
|
110
|
+
function prefilterToken(candidate) {
|
|
111
|
+
const base = path.win32.basename(candidate.replace(/\//g, "\\"));
|
|
112
|
+
if (!base || [...base].some((ch) => ch === '"' || ch === "\x5c" || ch.charCodeAt(0) < 32))
|
|
113
|
+
return null;
|
|
114
|
+
return CI ? base.toLowerCase() : base;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Scans are serialized process-wide: each is synchronous JSON work over up to 48 MB, and a burst of
|
|
118
|
+
* concurrent requests must queue rather than starve the event loop (terminal WS, transcript polls).
|
|
119
|
+
* A promise chain, not a cache - nothing is remembered between requests (CLAUDE.md rule 4).
|
|
120
|
+
*/
|
|
121
|
+
let scanQueue = Promise.resolve();
|
|
122
|
+
const SCAN_TIMEOUT_MS = 20_000;
|
|
123
|
+
const MAX_PENDING_SCANS = 8;
|
|
124
|
+
let pendingScans = 0;
|
|
125
|
+
export function findSessionEvidence(sessionUuid, loc, candidates, deps = {}) {
|
|
126
|
+
// Bounded backlog: a burst of unevidenced requests must not queue unbounded full scans (fail closed, incomplete).
|
|
127
|
+
if (pendingScans >= MAX_PENDING_SCANS)
|
|
128
|
+
return Promise.resolve({ found: new Set(), incomplete: true });
|
|
129
|
+
pendingScans++;
|
|
130
|
+
const release = () => {
|
|
131
|
+
pendingScans--;
|
|
132
|
+
};
|
|
133
|
+
// The backlog slot is held until the scan itself has stopped, not merely until the caller stopped waiting
|
|
134
|
+
// (a timed-out scan keeps running, so releasing on timeout would let stalled scans pile up past the cap).
|
|
135
|
+
const run = scanQueue.then(() => {
|
|
136
|
+
const scan = scanForEvidence(sessionUuid, loc, candidates, deps);
|
|
137
|
+
void scan.then(release, release);
|
|
138
|
+
return withTimeout(scan);
|
|
139
|
+
});
|
|
140
|
+
scanQueue = run.catch(() => undefined);
|
|
141
|
+
return run;
|
|
142
|
+
}
|
|
143
|
+
/** A stalled read must not hold the queue forever: give up (fail closed, incomplete) and move on. */
|
|
144
|
+
function withTimeout(p) {
|
|
145
|
+
let timer;
|
|
146
|
+
const timeout = new Promise((resolve) => {
|
|
147
|
+
timer = setTimeout(() => resolve({ found: new Set(), incomplete: true }), SCAN_TIMEOUT_MS);
|
|
148
|
+
});
|
|
149
|
+
return Promise.race([p, timeout]).finally(() => clearTimeout(timer));
|
|
150
|
+
}
|
|
151
|
+
async function scanForEvidence(sessionUuid, loc, candidates, deps) {
|
|
152
|
+
const found = new Set();
|
|
153
|
+
let incomplete = false;
|
|
154
|
+
if (!loc || candidates.length === 0)
|
|
155
|
+
return { found, incomplete };
|
|
156
|
+
const wanted = new Map(candidates.map((c) => [evidenceKey(c), c]));
|
|
157
|
+
try {
|
|
158
|
+
const info = await readSessionInfo(sessionUuid, loc, deps.infoDeps);
|
|
159
|
+
for (const o of info.outputs)
|
|
160
|
+
if (wanted.has(evidenceKey(o.path)))
|
|
161
|
+
found.add(evidenceKey(o.path));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* fall through to the raw scan; never widen access on error */
|
|
165
|
+
}
|
|
166
|
+
const tokens = candidates.map(prefilterToken);
|
|
167
|
+
const pending = () => candidates.filter((c) => !found.has(evidenceKey(c)));
|
|
168
|
+
const onLine = (line) => {
|
|
169
|
+
if (pending().length === 0)
|
|
170
|
+
return;
|
|
171
|
+
if (!line.includes('"user"') && !line.includes('"assistant"'))
|
|
172
|
+
return;
|
|
173
|
+
const probe = CI ? line.toLowerCase() : line;
|
|
174
|
+
const live = candidates.filter((c, i) => !found.has(evidenceKey(c)) && (tokens[i] === null || probe.includes(tokens[i])));
|
|
175
|
+
if (live.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
let rec;
|
|
178
|
+
try {
|
|
179
|
+
const parsed = JSON.parse(line);
|
|
180
|
+
if (!parsed || typeof parsed !== "object")
|
|
181
|
+
return;
|
|
182
|
+
rec = parsed;
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const strings = evidenceStrings(rec);
|
|
188
|
+
for (const c of live)
|
|
189
|
+
if (strings.some((s) => mentionsWholePath(s, c)))
|
|
190
|
+
found.add(evidenceKey(c));
|
|
191
|
+
};
|
|
192
|
+
try {
|
|
193
|
+
incomplete = (await scanLines(loc.path, SESSION_SCAN_BYTES, onLine)).truncated;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
/* unreadable session: only what structured outputs already proved */
|
|
197
|
+
incomplete = true;
|
|
198
|
+
}
|
|
199
|
+
return { found, incomplete };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../../src/core/session-file/evidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type AccessArgs } from "./access.js";
|
|
2
|
+
export declare const MAX_PROBE_PATHS = 40;
|
|
3
|
+
export type ProbeReason = "not_found" | "not_a_file" | "not_previewable" | "unavailable";
|
|
4
|
+
export interface ProbeResult {
|
|
5
|
+
openable: boolean;
|
|
6
|
+
reason?: ProbeReason;
|
|
7
|
+
}
|
|
8
|
+
export interface ProbeArgs extends Pick<AccessArgs, "roots" | "findEvidence"> {
|
|
9
|
+
paths: string[];
|
|
10
|
+
/** The viewer can only render allow-listed types (same MIME allowlist as the read route). */
|
|
11
|
+
/** The Viewer refuses files above this size (413); probe them as not openable too. */
|
|
12
|
+
maxBytes?: number;
|
|
13
|
+
previewable: (absolute: string) => boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function probeOpenable(args: ProbeArgs): Promise<ProbeResult[]>;
|
|
16
|
+
//# sourceMappingURL=probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/core/session-file/probe.ts"],"names":[],"mappings":"AAaA,OAAO,EAA2C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAIvF,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,aAAa,CAAC;AACzF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,cAAc,CAAC;IAC3E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6FAA6F;IAC7F,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C;AAyBD,wBAAsB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAsB3E"}
|