@remnic/core 9.54.5 → 9.54.7
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/dist/access-admin-ops-surface.d.ts +24 -24
- package/dist/access-admin-ops-surface.js +32 -29
- package/dist/access-authorization-probe.d.ts +25 -23
- package/dist/access-authorization-probe.js +35 -30
- package/dist/access-boundary.d.ts +26 -24
- package/dist/access-boundary.js +36 -31
- package/dist/access-cli.js +86 -80
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +19 -19
- package/dist/access-extraction-force-flush.js +32 -29
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +22 -22
- package/dist/access-http-lifecycle-flush.d.ts +22 -22
- package/dist/access-http-offline-stream.d.ts +18 -18
- package/dist/access-http-query.js +32 -29
- package/dist/access-http.d.ts +55 -37
- package/dist/access-http.js +52 -43
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +32 -29
- package/dist/access-lcm-surface.d.ts +21 -21
- package/dist/access-lcm-surface.js +32 -29
- package/dist/access-mcp.d.ts +22 -22
- package/dist/access-mcp.js +40 -36
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-BdHlGd_T.d.ts → access-namespace-preflight-CCNn_6NE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +32 -29
- package/dist/access-observe-write-surface.d.ts +22 -22
- package/dist/access-observe-write-surface.js +32 -29
- package/dist/access-offline-manifest.d.ts +9 -9
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +34 -31
- package/dist/access-operations.d.ts +23 -23
- package/dist/access-operations.js +38 -34
- package/dist/access-recall-concurrency.d.ts +21 -21
- package/dist/access-recall-concurrency.js +32 -29
- package/dist/access-recall-response.d.ts +19 -19
- package/dist/access-recall-response.js +32 -29
- package/dist/access-recall-surface.d.ts +19 -19
- package/dist/access-recall-surface.js +32 -29
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-DL7X9hrg.d.ts → access-service-DK82xdNi.d.ts} +1314 -83
- package/dist/access-service-helpers.d.ts +22 -22
- package/dist/access-service.d.ts +31 -31
- package/dist/access-service.js +32 -29
- package/dist/access-surface-catalog.d.ts +22 -22
- package/dist/access-surface-catalog.js +209 -2
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +6 -5
- package/dist/active-memory-bridge.js +2 -2
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -1
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/admin-console/public/what-helps-me/app.js +1594 -0
- package/dist/admin-console/public/what-helps-me/index.html +339 -0
- package/dist/admin-console/public/what-helps-me/model.js +685 -0
- package/dist/admin-console/public/what-helps-me/what-helps-me.css +1296 -0
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/{auto-sync-TDHLZPVP.js → auto-sync-NR3GPCOA.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +14 -14
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/buffer.js +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-B90is4d8.d.ts → catalog-DGFf8mD9.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +15 -15
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-CSY44OKU.js → chunk-26ZXBTYN.js} +4 -4
- package/dist/chunk-26ZXBTYN.js.map +1 -0
- package/dist/{chunk-LLJMAULE.js → chunk-2FKEIPIT.js} +5 -5
- package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
- package/dist/chunk-37DZZFFM.js +502 -0
- package/dist/chunk-37DZZFFM.js.map +1 -0
- package/dist/chunk-3HSRWJTC.js +9 -0
- package/dist/chunk-3HSRWJTC.js.map +1 -0
- package/dist/{chunk-TKFGFDPJ.js → chunk-3TIZPSJC.js} +4 -4
- package/dist/{chunk-B4T3FQMT.js → chunk-43SEBY2M.js} +1 -1
- package/dist/{chunk-LVKYLMSM.js → chunk-46SZBVDS.js} +2 -2
- package/dist/{chunk-YKZLOPTC.js → chunk-5FD7JMTX.js} +2 -2
- package/dist/{chunk-2PNXOQ4P.js → chunk-5NB726GV.js} +3 -7
- package/dist/chunk-5NB726GV.js.map +1 -0
- package/dist/chunk-62OKGIJA.js +39 -0
- package/dist/chunk-62OKGIJA.js.map +1 -0
- package/dist/{chunk-WM5LD6AT.js → chunk-6CYHUWCO.js} +2 -2
- package/dist/{chunk-BIF4SHMD.js → chunk-76JJSXK7.js} +1 -1
- package/dist/chunk-76JJSXK7.js.map +1 -0
- package/dist/{chunk-3SXLD5T3.js → chunk-7BD6O7ZV.js} +189 -4
- package/dist/chunk-7BD6O7ZV.js.map +1 -0
- package/dist/chunk-7TBXNYLO.js +346 -0
- package/dist/chunk-7TBXNYLO.js.map +1 -0
- package/dist/{chunk-YR65W7BV.js → chunk-BRR5EUTF.js} +3 -3
- package/dist/{chunk-JKW663ZN.js → chunk-CIAI24TQ.js} +2 -2
- package/dist/{chunk-3WGI7F4V.js → chunk-D3LBIUWV.js} +9219 -5233
- package/dist/chunk-D3LBIUWV.js.map +1 -0
- package/dist/{chunk-YDWPYDML.js → chunk-EKTP7MNS.js} +4 -4
- package/dist/{chunk-6LEIWWAF.js → chunk-F2JRDPON.js} +2 -2
- package/dist/{chunk-VYQ4URQB.js → chunk-FFRTNF3L.js} +2 -2
- package/dist/{chunk-TY6MKIWP.js → chunk-FONWBCVY.js} +3 -3
- package/dist/{chunk-XSV2YDCJ.js → chunk-FPLM2TKD.js} +2 -2
- package/dist/{chunk-VTU5IEKY.js → chunk-FTPONF6B.js} +2 -2
- package/dist/{chunk-6PZGKGAO.js → chunk-FWX7W5PM.js} +2 -2
- package/dist/{chunk-QPW3PAIH.js → chunk-G6DFSS6A.js} +2 -2
- package/dist/{chunk-2DD6ZHOM.js → chunk-GJ776BC2.js} +3 -3
- package/dist/{chunk-XKAR4RF6.js → chunk-GN3WRFJY.js} +6 -6
- package/dist/{chunk-RG426DJO.js → chunk-H7NAZ3UB.js} +2 -2
- package/dist/{chunk-BSXGTDVJ.js → chunk-HBUFQRIM.js} +2 -2
- package/dist/{chunk-FFEBSFVT.js → chunk-HGJ6NJ4E.js} +2 -2
- package/dist/{chunk-WB7JSQCP.js → chunk-HIEWDJ2O.js} +5 -2
- package/dist/{chunk-WB7JSQCP.js.map → chunk-HIEWDJ2O.js.map} +1 -1
- package/dist/{chunk-QTO6BMQZ.js → chunk-I3MSGFGD.js} +17 -6
- package/dist/chunk-I3MSGFGD.js.map +1 -0
- package/dist/{chunk-5JKUSBMX.js → chunk-IKP5OYQQ.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-DBY26JJJ.js → chunk-IQ4NVWEF.js} +2 -2
- package/dist/{chunk-7Q7JWLQ4.js → chunk-JYG4OLWH.js} +2 -2
- package/dist/{chunk-3OTSVCPK.js → chunk-K26NWEOC.js} +4 -4
- package/dist/{chunk-WZWZRZ2V.js → chunk-K2UGPTYY.js} +484 -43
- package/dist/chunk-K2UGPTYY.js.map +1 -0
- package/dist/{chunk-L6CQ7WIW.js → chunk-KFBOPMF6.js} +11 -11
- package/dist/chunk-KFBOPMF6.js.map +1 -0
- package/dist/{chunk-HOIRB77A.js → chunk-L6Z5OAS4.js} +2 -2
- package/dist/{chunk-7RZJWZ46.js → chunk-LEPOP46W.js} +5 -5
- package/dist/{chunk-QQXWFDRD.js → chunk-M4YHAODQ.js} +270 -684
- package/dist/chunk-M4YHAODQ.js.map +1 -0
- package/dist/{chunk-NGT35IGQ.js → chunk-MIH3CJPN.js} +3 -3
- package/dist/{chunk-QPAQSG3F.js → chunk-MK5VEWCR.js} +2 -2
- package/dist/chunk-NISZQW72.js +140 -0
- package/dist/chunk-NISZQW72.js.map +1 -0
- package/dist/{chunk-L7RTUEDG.js → chunk-OCIP6YMD.js} +2 -2
- package/dist/{chunk-2INWPC6E.js → chunk-PG4QBPVG.js} +20 -10
- package/dist/chunk-PG4QBPVG.js.map +1 -0
- package/dist/{chunk-DDA55IVB.js → chunk-PT54WISF.js} +189 -55
- package/dist/chunk-PT54WISF.js.map +1 -0
- package/dist/{chunk-UWJNKGBA.js → chunk-QZLDRQ4I.js} +5 -5
- package/dist/{chunk-UYOXFFEY.js → chunk-RUNORG2P.js} +3 -3
- package/dist/{chunk-LC3FD4BV.js → chunk-RZQ6W2W4.js} +39 -39
- package/dist/{chunk-MRGJZ75M.js → chunk-SMNYAMJD.js} +3 -3
- package/dist/{chunk-MKQBXQKU.js → chunk-TB6CBZ5V.js} +22 -15
- package/dist/chunk-TB6CBZ5V.js.map +1 -0
- package/dist/{chunk-DN2IDKI5.js → chunk-TO7ZTWJW.js} +2 -2
- package/dist/{chunk-K2TDK7GG.js → chunk-TWTUGCTY.js} +2 -2
- package/dist/{chunk-CUTFSLSD.js → chunk-UCTS3DDH.js} +2 -2
- package/dist/{chunk-JYIJNNN3.js → chunk-UG6VXIOK.js} +2 -2
- package/dist/{chunk-QOQQMVR2.js → chunk-UKYS3NU5.js} +2 -2
- package/dist/{chunk-VZRFGJCH.js → chunk-UPLZNJKN.js} +2 -2
- package/dist/{chunk-C23BYTJV.js → chunk-UW5NPZJ2.js} +40 -12
- package/dist/chunk-UW5NPZJ2.js.map +1 -0
- package/dist/{chunk-DOOWFDWN.js → chunk-V6ERBR7U.js} +2 -2
- package/dist/{chunk-7HG7MGAP.js → chunk-W5ZKPI34.js} +462 -2673
- package/dist/chunk-W5ZKPI34.js.map +1 -0
- package/dist/{chunk-HNDIND7P.js → chunk-XX4HPFFM.js} +54 -15
- package/dist/chunk-XX4HPFFM.js.map +1 -0
- package/dist/{chunk-N7CXQ5TA.js → chunk-XZHE2DEN.js} +1 -1
- package/dist/chunk-YXQEKCZM.js +223 -0
- package/dist/chunk-YXQEKCZM.js.map +1 -0
- package/dist/{chunk-6NNNURLK.js → chunk-Z54EM5YZ.js} +4 -4
- package/dist/{chunk-F2Y6I74C.js → chunk-ZRZVLB7O.js} +2 -2
- package/dist/{chunk-CLKBV3Z3.js → chunk-ZUKIUXHQ.js} +9 -9
- package/dist/{cli-jfuZXixq.d.ts → cli-BPDUXnAl.d.ts} +5 -5
- package/dist/cli.d.ts +22 -22
- package/dist/cli.js +66 -58
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +14 -14
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +14 -14
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +14 -14
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-KCADHXPE.js → contradiction-scan-JDTBXRGW.js} +3 -3
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +16 -16
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +16 -16
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-CTDuAVJc.d.ts → dependency-propagation-delivery-CzEfB31P.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/explicit-capture.js +4 -3
- package/dist/external-wiki-access.d.ts +22 -22
- package/dist/external-wiki-access.js +33 -30
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +22 -22
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-judge.js +2 -2
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +20 -20
- package/dist/fallback-llm.d.ts +14 -1
- package/dist/fallback-llm.js +1 -1
- package/dist/{first-start-migration-LMMZFLKK.js → first-start-migration-CRZCZAJN.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +30 -747
- package/dist/index.js +203 -118
- package/dist/inline-script.d.ts +3 -0
- package/dist/inline-script.js +8 -0
- package/dist/inline-script.js.map +1 -0
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/{maintenance-heMZSq7G.d.ts → maintenance-C8aRWfhq.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +22 -22
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +15 -15
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +14 -14
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +23 -22
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/{orchestrator-BQQPsSjs.d.ts → orchestrator-D85CzDDY.d.ts} +8 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +86 -80
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-DFfmsnGk.d.ts → pipeline-DPcUifCO.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/public-http-D3GBeII4.d.ts +25 -0
- package/dist/{qmd-BF5bcVRs.d.ts → qmd-dFCHp1r0.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -2
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-CbUOsE_E.d.ts → scope-profiles-DICK7GtN.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +5 -5
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -9
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-DAB3xdKM.d.ts → semantic-consolidation-BP7NAX0N.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +15 -15
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/{service-DGKg2O6r.d.ts → service-DT-pJyda.d.ts} +660 -660
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +16 -16
- package/dist/{storage-CC1jKcWg.d.ts → storage-qOnaJ1Lw.d.ts} +4 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +13 -13
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +518 -0
- package/dist/support-passport/index.js +357 -0
- package/dist/support-passport/index.js.map +1 -0
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/tier-routing.js +2 -2
- package/dist/{tier-stats-JDN6HRNT.js → tier-stats-EXYSKSVN.js} +3 -3
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/types.d.ts +24 -24
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-BnQza1y8.d.ts → types-ed-SvS2t.d.ts} +7 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +14 -14
- package/dist/write-envelope.d.ts +1 -1
- package/dist/write-rate-limiter.d.ts +11 -5
- package/dist/write-rate-limiter.js +1 -1
- package/package.json +12 -2
- package/scripts/build-with-heap.mjs +11 -1
- package/src/access-authorization-probe.ts +20 -2
- package/src/access-boundary.ts +32 -0
- package/src/access-http.test.ts +1940 -643
- package/src/access-http.ts +81 -74
- package/src/access-mcp.ts +3 -1
- package/src/access-operations.ts +2 -0
- package/src/access-service.ts +612 -845
- package/src/access-surface-catalog.test.ts +40 -10
- package/src/access-surface-catalog.ts +15 -0
- package/src/active-memory-bridge.ts +17 -19
- package/src/config.ts +18 -9
- package/src/fallback-llm.test.ts +54 -0
- package/src/fallback-llm.ts +54 -9
- package/src/inline-script.ts +6 -0
- package/src/local-llm-headers-timeout.test.ts +42 -0
- package/src/local-llm.ts +8 -8
- package/src/mcp-read-only-tools.ts +3 -0
- package/src/relay/mission-access.test.ts +11 -11
- package/src/relay/mission-ui.test.ts +3 -1
- package/src/storage/tombstone-blocked-capture-sync.ts +31 -0
- package/src/storage-contract/failure-semantics.test.ts +102 -0
- package/src/support-passport/access-http-base.ts +143 -0
- package/src/support-passport/access-http.ts +172 -0
- package/src/support-passport/access-operations.ts +272 -0
- package/src/support-passport/access-service-base.test.ts +193 -0
- package/src/support-passport/access-service-base.ts +176 -0
- package/src/support-passport/access-surface.test.ts +283 -0
- package/src/support-passport/access-surface.ts +286 -0
- package/src/support-passport/card-projection.test.ts +8 -0
- package/src/support-passport/card-projection.ts +77 -16
- package/src/support-passport/card-replacement.ts +126 -0
- package/src/support-passport/card-service-commit-forwarding.test.ts +160 -0
- package/src/support-passport/card-service.test.ts +533 -31
- package/src/support-passport/card-service.ts +506 -364
- package/src/support-passport/card-state.ts +158 -0
- package/src/support-passport/config-model-routing.test.ts +37 -0
- package/src/support-passport/config.test.ts +34 -0
- package/src/support-passport/config.ts +41 -0
- package/src/support-passport/contracts.test.ts +15 -2
- package/src/support-passport/contracts.ts +13 -0
- package/src/support-passport/errors.ts +6 -0
- package/src/support-passport/generated-batch.test.ts +185 -0
- package/src/support-passport/generated-batch.ts +338 -0
- package/src/support-passport/grant-contracts.ts +45 -1
- package/src/support-passport/grant-generated-batch-scope.test.ts +201 -0
- package/src/support-passport/grant-service-cache.test.ts +2 -2
- package/src/support-passport/grant-service-cancellation.test.ts +2 -0
- package/src/support-passport/grant-service-marker-cache.test.ts +62 -0
- package/src/support-passport/grant-service.test.ts +853 -239
- package/src/support-passport/grant-service.ts +206 -57
- package/src/support-passport/grant-store.ts +7 -3
- package/src/support-passport/index.ts +10 -0
- package/src/support-passport/mcp-tools.test.ts +222 -0
- package/src/support-passport/mcp-tools.ts +187 -0
- package/src/support-passport/model-adapter.test.ts +840 -0
- package/src/support-passport/model-adapter.ts +602 -0
- package/src/support-passport/model-audit-pinned-write.test.ts +59 -0
- package/src/support-passport/model-audit.ts +152 -0
- package/src/support-passport/model-bridge.test.ts +456 -0
- package/src/support-passport/model-bridge.ts +439 -0
- package/src/support-passport/model-contracts.ts +124 -0
- package/src/support-passport/model-service.test.ts +1731 -0
- package/src/support-passport/model-service.ts +399 -0
- package/src/support-passport/owner-http.test.ts +671 -0
- package/src/support-passport/owner-lock.ts +26 -9
- package/src/support-passport/private-file.test.ts +99 -0
- package/src/support-passport/private-file.ts +139 -12
- package/src/support-passport/public-http.test.ts +476 -0
- package/src/support-passport/public-http.ts +601 -0
- package/src/support-passport/ui.test.ts +181 -0
- package/src/types.ts +7 -0
- package/src/write-rate-limiter.test.ts +30 -6
- package/src/write-rate-limiter.ts +29 -18
- package/dist/chunk-2INWPC6E.js.map +0 -1
- package/dist/chunk-2PNXOQ4P.js.map +0 -1
- package/dist/chunk-3SXLD5T3.js.map +0 -1
- package/dist/chunk-3WGI7F4V.js.map +0 -1
- package/dist/chunk-7HG7MGAP.js.map +0 -1
- package/dist/chunk-BIF4SHMD.js.map +0 -1
- package/dist/chunk-C23BYTJV.js.map +0 -1
- package/dist/chunk-CSY44OKU.js.map +0 -1
- package/dist/chunk-DDA55IVB.js.map +0 -1
- package/dist/chunk-HNDIND7P.js.map +0 -1
- package/dist/chunk-L6CQ7WIW.js.map +0 -1
- package/dist/chunk-MKQBXQKU.js.map +0 -1
- package/dist/chunk-QQXWFDRD.js.map +0 -1
- package/dist/chunk-QTO6BMQZ.js.map +0 -1
- package/dist/chunk-WZWZRZ2V.js.map +0 -1
- /package/dist/{auto-sync-TDHLZPVP.js.map → auto-sync-NR3GPCOA.js.map} +0 -0
- /package/dist/{chunk-LLJMAULE.js.map → chunk-2FKEIPIT.js.map} +0 -0
- /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-TKFGFDPJ.js.map → chunk-3TIZPSJC.js.map} +0 -0
- /package/dist/{chunk-B4T3FQMT.js.map → chunk-43SEBY2M.js.map} +0 -0
- /package/dist/{chunk-LVKYLMSM.js.map → chunk-46SZBVDS.js.map} +0 -0
- /package/dist/{chunk-YKZLOPTC.js.map → chunk-5FD7JMTX.js.map} +0 -0
- /package/dist/{chunk-WM5LD6AT.js.map → chunk-6CYHUWCO.js.map} +0 -0
- /package/dist/{chunk-YR65W7BV.js.map → chunk-BRR5EUTF.js.map} +0 -0
- /package/dist/{chunk-JKW663ZN.js.map → chunk-CIAI24TQ.js.map} +0 -0
- /package/dist/{chunk-YDWPYDML.js.map → chunk-EKTP7MNS.js.map} +0 -0
- /package/dist/{chunk-6LEIWWAF.js.map → chunk-F2JRDPON.js.map} +0 -0
- /package/dist/{chunk-VYQ4URQB.js.map → chunk-FFRTNF3L.js.map} +0 -0
- /package/dist/{chunk-TY6MKIWP.js.map → chunk-FONWBCVY.js.map} +0 -0
- /package/dist/{chunk-XSV2YDCJ.js.map → chunk-FPLM2TKD.js.map} +0 -0
- /package/dist/{chunk-VTU5IEKY.js.map → chunk-FTPONF6B.js.map} +0 -0
- /package/dist/{chunk-6PZGKGAO.js.map → chunk-FWX7W5PM.js.map} +0 -0
- /package/dist/{chunk-QPW3PAIH.js.map → chunk-G6DFSS6A.js.map} +0 -0
- /package/dist/{chunk-2DD6ZHOM.js.map → chunk-GJ776BC2.js.map} +0 -0
- /package/dist/{chunk-XKAR4RF6.js.map → chunk-GN3WRFJY.js.map} +0 -0
- /package/dist/{chunk-RG426DJO.js.map → chunk-H7NAZ3UB.js.map} +0 -0
- /package/dist/{chunk-BSXGTDVJ.js.map → chunk-HBUFQRIM.js.map} +0 -0
- /package/dist/{chunk-FFEBSFVT.js.map → chunk-HGJ6NJ4E.js.map} +0 -0
- /package/dist/{chunk-5JKUSBMX.js.map → chunk-IKP5OYQQ.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-DBY26JJJ.js.map → chunk-IQ4NVWEF.js.map} +0 -0
- /package/dist/{chunk-7Q7JWLQ4.js.map → chunk-JYG4OLWH.js.map} +0 -0
- /package/dist/{chunk-3OTSVCPK.js.map → chunk-K26NWEOC.js.map} +0 -0
- /package/dist/{chunk-HOIRB77A.js.map → chunk-L6Z5OAS4.js.map} +0 -0
- /package/dist/{chunk-7RZJWZ46.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-NGT35IGQ.js.map → chunk-MIH3CJPN.js.map} +0 -0
- /package/dist/{chunk-QPAQSG3F.js.map → chunk-MK5VEWCR.js.map} +0 -0
- /package/dist/{chunk-L7RTUEDG.js.map → chunk-OCIP6YMD.js.map} +0 -0
- /package/dist/{chunk-UWJNKGBA.js.map → chunk-QZLDRQ4I.js.map} +0 -0
- /package/dist/{chunk-UYOXFFEY.js.map → chunk-RUNORG2P.js.map} +0 -0
- /package/dist/{chunk-LC3FD4BV.js.map → chunk-RZQ6W2W4.js.map} +0 -0
- /package/dist/{chunk-MRGJZ75M.js.map → chunk-SMNYAMJD.js.map} +0 -0
- /package/dist/{chunk-DN2IDKI5.js.map → chunk-TO7ZTWJW.js.map} +0 -0
- /package/dist/{chunk-K2TDK7GG.js.map → chunk-TWTUGCTY.js.map} +0 -0
- /package/dist/{chunk-CUTFSLSD.js.map → chunk-UCTS3DDH.js.map} +0 -0
- /package/dist/{chunk-JYIJNNN3.js.map → chunk-UG6VXIOK.js.map} +0 -0
- /package/dist/{chunk-QOQQMVR2.js.map → chunk-UKYS3NU5.js.map} +0 -0
- /package/dist/{chunk-VZRFGJCH.js.map → chunk-UPLZNJKN.js.map} +0 -0
- /package/dist/{chunk-DOOWFDWN.js.map → chunk-V6ERBR7U.js.map} +0 -0
- /package/dist/{chunk-N7CXQ5TA.js.map → chunk-XZHE2DEN.js.map} +0 -0
- /package/dist/{chunk-6NNNURLK.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{chunk-F2Y6I74C.js.map → chunk-ZRZVLB7O.js.map} +0 -0
- /package/dist/{chunk-CLKBV3Z3.js.map → chunk-ZUKIUXHQ.js.map} +0 -0
- /package/dist/{contradiction-scan-KCADHXPE.js.map → contradiction-scan-JDTBXRGW.js.map} +0 -0
- /package/dist/{first-start-migration-LMMZFLKK.js.map → first-start-migration-CRZCZAJN.js.map} +0 -0
- /package/dist/{tier-stats-JDN6HRNT.js.map → tier-stats-EXYSKSVN.js.map} +0 -0
|
@@ -6,23 +6,23 @@ import {
|
|
|
6
6
|
loadSyncState,
|
|
7
7
|
syncWearableSource,
|
|
8
8
|
wearableSourceLabel
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import {
|
|
11
|
-
runPeerProfileReasoner
|
|
12
|
-
} from "./chunk-I74SUMNI.js";
|
|
13
|
-
import {
|
|
14
|
-
CompressionGuidelineCoordinator
|
|
15
|
-
} from "./chunk-6LKEUCEM.js";
|
|
9
|
+
} from "./chunk-L6Z5OAS4.js";
|
|
16
10
|
import {
|
|
17
11
|
ActivityStore,
|
|
18
12
|
MaintenanceScheduler
|
|
19
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-K26NWEOC.js";
|
|
14
|
+
import {
|
|
15
|
+
runPeerProfileReasoner
|
|
16
|
+
} from "./chunk-I74SUMNI.js";
|
|
20
17
|
import {
|
|
21
18
|
migrateFromEngram
|
|
22
19
|
} from "./chunk-7HYPN2GC.js";
|
|
20
|
+
import {
|
|
21
|
+
CompressionGuidelineCoordinator
|
|
22
|
+
} from "./chunk-6LKEUCEM.js";
|
|
23
23
|
import {
|
|
24
24
|
LcmEngine
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-Z54EM5YZ.js";
|
|
26
26
|
import {
|
|
27
27
|
chunkTranscriptEntries
|
|
28
28
|
} from "./chunk-TECVW3JP.js";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
import {
|
|
33
33
|
CompoundingEngine,
|
|
34
34
|
defaultTierMigrationCycleBudget
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-ZRZVLB7O.js";
|
|
36
36
|
import {
|
|
37
37
|
SharedContextManager
|
|
38
38
|
} from "./chunk-M23RF3LJ.js";
|
|
@@ -41,9 +41,12 @@ import {
|
|
|
41
41
|
applyUtilityRankingRuntimeDelta,
|
|
42
42
|
loadUtilityRuntimeValues
|
|
43
43
|
} from "./chunk-SEF4IOFE.js";
|
|
44
|
+
import {
|
|
45
|
+
TierMigrationExecutor
|
|
46
|
+
} from "./chunk-YRFAYOFQ.js";
|
|
44
47
|
import {
|
|
45
48
|
decideTierTransition
|
|
46
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-F2JRDPON.js";
|
|
47
50
|
import {
|
|
48
51
|
TmtBuilder
|
|
49
52
|
} from "./chunk-ECZU5BJH.js";
|
|
@@ -56,12 +59,9 @@ import {
|
|
|
56
59
|
import {
|
|
57
60
|
CODEX_THREAD_KEY_PREFIX
|
|
58
61
|
} from "./chunk-4EX5WZ4M.js";
|
|
59
|
-
import {
|
|
60
|
-
TierMigrationExecutor
|
|
61
|
-
} from "./chunk-YRFAYOFQ.js";
|
|
62
62
|
import {
|
|
63
63
|
HourlySummarizer
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-2FKEIPIT.js";
|
|
65
65
|
import {
|
|
66
66
|
buildTargetedFactRecallSection,
|
|
67
67
|
shouldRecallTargetedFactEvidence
|
|
@@ -105,6 +105,12 @@ import {
|
|
|
105
105
|
buildResponseGuidanceRecallSection,
|
|
106
106
|
shouldRecallResponseGuidance
|
|
107
107
|
} from "./chunk-6TCXIRP5.js";
|
|
108
|
+
import {
|
|
109
|
+
LastRecallStore,
|
|
110
|
+
RecallHandleHistoryStore,
|
|
111
|
+
TierMigrationStatusStore,
|
|
112
|
+
clampGraphRecallExpandedEntries
|
|
113
|
+
} from "./chunk-PRDJMOST.js";
|
|
108
114
|
import {
|
|
109
115
|
findUnresolvedEntityRefs
|
|
110
116
|
} from "./chunk-X7XN6YU4.js";
|
|
@@ -119,12 +125,6 @@ import {
|
|
|
119
125
|
import {
|
|
120
126
|
reorderRecallResultsWithMmr
|
|
121
127
|
} from "./chunk-YDBIWGNI.js";
|
|
122
|
-
import {
|
|
123
|
-
LastRecallStore,
|
|
124
|
-
RecallHandleHistoryStore,
|
|
125
|
-
TierMigrationStatusStore,
|
|
126
|
-
clampGraphRecallExpandedEntries
|
|
127
|
-
} from "./chunk-PRDJMOST.js";
|
|
128
128
|
import {
|
|
129
129
|
applyReasoningTraceBoost
|
|
130
130
|
} from "./chunk-ZZTOURJI.js";
|
|
@@ -163,16 +163,13 @@ import {
|
|
|
163
163
|
} from "./chunk-OH7QLI6W.js";
|
|
164
164
|
import {
|
|
165
165
|
ExtractionEngine
|
|
166
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-GN3WRFJY.js";
|
|
167
167
|
import {
|
|
168
168
|
parseMemoryActionEligibilityContext
|
|
169
169
|
} from "./chunk-WFLBP5GC.js";
|
|
170
170
|
import {
|
|
171
171
|
ModelRegistry
|
|
172
172
|
} from "./chunk-WLZYGLJ4.js";
|
|
173
|
-
import {
|
|
174
|
-
LocalLlmClient
|
|
175
|
-
} from "./chunk-L6CQ7WIW.js";
|
|
176
173
|
import {
|
|
177
174
|
recordJudgeTrainingPair
|
|
178
175
|
} from "./chunk-PWFCHOB3.js";
|
|
@@ -182,7 +179,7 @@ import {
|
|
|
182
179
|
getVerdictKind,
|
|
183
180
|
judgeFactDurability,
|
|
184
181
|
validateProcedureExtraction
|
|
185
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-TWTUGCTY.js";
|
|
186
183
|
import {
|
|
187
184
|
buildExplicitCueRecallSection
|
|
188
185
|
} from "./chunk-TVIVY7KU.js";
|
|
@@ -190,7 +187,7 @@ import {
|
|
|
190
187
|
buildEntityRecallSection,
|
|
191
188
|
entityRecentTranscriptLookbackHours,
|
|
192
189
|
readRecentEntityTranscriptEntries
|
|
193
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-FPLM2TKD.js";
|
|
194
191
|
import {
|
|
195
192
|
buildEventOrderRecallSection,
|
|
196
193
|
shouldRecallEventOrderEvidence
|
|
@@ -207,7 +204,7 @@ import {
|
|
|
207
204
|
} from "./chunk-YK6BDDHP.js";
|
|
208
205
|
import {
|
|
209
206
|
refreshConvergedNamespaces
|
|
210
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-IKP5OYQQ.js";
|
|
211
208
|
import {
|
|
212
209
|
formatDaySummaryMemories
|
|
213
210
|
} from "./chunk-RPSYDM6C.js";
|
|
@@ -216,44 +213,44 @@ import {
|
|
|
216
213
|
ensureBuiltInWearableConnectors,
|
|
217
214
|
getWearableConnector,
|
|
218
215
|
listWearableConnectors
|
|
219
|
-
} from "./chunk-
|
|
220
|
-
import {
|
|
221
|
-
normalizeReplaySessionKey
|
|
222
|
-
} from "./chunk-AJVLDJU6.js";
|
|
216
|
+
} from "./chunk-RZQ6W2W4.js";
|
|
223
217
|
import {
|
|
224
218
|
RoutingRulesStore
|
|
225
219
|
} from "./chunk-XL24QQ63.js";
|
|
220
|
+
import {
|
|
221
|
+
normalizeReplaySessionKey
|
|
222
|
+
} from "./chunk-AJVLDJU6.js";
|
|
226
223
|
import {
|
|
227
224
|
compareVerifiedEpisodeResults,
|
|
228
225
|
searchVerifiedEpisodes
|
|
229
|
-
} from "./chunk-
|
|
226
|
+
} from "./chunk-5FD7JMTX.js";
|
|
230
227
|
import {
|
|
231
228
|
ThreadingManager
|
|
232
229
|
} from "./chunk-OJP3N7UK.js";
|
|
233
230
|
import {
|
|
234
231
|
compareVerifiedSemanticRuleResults,
|
|
235
232
|
searchVerifiedSemanticRules
|
|
236
|
-
} from "./chunk-
|
|
233
|
+
} from "./chunk-FWX7W5PM.js";
|
|
237
234
|
import {
|
|
238
235
|
searchWorkProductLedgerEntries
|
|
239
236
|
} from "./chunk-WT6UL3UA.js";
|
|
240
237
|
import {
|
|
241
238
|
TranscriptManager
|
|
242
239
|
} from "./chunk-HYQJQGD3.js";
|
|
240
|
+
import {
|
|
241
|
+
PolicyRuntimeManager
|
|
242
|
+
} from "./chunk-33JBK2XP.js";
|
|
243
243
|
import {
|
|
244
244
|
runNamespaceMaintenanceFanout,
|
|
245
245
|
summarizeNamespaceMaintenanceHealth
|
|
246
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-ZUKIUXHQ.js";
|
|
247
247
|
import {
|
|
248
248
|
NamespaceCatalog,
|
|
249
249
|
planNamespaceMaintenance
|
|
250
|
-
} from "./chunk-
|
|
251
|
-
import {
|
|
252
|
-
PolicyRuntimeManager
|
|
253
|
-
} from "./chunk-33JBK2XP.js";
|
|
250
|
+
} from "./chunk-FFRTNF3L.js";
|
|
254
251
|
import {
|
|
255
252
|
searchHarmonicRetrieval
|
|
256
|
-
} from "./chunk-
|
|
253
|
+
} from "./chunk-43SEBY2M.js";
|
|
257
254
|
import {
|
|
258
255
|
isAboveImportanceThreshold,
|
|
259
256
|
scoreImportance
|
|
@@ -285,7 +282,7 @@ import {
|
|
|
285
282
|
materializeAfterSemanticConsolidation,
|
|
286
283
|
parseConsolidationResponse,
|
|
287
284
|
parseOperatorAwareConsolidationResponse
|
|
288
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-UKYS3NU5.js";
|
|
289
286
|
import {
|
|
290
287
|
BootstrapEngine
|
|
291
288
|
} from "./chunk-MYVPLJOO.js";
|
|
@@ -300,13 +297,13 @@ import {
|
|
|
300
297
|
} from "./chunk-UQ7RN5HK.js";
|
|
301
298
|
import {
|
|
302
299
|
SmartBuffer
|
|
303
|
-
} from "./chunk-
|
|
300
|
+
} from "./chunk-UCTS3DDH.js";
|
|
304
301
|
import {
|
|
305
302
|
isDisagreementPrompt
|
|
306
303
|
} from "./chunk-H3FZVNRN.js";
|
|
307
304
|
import {
|
|
308
305
|
detectMeetings
|
|
309
|
-
} from "./chunk-
|
|
306
|
+
} from "./chunk-PG4QBPVG.js";
|
|
310
307
|
import {
|
|
311
308
|
compileCorrectionRule,
|
|
312
309
|
correctionsFilePath,
|
|
@@ -331,7 +328,7 @@ import {
|
|
|
331
328
|
} from "./chunk-KD3QD3A5.js";
|
|
332
329
|
import {
|
|
333
330
|
MeetingsInputError
|
|
334
|
-
} from "./chunk-
|
|
331
|
+
} from "./chunk-PT54WISF.js";
|
|
335
332
|
import {
|
|
336
333
|
WearablesInputError,
|
|
337
334
|
describeErrorForOperator
|
|
@@ -352,7 +349,7 @@ import {
|
|
|
352
349
|
filterRecallCandidates,
|
|
353
350
|
isGenericRecallExcludedPath,
|
|
354
351
|
isTopLevelArchivePath
|
|
355
|
-
} from "./chunk-
|
|
352
|
+
} from "./chunk-D3LBIUWV.js";
|
|
356
353
|
import {
|
|
357
354
|
importCapsule
|
|
358
355
|
} from "./chunk-QYN5PXDZ.js";
|
|
@@ -370,6 +367,9 @@ import {
|
|
|
370
367
|
trustResultFor,
|
|
371
368
|
trustResultKey
|
|
372
369
|
} from "./chunk-GNVZQ5JN.js";
|
|
370
|
+
import {
|
|
371
|
+
buildXraySnapshot
|
|
372
|
+
} from "./chunk-MK5VEWCR.js";
|
|
373
373
|
import {
|
|
374
374
|
boundRecallContextComposition,
|
|
375
375
|
composeRecallContext,
|
|
@@ -377,9 +377,6 @@ import {
|
|
|
377
377
|
formatCuriosityFooter,
|
|
378
378
|
selectCuriosityQuestion
|
|
379
379
|
} from "./chunk-AHVEHR6K.js";
|
|
380
|
-
import {
|
|
381
|
-
buildXraySnapshot
|
|
382
|
-
} from "./chunk-QPAQSG3F.js";
|
|
383
380
|
import {
|
|
384
381
|
objectiveStateStoreOverrideForNamespace,
|
|
385
382
|
searchObjectiveStateSnapshots
|
|
@@ -391,15 +388,18 @@ import {
|
|
|
391
388
|
import {
|
|
392
389
|
ProfilingCollector
|
|
393
390
|
} from "./chunk-NLE6TSLG.js";
|
|
391
|
+
import {
|
|
392
|
+
LocalLlmClient
|
|
393
|
+
} from "./chunk-KFBOPMF6.js";
|
|
394
394
|
import {
|
|
395
395
|
buildProcedurePersistBody
|
|
396
396
|
} from "./chunk-QDW3E4RD.js";
|
|
397
397
|
import {
|
|
398
398
|
shouldSkipImplicitExtraction
|
|
399
|
-
} from "./chunk-
|
|
399
|
+
} from "./chunk-SMNYAMJD.js";
|
|
400
400
|
import {
|
|
401
401
|
NamespaceStorageRouter
|
|
402
|
-
} from "./chunk-
|
|
402
|
+
} from "./chunk-UPLZNJKN.js";
|
|
403
403
|
import {
|
|
404
404
|
searchCausalTrajectories
|
|
405
405
|
} from "./chunk-AHZOMHWN.js";
|
|
@@ -408,7 +408,7 @@ import {
|
|
|
408
408
|
} from "./chunk-BIJAWZYW.js";
|
|
409
409
|
import {
|
|
410
410
|
buildChainFollowupGenerator
|
|
411
|
-
} from "./chunk-
|
|
411
|
+
} from "./chunk-RUNORG2P.js";
|
|
412
412
|
import {
|
|
413
413
|
QmdResultResolver,
|
|
414
414
|
StorageManager,
|
|
@@ -427,7 +427,10 @@ import {
|
|
|
427
427
|
reconstructFusionInputs,
|
|
428
428
|
selfDeps,
|
|
429
429
|
serializeFusionDay
|
|
430
|
-
} from "./chunk-
|
|
430
|
+
} from "./chunk-M4YHAODQ.js";
|
|
431
|
+
import {
|
|
432
|
+
buildRetiredFactTombstoneInputs
|
|
433
|
+
} from "./chunk-MLPTFODV.js";
|
|
431
434
|
import {
|
|
432
435
|
bodyIsEscaped,
|
|
433
436
|
decodeTranscriptBody,
|
|
@@ -438,18 +441,15 @@ import {
|
|
|
438
441
|
saveSpeakerRegistry,
|
|
439
442
|
speakerRegistryKey
|
|
440
443
|
} from "./chunk-UHVXE24Y.js";
|
|
441
|
-
import {
|
|
442
|
-
buildRetiredFactTombstoneInputs
|
|
443
|
-
} from "./chunk-MLPTFODV.js";
|
|
444
444
|
import {
|
|
445
445
|
NamespaceSearchRouter,
|
|
446
446
|
namespaceCollectionName
|
|
447
|
-
} from "./chunk-
|
|
447
|
+
} from "./chunk-TO7ZTWJW.js";
|
|
448
448
|
import {
|
|
449
449
|
createConversationIndexRuntime,
|
|
450
450
|
createSearchBackend,
|
|
451
451
|
isSearchBackendEnabled
|
|
452
|
-
} from "./chunk-
|
|
452
|
+
} from "./chunk-QZLDRQ4I.js";
|
|
453
453
|
import {
|
|
454
454
|
NoopSearchBackend
|
|
455
455
|
} from "./chunk-CYEPCZN5.js";
|
|
@@ -463,7 +463,7 @@ import {
|
|
|
463
463
|
} from "./chunk-S2V7RUCL.js";
|
|
464
464
|
import {
|
|
465
465
|
confidenceTier
|
|
466
|
-
} from "./chunk-
|
|
466
|
+
} from "./chunk-76JJSXK7.js";
|
|
467
467
|
import {
|
|
468
468
|
lintWorkspaceFiles,
|
|
469
469
|
rotateMarkdownFileToArchive
|
|
@@ -472,7 +472,7 @@ import {
|
|
|
472
472
|
applyFaithfulnessVerdict,
|
|
473
473
|
createFaithfulnessCounters,
|
|
474
474
|
runFaithfulnessGateBatch
|
|
475
|
-
} from "./chunk-
|
|
475
|
+
} from "./chunk-UG6VXIOK.js";
|
|
476
476
|
import {
|
|
477
477
|
TAG_LIMITS,
|
|
478
478
|
composeMemoryEnvelope,
|
|
@@ -514,7 +514,7 @@ import {
|
|
|
514
514
|
FallbackLlmClient,
|
|
515
515
|
fallbackLlmRuntimeContextFromConfig,
|
|
516
516
|
gatewayTaskChainOptions
|
|
517
|
-
} from "./chunk-
|
|
517
|
+
} from "./chunk-UW5NPZJ2.js";
|
|
518
518
|
import {
|
|
519
519
|
BulkImportBatchPartialFailureError,
|
|
520
520
|
COMPACTION_SIGNAL_MAX_AGE_MS,
|
|
@@ -554,7 +554,7 @@ import {
|
|
|
554
554
|
throwIfRecallAborted,
|
|
555
555
|
tokenizeRecallQuery,
|
|
556
556
|
utcDateKeysForLocalDay
|
|
557
|
-
} from "./chunk-
|
|
557
|
+
} from "./chunk-XZHE2DEN.js";
|
|
558
558
|
import {
|
|
559
559
|
inferIntentFromText,
|
|
560
560
|
intentCompatibilityScore,
|
|
@@ -615,28 +615,9 @@ import {
|
|
|
615
615
|
ContentHashIndex
|
|
616
616
|
} from "./chunk-CX5SW2EW.js";
|
|
617
617
|
import {
|
|
618
|
-
serializeMutations,
|
|
619
|
-
withHeldFileLock
|
|
620
|
-
} from "./chunk-FFAZ2XFU.js";
|
|
621
|
-
import {
|
|
622
|
-
SUPPORT_PASSPORT_ATTRIBUTE_KEYS,
|
|
623
|
-
SUPPORT_PASSPORT_CARD_TAG,
|
|
624
|
-
SupportPassportCardCategorySchema,
|
|
625
|
-
SupportPassportCardListSchema,
|
|
626
|
-
SupportPassportCardMutationInputSchema,
|
|
627
|
-
SupportPassportListCardsInputSchema,
|
|
628
|
-
SupportPassportManualDraftInputSchema,
|
|
629
|
-
SupportPassportMemoryIdSchema,
|
|
630
|
-
SupportPassportNamespaceSchema,
|
|
631
|
-
SupportPassportReplaceCardInputSchema,
|
|
632
|
-
computeSupportPassportCardRevision,
|
|
633
|
-
computeSupportPassportOwnerKey,
|
|
634
|
-
decodeSupportPassportNamespaceAttributes,
|
|
635
|
-
encodeSupportPassportNamespaceAttributes,
|
|
636
618
|
excludeSupportPassportPrivateMemories,
|
|
637
|
-
isSupportPassportPrivateMemory
|
|
638
|
-
|
|
639
|
-
} from "./chunk-HNDIND7P.js";
|
|
619
|
+
isSupportPassportPrivateMemory
|
|
620
|
+
} from "./chunk-XX4HPFFM.js";
|
|
640
621
|
import {
|
|
641
622
|
namespaceIdentityFromToken,
|
|
642
623
|
namespaceIdentityToken,
|
|
@@ -659,9 +640,6 @@ import {
|
|
|
659
640
|
assertIsDirectoryNotSymlink,
|
|
660
641
|
assertRealpathInsideRoot
|
|
661
642
|
} from "./chunk-GCGJW34D.js";
|
|
662
|
-
import {
|
|
663
|
-
parseIsoOffsetTimestamp
|
|
664
|
-
} from "./chunk-P7FMDTKL.js";
|
|
665
643
|
import {
|
|
666
644
|
canReadNamespace,
|
|
667
645
|
defaultNamespaceForPrincipal,
|
|
@@ -2236,7 +2214,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2236
2214
|
namespaces,
|
|
2237
2215
|
{
|
|
2238
2216
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2239
|
-
readMemoryFrontmatter: async (
|
|
2217
|
+
readMemoryFrontmatter: async (path35, preferredNamespace) => {
|
|
2240
2218
|
if (!fallbackReader) {
|
|
2241
2219
|
for (const ns of namespaces) {
|
|
2242
2220
|
try {
|
|
@@ -2248,7 +2226,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2248
2226
|
}
|
|
2249
2227
|
if (!fallbackReader) return null;
|
|
2250
2228
|
const memory = await this.readQmdResultMemory(
|
|
2251
|
-
|
|
2229
|
+
path35,
|
|
2252
2230
|
fallbackReader,
|
|
2253
2231
|
namespaces,
|
|
2254
2232
|
preferredNamespace
|
|
@@ -15043,7 +15021,7 @@ var OrchestratorInitCoordinator = class {
|
|
|
15043
15021
|
if (signal.aborted) return;
|
|
15044
15022
|
if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.deps.config).qmdTierMigration) {
|
|
15045
15023
|
try {
|
|
15046
|
-
const { runFirstStartMigration } = await import("./first-start-migration-
|
|
15024
|
+
const { runFirstStartMigration } = await import("./first-start-migration-CRZCZAJN.js");
|
|
15047
15025
|
const result = await runFirstStartMigration({
|
|
15048
15026
|
storage: this.deps.storage,
|
|
15049
15027
|
config: this.deps.config,
|
|
@@ -15066,7 +15044,7 @@ var OrchestratorInitCoordinator = class {
|
|
|
15066
15044
|
if (signal.aborted) return;
|
|
15067
15045
|
if (!this.deps.wearablesAutoSyncHandle && this.deps.config.wearables.enabled && this.deps.config.wearables.autoSyncEnabled && Object.values(this.deps.config.wearables.sources).some((source) => source.enabled)) {
|
|
15068
15046
|
try {
|
|
15069
|
-
const { startWearablesAutoSync } = await import("./auto-sync-
|
|
15047
|
+
const { startWearablesAutoSync } = await import("./auto-sync-NR3GPCOA.js");
|
|
15070
15048
|
if (signal.aborted) return;
|
|
15071
15049
|
this.deps.wearablesAutoSyncHandle = startWearablesAutoSync(
|
|
15072
15050
|
{
|
|
@@ -20970,2340 +20948,166 @@ ${doc.content}` : doc.content,
|
|
|
20970
20948
|
}
|
|
20971
20949
|
};
|
|
20972
20950
|
|
|
20973
|
-
// src/
|
|
20974
|
-
var
|
|
20975
|
-
|
|
20976
|
-
|
|
20977
|
-
|
|
20978
|
-
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
}
|
|
20951
|
+
// src/relay/mission-fixture.ts
|
|
20952
|
+
var RELAY_DEMO_MISSION_ID = "checkout-token-recovery";
|
|
20953
|
+
var RELAY_DEMO_NAMESPACE = "relay-build-week";
|
|
20954
|
+
var sourceEvidence = {
|
|
20955
|
+
kind: "source",
|
|
20956
|
+
id: "source-checkout-contract",
|
|
20957
|
+
label: "Checkout token contract",
|
|
20958
|
+
locator: "fixture://checkout-service/src/token-policy.ts",
|
|
20959
|
+
capture: "fixture"
|
|
20983
20960
|
};
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
|
|
20990
|
-
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
async (acquired, lock) => {
|
|
21008
|
-
if (!acquired) {
|
|
21009
|
-
throw new SupportPassportError("storage_conflict", "The support passport is busy. Try again.", 409);
|
|
21010
|
-
}
|
|
21011
|
-
return await task(lock);
|
|
21012
|
-
}
|
|
21013
|
-
)
|
|
21014
|
-
);
|
|
21015
|
-
}
|
|
21016
|
-
async function requireSupportPassportOwnerLock(lock) {
|
|
21017
|
-
if (await lock.refresh()) return;
|
|
21018
|
-
throw new SupportPassportError("storage_conflict", "The support passport changed during the request.", 409);
|
|
20961
|
+
var testEvidence = {
|
|
20962
|
+
kind: "test",
|
|
20963
|
+
id: "test-checkout-contract",
|
|
20964
|
+
label: "Checkout integration contract",
|
|
20965
|
+
locator: "fixture://checkout-service/test/token-policy.test.ts",
|
|
20966
|
+
capture: "fixture"
|
|
20967
|
+
};
|
|
20968
|
+
var approvalEvidence = {
|
|
20969
|
+
kind: "approval",
|
|
20970
|
+
id: "approval-build-week-operator",
|
|
20971
|
+
label: "Human approval receipt",
|
|
20972
|
+
locator: "fixture://relay/approvals/correction-token-refresh.json",
|
|
20973
|
+
capture: "fixture"
|
|
20974
|
+
};
|
|
20975
|
+
var correctionEvidence = {
|
|
20976
|
+
kind: "correction",
|
|
20977
|
+
id: "correction-token-refresh",
|
|
20978
|
+
label: "Applied Remnic correction",
|
|
20979
|
+
locator: "fixture://remnic/corrections/correction-token-refresh.json",
|
|
20980
|
+
capture: "fixture"
|
|
20981
|
+
};
|
|
20982
|
+
function at(second) {
|
|
20983
|
+
return `2026-07-17T18:00:${String(second).padStart(2, "0")}.000Z`;
|
|
21019
20984
|
}
|
|
21020
|
-
|
|
21021
|
-
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21025
|
-
|
|
21026
|
-
|
|
21027
|
-
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
resolveOwner;
|
|
21032
|
-
now;
|
|
21033
|
-
constructor(dependencies) {
|
|
21034
|
-
this.resolveOwner = dependencies.resolveOwner;
|
|
21035
|
-
this.now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
21036
|
-
}
|
|
21037
|
-
async listCards(input) {
|
|
21038
|
-
const parsed = SupportPassportListCardsInputSchema.safeParse(input);
|
|
21039
|
-
if (!parsed.success) throw invalidInput();
|
|
21040
|
-
const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
|
|
21041
|
-
return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
|
|
21042
|
-
const stored = await this.readStoredCards(storage, lock, principal, namespace);
|
|
21043
|
-
const cards = this.ownerVisibleCards(stored).sort((a, b) => a.order - b.order || a.card.cardId.localeCompare(b.card.cardId)).map((item) => item.card);
|
|
21044
|
-
const output = SupportPassportCardListSchema.safeParse(cards);
|
|
21045
|
-
if (!output.success) {
|
|
21046
|
-
throw new SupportPassportError("card_data_invalid", "The support card data is invalid.", 500);
|
|
21047
|
-
}
|
|
21048
|
-
return output.data;
|
|
21049
|
-
});
|
|
21050
|
-
}
|
|
21051
|
-
async createManualDraft(input) {
|
|
21052
|
-
const parsed = SupportPassportManualDraftInputSchema.safeParse(input);
|
|
21053
|
-
if (!parsed.success) throw invalidInput();
|
|
21054
|
-
const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
|
|
21055
|
-
return await withSupportPassportOwnerLock(
|
|
21056
|
-
storage,
|
|
21057
|
-
{ namespace, principal },
|
|
21058
|
-
(lock) => this.createDraft(
|
|
21059
|
-
storage,
|
|
21060
|
-
{
|
|
21061
|
-
title: parsed.data.title,
|
|
21062
|
-
statement: parsed.data.statement,
|
|
21063
|
-
category: parsed.data.category,
|
|
21064
|
-
reviewBy: parsed.data.reviewBy,
|
|
21065
|
-
sourceMemoryIds: []
|
|
21066
|
-
},
|
|
21067
|
-
lock,
|
|
21068
|
-
principal,
|
|
21069
|
-
namespace
|
|
21070
|
-
)
|
|
21071
|
-
);
|
|
21072
|
-
}
|
|
21073
|
-
async replaceCard(input) {
|
|
21074
|
-
const parsed = SupportPassportReplaceCardInputSchema.safeParse(input);
|
|
21075
|
-
if (!parsed.success) throw invalidInput();
|
|
21076
|
-
const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
|
|
21077
|
-
return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
|
|
21078
|
-
const loadedPrior = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
|
|
21079
|
-
const storedCards = await this.readProjectedCards(storage, namespace, principal);
|
|
21080
|
-
const interruptedReplacements = storedCards.filter(
|
|
21081
|
-
(item) => item.card.status === "pending_review" && (item.replacesDraftId === loadedPrior.card.cardId || item.memory.frontmatter.supersedes === loadedPrior.card.cardId)
|
|
21082
|
-
);
|
|
21083
|
-
if (interruptedReplacements.length > 1) {
|
|
21084
|
-
throw new SupportPassportError(
|
|
21085
|
-
"storage_conflict",
|
|
21086
|
-
"Multiple support card edits already completed. Reload the support passport.",
|
|
21087
|
-
409
|
|
21088
|
-
);
|
|
20985
|
+
function createRelayMissionFixture() {
|
|
20986
|
+
return [
|
|
20987
|
+
{
|
|
20988
|
+
occurredAt: at(0),
|
|
20989
|
+
idempotencyKey: "fixture-001",
|
|
20990
|
+
payload: {
|
|
20991
|
+
kind: "mission_started",
|
|
20992
|
+
title: "The checkout token split",
|
|
20993
|
+
objective: "Resolve a conflicting token refresh policy and prove a cold agent acts on it.",
|
|
20994
|
+
runMode: "fixture",
|
|
20995
|
+
evidence: [sourceEvidence]
|
|
21089
20996
|
}
|
|
21090
|
-
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
}
|
|
21103
|
-
if (!interruptedReplacement.draftReplacementPrepared) return interruptedReplacement.card;
|
|
21104
|
-
const recovered = await this.recoverReplacementTransition(
|
|
21105
|
-
storage,
|
|
21106
|
-
interruptedReplacement.memory,
|
|
21107
|
-
lock,
|
|
21108
|
-
principal,
|
|
21109
|
-
namespace
|
|
21110
|
-
);
|
|
21111
|
-
return this.projectRequiredCard(recovered, namespace, principal).card;
|
|
20997
|
+
},
|
|
20998
|
+
{
|
|
20999
|
+
occurredAt: at(2),
|
|
21000
|
+
idempotencyKey: "fixture-002",
|
|
21001
|
+
payload: {
|
|
21002
|
+
kind: "agent_status",
|
|
21003
|
+
agentId: "agent-atlas",
|
|
21004
|
+
sessionId: "session-atlas",
|
|
21005
|
+
label: "Atlas",
|
|
21006
|
+
role: "Checkout implementation",
|
|
21007
|
+
status: "working",
|
|
21008
|
+
evidence: [sourceEvidence]
|
|
21112
21009
|
}
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
if (prior.card.status !== "active" && prior.card.status !== "pending_review") {
|
|
21126
|
-
throw new SupportPassportError(
|
|
21127
|
-
"invalid_card_status",
|
|
21128
|
-
"Only a draft or approved support card can be edited.",
|
|
21129
|
-
409
|
|
21130
|
-
);
|
|
21010
|
+
},
|
|
21011
|
+
{
|
|
21012
|
+
occurredAt: at(3),
|
|
21013
|
+
idempotencyKey: "fixture-003",
|
|
21014
|
+
payload: {
|
|
21015
|
+
kind: "agent_status",
|
|
21016
|
+
agentId: "agent-nova",
|
|
21017
|
+
sessionId: "session-nova",
|
|
21018
|
+
label: "Nova",
|
|
21019
|
+
role: "Integration verification",
|
|
21020
|
+
status: "working",
|
|
21021
|
+
evidence: [testEvidence]
|
|
21131
21022
|
}
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
21135
|
-
|
|
21136
|
-
|
|
21137
|
-
|
|
21138
|
-
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
const replacedAt = this.now().toISOString();
|
|
21152
|
-
await this.requireOwnerLock(lock);
|
|
21153
|
-
const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21154
|
-
prior.memory,
|
|
21155
|
-
{ status: "rejected", updated: replacedAt },
|
|
21156
|
-
{ actor: principal, reasonCode: "owner-replaced-draft" }
|
|
21157
|
-
);
|
|
21158
|
-
if (rejected) {
|
|
21159
|
-
return await this.finishPreparedDraftReplacement(storage, replacement.cardId, lock, principal, namespace);
|
|
21023
|
+
},
|
|
21024
|
+
{
|
|
21025
|
+
occurredAt: at(6),
|
|
21026
|
+
idempotencyKey: "fixture-004",
|
|
21027
|
+
payload: {
|
|
21028
|
+
kind: "agent_output",
|
|
21029
|
+
agentId: "agent-atlas",
|
|
21030
|
+
sessionId: "session-atlas",
|
|
21031
|
+
outputId: "output-atlas-policy",
|
|
21032
|
+
summary: "Implemented a new token for every checkout retry.",
|
|
21033
|
+
evidence: [
|
|
21034
|
+
{
|
|
21035
|
+
kind: "agent_output",
|
|
21036
|
+
id: "output-atlas-policy",
|
|
21037
|
+
label: "Atlas one-shot output",
|
|
21038
|
+
locator: "fixture://codex/atlas/final-output.txt",
|
|
21039
|
+
capture: "fixture"
|
|
21040
|
+
}
|
|
21041
|
+
]
|
|
21160
21042
|
}
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21043
|
+
},
|
|
21044
|
+
{
|
|
21045
|
+
occurredAt: at(7),
|
|
21046
|
+
idempotencyKey: "fixture-005",
|
|
21047
|
+
payload: {
|
|
21048
|
+
kind: "belief_observed",
|
|
21049
|
+
agentId: "agent-atlas",
|
|
21050
|
+
sessionId: "session-atlas",
|
|
21051
|
+
beliefId: "belief-new-token-every-request",
|
|
21052
|
+
decisionId: "decision-new-token-every-request",
|
|
21053
|
+
statement: "Mint a new checkout token for every request and retry.",
|
|
21054
|
+
confidence: 0.91,
|
|
21055
|
+
evidence: [
|
|
21056
|
+
{
|
|
21057
|
+
kind: "memory",
|
|
21058
|
+
id: "memory-stale-token-policy",
|
|
21059
|
+
label: "Stale project decision",
|
|
21060
|
+
locator: "fixture://remnic/memories/memory-stale-token-policy.md",
|
|
21061
|
+
capture: "fixture"
|
|
21062
|
+
}
|
|
21063
|
+
]
|
|
21165
21064
|
}
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
storage,
|
|
21187
|
-
loadedCard.memory,
|
|
21188
|
-
lock,
|
|
21189
|
-
principal,
|
|
21190
|
-
namespace
|
|
21191
|
-
);
|
|
21192
|
-
const card = this.projectRequiredCard(recoveredMemory, namespace, principal);
|
|
21193
|
-
if (card.card.status === "active") return card.card;
|
|
21194
|
-
if (card.card.status === "rejected") {
|
|
21195
|
-
throw new SupportPassportError(
|
|
21196
|
-
"storage_conflict",
|
|
21197
|
-
"The support card was rejected while its replacement state was recovered.",
|
|
21198
|
-
409
|
|
21199
|
-
);
|
|
21065
|
+
},
|
|
21066
|
+
{
|
|
21067
|
+
occurredAt: at(9),
|
|
21068
|
+
idempotencyKey: "fixture-006",
|
|
21069
|
+
payload: {
|
|
21070
|
+
kind: "agent_output",
|
|
21071
|
+
agentId: "agent-nova",
|
|
21072
|
+
sessionId: "session-nova",
|
|
21073
|
+
outputId: "output-nova-policy",
|
|
21074
|
+
summary: "The contract requires one token per checkout session, refreshed only after expiry.",
|
|
21075
|
+
evidence: [
|
|
21076
|
+
{
|
|
21077
|
+
kind: "agent_output",
|
|
21078
|
+
id: "output-nova-policy",
|
|
21079
|
+
label: "Nova one-shot output",
|
|
21080
|
+
locator: "fixture://codex/nova/final-output.txt",
|
|
21081
|
+
capture: "fixture"
|
|
21082
|
+
},
|
|
21083
|
+
sourceEvidence
|
|
21084
|
+
]
|
|
21200
21085
|
}
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
|
|
21209
|
-
|
|
21210
|
-
|
|
21211
|
-
|
|
21212
|
-
|
|
21213
|
-
|
|
21214
|
-
const currentCard = current ? this.projectOwnedCard(current, namespace, principal) : null;
|
|
21215
|
-
if (currentCard?.card.status === "active") {
|
|
21216
|
-
return await this.finishCommittedApproval(storage, currentCard, lock, principal, namespace);
|
|
21217
|
-
}
|
|
21218
|
-
throw error;
|
|
21086
|
+
},
|
|
21087
|
+
{
|
|
21088
|
+
occurredAt: at(10),
|
|
21089
|
+
idempotencyKey: "fixture-007",
|
|
21090
|
+
payload: {
|
|
21091
|
+
kind: "belief_observed",
|
|
21092
|
+
agentId: "agent-nova",
|
|
21093
|
+
sessionId: "session-nova",
|
|
21094
|
+
beliefId: "belief-refresh-after-expiry",
|
|
21095
|
+
decisionId: "decision-refresh-after-expiry",
|
|
21096
|
+
statement: "Reuse the checkout-session token and refresh it only after expiry.",
|
|
21097
|
+
confidence: 0.98,
|
|
21098
|
+
evidence: [sourceEvidence]
|
|
21219
21099
|
}
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21227
|
-
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
updatedAt,
|
|
21232
|
-
revision: this.revisionFor(card.card, "active", updatedAt)
|
|
21233
|
-
};
|
|
21234
|
-
try {
|
|
21235
|
-
const current = await this.requireCard(storage, card.card.cardId, namespace, principal);
|
|
21236
|
-
return await this.finishCommittedApproval(storage, current, lock, principal, namespace);
|
|
21237
|
-
} catch (error) {
|
|
21238
|
-
if (isStorageConflict(error)) throw error;
|
|
21239
|
-
log.warn(
|
|
21240
|
-
`support passport could not finish replacement approval side effects: ${error instanceof Error ? error.message : String(error)}`
|
|
21241
|
-
);
|
|
21242
|
-
return committedCard;
|
|
21243
|
-
}
|
|
21244
|
-
});
|
|
21245
|
-
}
|
|
21246
|
-
async rejectCard(input) {
|
|
21247
|
-
return await this.changeStatus(input, "pending_review", "rejected");
|
|
21248
|
-
}
|
|
21249
|
-
async withdrawCard(input) {
|
|
21250
|
-
return await this.changeStatus(input, "active", "archived");
|
|
21251
|
-
}
|
|
21252
|
-
async createDraft(storage, input, lock, principal, namespace) {
|
|
21253
|
-
const now = this.now();
|
|
21254
|
-
const reviewBy = input.reviewBy ?? now.toISOString();
|
|
21255
|
-
const storedCards = await this.readStoredCards(storage, lock, principal, namespace);
|
|
21256
|
-
const visibleCards = this.ownerVisibleCards(storedCards);
|
|
21257
|
-
const replacesVisibleCard = visibleCards.some(
|
|
21258
|
-
(item) => input.replacesDraftId === item.card.cardId && item.card.status === "pending_review" || input.supersedes === item.card.cardId && item.card.status === "active"
|
|
21259
|
-
);
|
|
21260
|
-
if (visibleCards.length - (replacesVisibleCard ? 1 : 0) >= MAX_OWNER_VISIBLE_CARDS) {
|
|
21261
|
-
throw new SupportPassportError("invalid_input", "A support passport can contain at most 100 visible cards.", 400);
|
|
21262
|
-
}
|
|
21263
|
-
const maximumOrder = storedCards.reduce((maximum, card) => Math.max(maximum, card.order), -1);
|
|
21264
|
-
const order = input.order ?? maximumOrder + 1;
|
|
21265
|
-
if (!Number.isSafeInteger(order)) {
|
|
21266
|
-
throw new SupportPassportError("storage_conflict", "The support card order range is exhausted.", 409);
|
|
21267
|
-
}
|
|
21268
|
-
const envelope = composeMemoryEnvelope(
|
|
21269
|
-
{
|
|
21270
|
-
content: input.statement,
|
|
21271
|
-
category: "preference",
|
|
21272
|
-
tags: [SUPPORT_PASSPORT_CARD_TAG],
|
|
21273
|
-
structuredAttributes: {
|
|
21274
|
-
...encodeSupportPassportNamespaceAttributes(namespace),
|
|
21275
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner]: computeSupportPassportOwnerKey(principal),
|
|
21276
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.title]: input.title,
|
|
21277
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.category]: input.category,
|
|
21278
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.order]: String(order),
|
|
21279
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.reviewBy]: reviewBy,
|
|
21280
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.sourceMemoryIds]: input.sourceMemoryIds.join(","),
|
|
21281
|
-
...input.replacesDraftId ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacesDraftId]: input.replacesDraftId } : {},
|
|
21282
|
-
...input.replacedRevision ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacedRevision]: input.replacedRevision } : {},
|
|
21283
|
-
...input.draftReplacementPrepared ? { [SUPPORT_PASSPORT_ATTRIBUTE_KEYS.draftReplacementPrepared]: "true" } : {}
|
|
21284
|
-
},
|
|
21285
|
-
sourceReason: "support-passport"
|
|
21286
|
-
},
|
|
21287
|
-
{ source: "support-passport", now: this.now }
|
|
21288
|
-
);
|
|
21289
|
-
if (envelope.sanitizeViolations.length > 0) throw invalidInput();
|
|
21290
|
-
await this.requireOwnerLock(lock);
|
|
21291
|
-
const written = await storage.writeSealedMemory(envelope, {
|
|
21292
|
-
actor: principal,
|
|
21293
|
-
status: "pending_review",
|
|
21294
|
-
lineage: input.sourceMemoryIds.length > 0 ? input.sourceMemoryIds : void 0,
|
|
21295
|
-
supersedes: input.supersedes
|
|
21296
|
-
});
|
|
21297
|
-
if (written.tombstoneBlocked) {
|
|
21298
|
-
throw new SupportPassportError("storage_conflict", "The support card needs memory review before use.", 409);
|
|
21299
|
-
}
|
|
21300
|
-
return this.projectRequiredCard(written.memory, namespace, principal).card;
|
|
21301
|
-
}
|
|
21302
|
-
async changeStatus(input, expectedStatus, nextStatus) {
|
|
21303
|
-
const parsed = SupportPassportCardMutationInputSchema.safeParse(input);
|
|
21304
|
-
if (!parsed.success) throw invalidInput();
|
|
21305
|
-
const { principal, namespace, storage } = await this.resolveOwnerScope(parsed.data.principal);
|
|
21306
|
-
return await withSupportPassportOwnerLock(storage, { namespace, principal }, async (lock) => {
|
|
21307
|
-
let card = await this.requireCard(storage, parsed.data.cardId, namespace, principal);
|
|
21308
|
-
this.requireRevision(card, parsed.data.expectedRevision);
|
|
21309
|
-
this.requireStatus(card, expectedStatus);
|
|
21310
|
-
if (expectedStatus === "pending_review" && nextStatus === "rejected") {
|
|
21311
|
-
await this.rejectPendingReplacementForPredecessor(storage, card, lock, principal, namespace);
|
|
21312
|
-
card = await this.requireCard(storage, card.card.cardId, namespace, principal);
|
|
21313
|
-
this.requireRevision(card, parsed.data.expectedRevision);
|
|
21314
|
-
this.requireStatus(card, expectedStatus);
|
|
21315
|
-
}
|
|
21316
|
-
if (expectedStatus === "pending_review" || expectedStatus === "active" && (card.replacesDraftId || card.memory.frontmatter.supersedes)) {
|
|
21317
|
-
card = this.projectRequiredCard(
|
|
21318
|
-
await this.recoverReplacementTransition(storage, card.memory, lock, principal, namespace, {
|
|
21319
|
-
rollbackConflictedApproval: expectedStatus !== "active"
|
|
21320
|
-
}),
|
|
21321
|
-
namespace,
|
|
21322
|
-
principal
|
|
21323
|
-
);
|
|
21324
|
-
}
|
|
21325
|
-
if (card.card.status === nextStatus) return card.card;
|
|
21326
|
-
this.requireStatus(card, expectedStatus);
|
|
21327
|
-
if (expectedStatus === "active" && nextStatus === "archived") {
|
|
21328
|
-
await this.rejectPendingReplacementForPredecessor(storage, card, lock, principal, namespace);
|
|
21329
|
-
card = await this.requireCard(storage, card.card.cardId, namespace, principal);
|
|
21330
|
-
this.requireRevision(card, parsed.data.expectedRevision);
|
|
21331
|
-
this.requireStatus(card, expectedStatus);
|
|
21332
|
-
}
|
|
21333
|
-
const updatedAt = this.now().toISOString();
|
|
21334
|
-
await this.requireOwnerLock(lock);
|
|
21335
|
-
const changed = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21336
|
-
card.memory,
|
|
21337
|
-
{
|
|
21338
|
-
status: nextStatus,
|
|
21339
|
-
updated: updatedAt,
|
|
21340
|
-
...nextStatus === "archived" ? { archivedAt: updatedAt } : {}
|
|
21341
|
-
},
|
|
21342
|
-
{ actor: principal, reasonCode: nextStatus === "archived" ? "owner-withdrew" : "owner-rejected" }
|
|
21343
|
-
);
|
|
21344
|
-
if (!changed)
|
|
21345
|
-
throw new SupportPassportError(
|
|
21346
|
-
"storage_conflict",
|
|
21347
|
-
"The support card changed before the request completed.",
|
|
21348
|
-
409
|
|
21349
|
-
);
|
|
21350
|
-
return {
|
|
21351
|
-
...card.card,
|
|
21352
|
-
status: nextStatus,
|
|
21353
|
-
updatedAt,
|
|
21354
|
-
revision: this.revisionFor(card.card, nextStatus, updatedAt)
|
|
21355
|
-
};
|
|
21356
|
-
});
|
|
21357
|
-
}
|
|
21358
|
-
revisionFor(card, status, updatedAt) {
|
|
21359
|
-
return computeSupportPassportCardRevision({
|
|
21360
|
-
cardId: card.cardId,
|
|
21361
|
-
title: card.title,
|
|
21362
|
-
statement: card.statement,
|
|
21363
|
-
category: card.category,
|
|
21364
|
-
status,
|
|
21365
|
-
updatedAt,
|
|
21366
|
-
reviewBy: card.reviewBy
|
|
21367
|
-
});
|
|
21368
|
-
}
|
|
21369
|
-
async resolveOwnerScope(principal) {
|
|
21370
|
-
const requestedPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal });
|
|
21371
|
-
const owner = await this.resolveOwner(principal);
|
|
21372
|
-
const namespace = SupportPassportNamespaceSchema.safeParse(owner.namespace);
|
|
21373
|
-
const ownerPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal: owner.principal });
|
|
21374
|
-
if (!requestedPrincipal.success || !namespace.success || !ownerPrincipal.success || ownerPrincipal.data.principal !== requestedPrincipal.data.principal) {
|
|
21375
|
-
throw new SupportPassportError("card_data_invalid", "The support passport owner scope is invalid.", 500);
|
|
21376
|
-
}
|
|
21377
|
-
return { ...owner, principal: ownerPrincipal.data.principal, namespace: namespace.data };
|
|
21378
|
-
}
|
|
21379
|
-
async rejectCreatedDraft(storage, cardId, reasonCode, lock, principal, namespace) {
|
|
21380
|
-
try {
|
|
21381
|
-
const current = await this.requireCard(storage, cardId, namespace, principal);
|
|
21382
|
-
await this.requireOwnerLock(lock);
|
|
21383
|
-
const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21384
|
-
current.memory,
|
|
21385
|
-
{ status: "rejected", updated: this.now().toISOString() },
|
|
21386
|
-
{ actor: principal, reasonCode }
|
|
21387
|
-
);
|
|
21388
|
-
if (!rejected) log.warn("support passport could not roll back a replacement draft");
|
|
21389
|
-
} catch (error) {
|
|
21390
|
-
log.warn(
|
|
21391
|
-
`support passport could not roll back a replacement draft: ${error instanceof Error ? error.message : String(error)}`
|
|
21392
|
-
);
|
|
21393
|
-
}
|
|
21394
|
-
}
|
|
21395
|
-
async requireCard(storage, cardId, namespace, principal) {
|
|
21396
|
-
const stored = await storage.getMemoryById(cardId);
|
|
21397
|
-
const card = stored ? this.projectOwnedCard(stored, namespace, principal) : null;
|
|
21398
|
-
if (!card) throw new SupportPassportError("card_not_found", "The support card was not found.", 404);
|
|
21399
|
-
return card;
|
|
21400
|
-
}
|
|
21401
|
-
projectRequiredCard(memory, namespace, principal) {
|
|
21402
|
-
const card = projectSupportPassportCard(memory);
|
|
21403
|
-
if (!card) throw new SupportPassportError("card_data_invalid", "The support card data is invalid.", 500);
|
|
21404
|
-
if (card.namespace !== namespace || card.owner !== computeSupportPassportOwnerKey(principal)) {
|
|
21405
|
-
throw new SupportPassportError("card_not_found", "The support card was not found.", 404);
|
|
21406
|
-
}
|
|
21407
|
-
return card;
|
|
21408
|
-
}
|
|
21409
|
-
projectOwnedCard(memory, namespace, principal) {
|
|
21410
|
-
const card = projectSupportPassportCard(memory);
|
|
21411
|
-
return card?.namespace === namespace && card.owner === computeSupportPassportOwnerKey(principal) ? card : null;
|
|
21412
|
-
}
|
|
21413
|
-
ownsMemory(memory, namespace, principal) {
|
|
21414
|
-
const attributes = memory.frontmatter.structuredAttributes;
|
|
21415
|
-
return attributes !== void 0 && decodeSupportPassportNamespaceAttributes(attributes) === namespace && attributes[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner] === computeSupportPassportOwnerKey(principal);
|
|
21416
|
-
}
|
|
21417
|
-
async readProjectedCards(storage, namespace, principal) {
|
|
21418
|
-
const owner = computeSupportPassportOwnerKey(principal);
|
|
21419
|
-
const projected = (await storage.readAllMemories()).map(projectSupportPassportCard).filter((card) => card?.namespace === namespace && card.owner === owner);
|
|
21420
|
-
const ids = /* @__PURE__ */ new Set();
|
|
21421
|
-
for (const item of projected) {
|
|
21422
|
-
if (ids.has(item.card.cardId)) {
|
|
21423
|
-
throw new SupportPassportError("card_data_invalid", "Support card IDs must be unique.", 500);
|
|
21424
|
-
}
|
|
21425
|
-
ids.add(item.card.cardId);
|
|
21426
|
-
}
|
|
21427
|
-
return projected;
|
|
21428
|
-
}
|
|
21429
|
-
requireRevision(card, expectedRevision) {
|
|
21430
|
-
if (card.card.revision !== expectedRevision) {
|
|
21431
|
-
throw new SupportPassportError("revision_conflict", "The support card changed after it was loaded.", 409);
|
|
21432
|
-
}
|
|
21433
|
-
}
|
|
21434
|
-
requireStatus(card, status) {
|
|
21435
|
-
if (card.card.status !== status) {
|
|
21436
|
-
throw new SupportPassportError("invalid_card_status", `The support card must have status ${status}.`, 409);
|
|
21437
|
-
}
|
|
21438
|
-
}
|
|
21439
|
-
async readStoredCards(storage, lock, principal, namespace) {
|
|
21440
|
-
const initialVersion = storage.getCorpusScanVersion();
|
|
21441
|
-
const initial = await storage.readAllMemories();
|
|
21442
|
-
for (const memory of initial) {
|
|
21443
|
-
const card = this.projectOwnedCard(memory, namespace, principal);
|
|
21444
|
-
if (card) await this.recoverReplacementTransition(storage, memory, lock, principal, namespace);
|
|
21445
|
-
}
|
|
21446
|
-
const memories = storage.getCorpusScanVersion() === initialVersion ? initial : await storage.readAllMemories();
|
|
21447
|
-
const owner = computeSupportPassportOwnerKey(principal);
|
|
21448
|
-
const projected = memories.map(projectSupportPassportCard).filter((card) => card?.namespace === namespace && card.owner === owner);
|
|
21449
|
-
const ids = /* @__PURE__ */ new Set();
|
|
21450
|
-
for (const item of projected) {
|
|
21451
|
-
if (ids.has(item.card.cardId)) {
|
|
21452
|
-
throw new SupportPassportError("card_data_invalid", "Support card IDs must be unique.", 500);
|
|
21453
|
-
}
|
|
21454
|
-
ids.add(item.card.cardId);
|
|
21455
|
-
}
|
|
21456
|
-
return projected;
|
|
21457
|
-
}
|
|
21458
|
-
ownerVisibleCards(storedCards) {
|
|
21459
|
-
const visibleCards = storedCards.filter(
|
|
21460
|
-
(item) => OWNER_VISIBLE_STATUSES.has(item.card.status) && !item.draftReplacementPrepared
|
|
21461
|
-
);
|
|
21462
|
-
if (visibleCards.length <= MAX_OWNER_VISIBLE_CARDS) return visibleCards;
|
|
21463
|
-
const activeCardsWithPendingReplacements = new Set(
|
|
21464
|
-
visibleCards.filter((item) => item.card.status === "pending_review").map((item) => item.memory.frontmatter.supersedes).filter((cardId) => typeof cardId === "string")
|
|
21465
|
-
);
|
|
21466
|
-
return visibleCards.filter(
|
|
21467
|
-
(item) => item.card.status !== "active" || !activeCardsWithPendingReplacements.has(item.card.cardId)
|
|
21468
|
-
);
|
|
21469
|
-
}
|
|
21470
|
-
async preparePriorForReplacement(storage, replacement, lock, principal, namespace) {
|
|
21471
|
-
const priorId = replacement.memory.frontmatter.supersedes;
|
|
21472
|
-
if (!priorId) return null;
|
|
21473
|
-
const priorMemory = await storage.getMemoryById(priorId);
|
|
21474
|
-
const priorIsOwned = priorMemory ? this.ownsMemory(priorMemory, namespace, principal) : false;
|
|
21475
|
-
const alreadyRetired = priorIsOwned && priorMemory?.frontmatter.status === "superseded" && priorMemory.frontmatter.supersededBy === replacement.card.cardId;
|
|
21476
|
-
const prior = priorMemory && priorIsOwned && !alreadyRetired ? projectSupportPassportCard(priorMemory) : null;
|
|
21477
|
-
if (prior?.card.status === "rejected") return null;
|
|
21478
|
-
if (!priorMemory || !alreadyRetired && prior?.card.status !== "active") {
|
|
21479
|
-
throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
|
|
21480
|
-
}
|
|
21481
|
-
if (alreadyRetired) return priorId;
|
|
21482
|
-
const retiredAt = this.now().toISOString();
|
|
21483
|
-
await this.requireOwnerLock(lock);
|
|
21484
|
-
const retired = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21485
|
-
priorMemory,
|
|
21486
|
-
{
|
|
21487
|
-
status: "superseded",
|
|
21488
|
-
supersededBy: replacement.card.cardId,
|
|
21489
|
-
supersededAt: retiredAt,
|
|
21490
|
-
supersessionCause: "direct",
|
|
21491
|
-
updated: retiredAt
|
|
21492
|
-
},
|
|
21493
|
-
{
|
|
21494
|
-
actor: principal,
|
|
21495
|
-
reasonCode: "support-passport-replacement-pending",
|
|
21496
|
-
relatedMemoryIds: [replacement.card.cardId]
|
|
21497
|
-
}
|
|
21498
|
-
);
|
|
21499
|
-
if (!retired) {
|
|
21500
|
-
throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
|
|
21501
|
-
}
|
|
21502
|
-
return priorId;
|
|
21503
|
-
}
|
|
21504
|
-
async rejectPendingReplacementForPredecessor(storage, predecessor, lock, principal, namespace) {
|
|
21505
|
-
const storedCards = predecessor.card.status === "active" ? await this.readStoredCards(storage, lock, principal, namespace) : await this.readProjectedCards(storage, namespace, principal);
|
|
21506
|
-
const replacements = storedCards.filter((item) => {
|
|
21507
|
-
if (item.card.status !== "pending_review") return false;
|
|
21508
|
-
return predecessor.card.status === "pending_review" ? item.replacesDraftId === predecessor.card.cardId : item.memory.frontmatter.supersedes === predecessor.card.cardId;
|
|
21509
|
-
});
|
|
21510
|
-
if (replacements.length > 1) {
|
|
21511
|
-
throw new SupportPassportError(
|
|
21512
|
-
"storage_conflict",
|
|
21513
|
-
"Multiple support card edits target the card being withdrawn.",
|
|
21514
|
-
409
|
|
21515
|
-
);
|
|
21516
|
-
}
|
|
21517
|
-
const [replacement] = replacements;
|
|
21518
|
-
if (!replacement) return;
|
|
21519
|
-
await this.requireOwnerLock(lock);
|
|
21520
|
-
const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21521
|
-
replacement.memory,
|
|
21522
|
-
{ status: "rejected", updated: this.now().toISOString() },
|
|
21523
|
-
{
|
|
21524
|
-
actor: principal,
|
|
21525
|
-
reasonCode: predecessor.card.status === "pending_review" ? "source-draft-rejected" : "predecessor-withdrawn"
|
|
21526
|
-
}
|
|
21527
|
-
);
|
|
21528
|
-
if (rejected) return;
|
|
21529
|
-
const current = await storage.getMemoryById(replacement.card.cardId);
|
|
21530
|
-
const currentCard = current ? this.projectOwnedCard(current, namespace, principal) : null;
|
|
21531
|
-
if (currentCard?.card.status !== "rejected") {
|
|
21532
|
-
throw new SupportPassportError("storage_conflict", "The pending support card edit could not be cancelled.", 409);
|
|
21533
|
-
}
|
|
21534
|
-
}
|
|
21535
|
-
async validatePriorForReplacement(storage, replacement, namespace, principal) {
|
|
21536
|
-
const priorId = replacement.memory.frontmatter.supersedes;
|
|
21537
|
-
if (!priorId) return;
|
|
21538
|
-
const priorMemory = await storage.getMemoryById(priorId);
|
|
21539
|
-
const priorIsOwned = priorMemory ? this.ownsMemory(priorMemory, namespace, principal) : false;
|
|
21540
|
-
const alreadyRetired = priorIsOwned && priorMemory?.frontmatter.status === "superseded" && priorMemory.frontmatter.supersededBy === replacement.card.cardId;
|
|
21541
|
-
const prior = priorMemory && priorIsOwned && !alreadyRetired ? projectSupportPassportCard(priorMemory) : null;
|
|
21542
|
-
if (prior?.card.status === "rejected" || alreadyRetired) return;
|
|
21543
|
-
if (!priorMemory || prior?.card.status !== "active") {
|
|
21544
|
-
throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
|
|
21545
|
-
}
|
|
21546
|
-
}
|
|
21547
|
-
async recoverReplacementTransition(storage, memory, lock, principal, namespace, options = {}) {
|
|
21548
|
-
const replacement = this.projectOwnedCard(memory, namespace, principal);
|
|
21549
|
-
if (replacement?.card.status !== "pending_review" && replacement?.card.status !== "active") return memory;
|
|
21550
|
-
if (!replacement.replacesDraftId && !memory.frontmatter.supersedes) return memory;
|
|
21551
|
-
if (replacement.card.status === "active" && memory.frontmatter.structuredAttributes?.[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete] === "true") {
|
|
21552
|
-
return memory;
|
|
21553
|
-
}
|
|
21554
|
-
await this.recoverReplacedDraft(storage, replacement, lock, principal, namespace);
|
|
21555
|
-
const currentMemory = await storage.getMemoryById(replacement.card.cardId) ?? memory;
|
|
21556
|
-
const currentCard = this.projectOwnedCard(currentMemory, namespace, principal);
|
|
21557
|
-
if (currentCard?.card.status !== "pending_review" && currentCard?.card.status !== "active") {
|
|
21558
|
-
return currentMemory;
|
|
21559
|
-
}
|
|
21560
|
-
if (currentCard.card.status === "pending_review") {
|
|
21561
|
-
const priorId = currentMemory.frontmatter.supersedes;
|
|
21562
|
-
if (!priorId) return currentMemory;
|
|
21563
|
-
const prior = await storage.getMemoryById(priorId);
|
|
21564
|
-
if (prior && this.ownsMemory(prior, namespace, principal) && prior.frontmatter.status === "superseded" && prior.frontmatter.supersededBy === replacement.card.cardId) {
|
|
21565
|
-
await this.restorePriorAfterApprovalFailure(
|
|
21566
|
-
storage,
|
|
21567
|
-
priorId,
|
|
21568
|
-
replacement.card.cardId,
|
|
21569
|
-
lock,
|
|
21570
|
-
principal,
|
|
21571
|
-
namespace
|
|
21572
|
-
);
|
|
21573
|
-
}
|
|
21574
|
-
return await storage.getMemoryById(replacement.card.cardId) ?? currentMemory;
|
|
21575
|
-
}
|
|
21576
|
-
try {
|
|
21577
|
-
await this.completeReplacementAfterActivation(storage, currentCard, lock, principal, namespace);
|
|
21578
|
-
} catch (error) {
|
|
21579
|
-
if (!isStorageConflict(error)) throw error;
|
|
21580
|
-
if (options.rollbackConflictedApproval === false) throw error;
|
|
21581
|
-
await this.rollbackConflictedApproval(storage, currentCard.card.cardId, lock, principal, namespace);
|
|
21582
|
-
}
|
|
21583
|
-
return await storage.getMemoryById(replacement.card.cardId) ?? currentMemory;
|
|
21584
|
-
}
|
|
21585
|
-
async completeReplacementAfterActivation(storage, replacement, lock, principal, namespace) {
|
|
21586
|
-
const priorId = await this.preparePriorForReplacement(storage, replacement, lock, principal, namespace);
|
|
21587
|
-
if (priorId && !await this.completePriorRetirement(storage, priorId, replacement, lock, principal, namespace)) {
|
|
21588
|
-
throw new SupportPassportError("storage_conflict", "The prior support card changed before replacement.", 409);
|
|
21589
|
-
}
|
|
21590
|
-
await this.markReplacementComplete(storage, replacement.card.cardId, lock, principal, namespace);
|
|
21591
|
-
}
|
|
21592
|
-
async finishCommittedApproval(storage, replacement, lock, principal, namespace) {
|
|
21593
|
-
try {
|
|
21594
|
-
if (replacement.replacesDraftId || replacement.memory.frontmatter.supersedes) {
|
|
21595
|
-
await this.completeReplacementAfterActivation(storage, replacement, lock, principal, namespace);
|
|
21596
|
-
}
|
|
21597
|
-
} catch (error) {
|
|
21598
|
-
if (isStorageConflict(error)) {
|
|
21599
|
-
await this.rollbackConflictedApproval(storage, replacement.card.cardId, lock, principal, namespace);
|
|
21600
|
-
throw error;
|
|
21601
|
-
}
|
|
21602
|
-
log.warn(
|
|
21603
|
-
`support passport could not finish replacement approval side effects: ${error instanceof Error ? error.message : String(error)}`
|
|
21604
|
-
);
|
|
21605
|
-
}
|
|
21606
|
-
return replacement.card;
|
|
21607
|
-
}
|
|
21608
|
-
async rollbackConflictedApproval(storage, replacementId, lock, principal, namespace) {
|
|
21609
|
-
const replacement = await this.requireCard(storage, replacementId, namespace, principal);
|
|
21610
|
-
if (replacement.card.status !== "active") return;
|
|
21611
|
-
await this.requireOwnerLock(lock);
|
|
21612
|
-
const rolledBack = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21613
|
-
replacement.memory,
|
|
21614
|
-
{ status: "pending_review", updated: this.now().toISOString() },
|
|
21615
|
-
{ actor: principal, reasonCode: "replacement-predecessor-conflict" }
|
|
21616
|
-
);
|
|
21617
|
-
if (!rolledBack) {
|
|
21618
|
-
throw new SupportPassportError(
|
|
21619
|
-
"storage_conflict",
|
|
21620
|
-
"The replacement changed while its approval was rolled back.",
|
|
21621
|
-
409
|
|
21622
|
-
);
|
|
21623
|
-
}
|
|
21624
|
-
const priorId = replacement.memory.frontmatter.supersedes;
|
|
21625
|
-
if (priorId) {
|
|
21626
|
-
await this.restorePriorAfterApprovalFailure(storage, priorId, replacementId, lock, principal, namespace);
|
|
21627
|
-
}
|
|
21628
|
-
}
|
|
21629
|
-
async completePriorRetirement(storage, priorId, replacement, lock, principal, namespace) {
|
|
21630
|
-
const replacementId = replacement.card.cardId;
|
|
21631
|
-
const prior = await storage.getMemoryById(priorId);
|
|
21632
|
-
if (!prior || !this.ownsMemory(prior, namespace, principal) || prior.frontmatter.status !== "superseded" || prior.frontmatter.supersededBy !== replacementId) {
|
|
21633
|
-
return false;
|
|
21634
|
-
}
|
|
21635
|
-
await this.requireOwnerLock(lock);
|
|
21636
|
-
const completed = await storage.supersedeMemory(
|
|
21637
|
-
priorId,
|
|
21638
|
-
replacementId,
|
|
21639
|
-
"support-passport-replacement",
|
|
21640
|
-
{ supersessionCause: "direct" },
|
|
21641
|
-
{
|
|
21642
|
-
actor: principal,
|
|
21643
|
-
requireActive: true,
|
|
21644
|
-
acceptExactReplay: true,
|
|
21645
|
-
expectedSnapshot: prior,
|
|
21646
|
-
audit: {
|
|
21647
|
-
content: stripAttributesSuffix(prior.content),
|
|
21648
|
-
tags: ["supersession", "auto-resolved", "support-passport-audit"],
|
|
21649
|
-
structuredAttributes: {
|
|
21650
|
-
...encodeSupportPassportNamespaceAttributes(namespace),
|
|
21651
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.owner]: computeSupportPassportOwnerKey(principal)
|
|
21652
|
-
},
|
|
21653
|
-
source: "support-passport"
|
|
21654
|
-
}
|
|
21655
|
-
}
|
|
21656
|
-
);
|
|
21657
|
-
if (!completed) log.warn("support passport could not complete replacement retirement side effects");
|
|
21658
|
-
return completed;
|
|
21659
|
-
}
|
|
21660
|
-
async recoverReplacedDraft(storage, replacement, lock, principal, namespace) {
|
|
21661
|
-
if (!replacement.replacesDraftId) return;
|
|
21662
|
-
const replacedDraft = await storage.getMemoryById(replacement.replacesDraftId);
|
|
21663
|
-
const projectedDraft = replacedDraft ? this.projectOwnedCard(replacedDraft, namespace, principal) : null;
|
|
21664
|
-
if (replacedDraft && projectedDraft?.card.status === "pending_review" && projectedDraft.card.revision === replacement.replacedRevision) {
|
|
21665
|
-
await this.requireOwnerLock(lock);
|
|
21666
|
-
const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21667
|
-
replacedDraft,
|
|
21668
|
-
{ status: "rejected", updated: this.now().toISOString() },
|
|
21669
|
-
{ actor: principal, reasonCode: "complete-draft-replacement" }
|
|
21670
|
-
);
|
|
21671
|
-
if (rejected) {
|
|
21672
|
-
await this.finishPreparedDraftReplacement(storage, replacement.card.cardId, lock, principal, namespace);
|
|
21673
|
-
return;
|
|
21674
|
-
}
|
|
21675
|
-
}
|
|
21676
|
-
const currentDraft = await storage.getMemoryById(replacement.replacesDraftId);
|
|
21677
|
-
if (currentDraft && this.ownsMemory(currentDraft, namespace, principal) && currentDraft.frontmatter.status === "rejected") {
|
|
21678
|
-
await this.finishPreparedDraftReplacement(storage, replacement.card.cardId, lock, principal, namespace);
|
|
21679
|
-
return;
|
|
21680
|
-
}
|
|
21681
|
-
if (currentDraft && this.ownsMemory(currentDraft, namespace, principal) && currentDraft.frontmatter.status === "pending_review") {
|
|
21682
|
-
throw new SupportPassportError("storage_conflict", "The replaced draft changed during recovery.", 409);
|
|
21683
|
-
}
|
|
21684
|
-
await this.rejectOrphanedReplacement(storage, replacement.card.cardId, lock, principal, namespace);
|
|
21685
|
-
}
|
|
21686
|
-
async finishPreparedDraftReplacement(storage, replacementId, lock, principal, namespace) {
|
|
21687
|
-
const replacement = await this.requireCard(storage, replacementId, namespace, principal);
|
|
21688
|
-
if (!replacement.draftReplacementPrepared) return replacement.card;
|
|
21689
|
-
const structuredAttributes = { ...replacement.memory.frontmatter.structuredAttributes };
|
|
21690
|
-
delete structuredAttributes[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.draftReplacementPrepared];
|
|
21691
|
-
await this.requireOwnerLock(lock);
|
|
21692
|
-
const finished = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21693
|
-
replacement.memory,
|
|
21694
|
-
{ structuredAttributes },
|
|
21695
|
-
{ actor: principal, reasonCode: "draft-replacement-complete" }
|
|
21696
|
-
);
|
|
21697
|
-
if (finished) {
|
|
21698
|
-
return this.projectRequiredCard(
|
|
21699
|
-
{ ...replacement.memory, frontmatter: { ...replacement.memory.frontmatter, structuredAttributes } },
|
|
21700
|
-
namespace,
|
|
21701
|
-
principal
|
|
21702
|
-
).card;
|
|
21703
|
-
}
|
|
21704
|
-
const current = await this.requireCard(storage, replacementId, namespace, principal);
|
|
21705
|
-
if (!current.draftReplacementPrepared) return current.card;
|
|
21706
|
-
throw new SupportPassportError("storage_conflict", "The support card edit could not be completed.", 409);
|
|
21707
|
-
}
|
|
21708
|
-
async rejectOrphanedReplacement(storage, replacementId, lock, principal, namespace) {
|
|
21709
|
-
const currentReplacement = await this.requireCard(storage, replacementId, namespace, principal);
|
|
21710
|
-
if (currentReplacement.card.status === "rejected") return;
|
|
21711
|
-
this.requireStatus(currentReplacement, "pending_review");
|
|
21712
|
-
await this.requireOwnerLock(lock);
|
|
21713
|
-
const rejected = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21714
|
-
currentReplacement.memory,
|
|
21715
|
-
{ status: "rejected", updated: this.now().toISOString() },
|
|
21716
|
-
{ actor: principal, reasonCode: "replaced-draft-approved" }
|
|
21717
|
-
);
|
|
21718
|
-
if (rejected) return;
|
|
21719
|
-
const latest = await storage.getMemoryById(replacementId);
|
|
21720
|
-
if (latest?.frontmatter.status !== "rejected") {
|
|
21721
|
-
throw new SupportPassportError("storage_conflict", "The orphaned replacement could not be rejected.", 409);
|
|
21722
|
-
}
|
|
21723
|
-
}
|
|
21724
|
-
async restorePriorAfterApprovalFailure(storage, priorId, replacementId, lock, principal, namespace) {
|
|
21725
|
-
const replacement = await storage.getMemoryById(replacementId);
|
|
21726
|
-
if (replacement && !this.ownsMemory(replacement, namespace, principal)) {
|
|
21727
|
-
throw new SupportPassportError("storage_conflict", "The replacement support card changed ownership.", 409);
|
|
21728
|
-
}
|
|
21729
|
-
if (replacement?.frontmatter.status === "active") return;
|
|
21730
|
-
const prior = await storage.getMemoryById(priorId);
|
|
21731
|
-
if (prior && !this.ownsMemory(prior, namespace, principal)) {
|
|
21732
|
-
throw new SupportPassportError("storage_conflict", "The prior support card changed ownership.", 409);
|
|
21733
|
-
}
|
|
21734
|
-
if (prior?.frontmatter.status === "active" && prior.frontmatter.supersededBy === void 0) return;
|
|
21735
|
-
if (prior?.frontmatter.status !== "superseded" || prior.frontmatter.supersededBy !== replacementId) {
|
|
21736
|
-
throw new SupportPassportError("storage_conflict", "The prior support card could not be restored.", 409);
|
|
21737
|
-
}
|
|
21738
|
-
await this.requireOwnerLock(lock);
|
|
21739
|
-
const restored = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21740
|
-
prior,
|
|
21741
|
-
{
|
|
21742
|
-
status: "active",
|
|
21743
|
-
supersededBy: void 0,
|
|
21744
|
-
supersededAt: void 0,
|
|
21745
|
-
supersessionCause: void 0,
|
|
21746
|
-
invalidatedBy: void 0,
|
|
21747
|
-
updated: this.now().toISOString()
|
|
21748
|
-
},
|
|
21749
|
-
{ actor: principal, reasonCode: "replacement-activation-failed" }
|
|
21750
|
-
);
|
|
21751
|
-
if (restored) return;
|
|
21752
|
-
const currentPrior = await storage.getMemoryById(priorId);
|
|
21753
|
-
if (currentPrior?.frontmatter.status === "active" && currentPrior.frontmatter.supersededBy === void 0) return;
|
|
21754
|
-
throw new SupportPassportError("storage_conflict", "The prior support card could not be restored.", 409);
|
|
21755
|
-
}
|
|
21756
|
-
async markReplacementComplete(storage, replacementId, lock, principal, namespace) {
|
|
21757
|
-
const replacement = await this.requireCard(storage, replacementId, namespace, principal);
|
|
21758
|
-
if (replacement.memory.frontmatter.structuredAttributes?.[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete] === "true") {
|
|
21759
|
-
return;
|
|
21760
|
-
}
|
|
21761
|
-
await this.requireOwnerLock(lock);
|
|
21762
|
-
const marked = await storage.writeMemoryFrontmatterIfUnchanged(
|
|
21763
|
-
replacement.memory,
|
|
21764
|
-
{
|
|
21765
|
-
structuredAttributes: {
|
|
21766
|
-
...replacement.memory.frontmatter.structuredAttributes,
|
|
21767
|
-
[SUPPORT_PASSPORT_ATTRIBUTE_KEYS.replacementComplete]: "true"
|
|
21768
|
-
}
|
|
21769
|
-
},
|
|
21770
|
-
{ actor: principal, reasonCode: "replacement-side-effects-complete" }
|
|
21771
|
-
);
|
|
21772
|
-
if (!marked) log.warn("support passport could not mark replacement side effects complete");
|
|
21773
|
-
}
|
|
21774
|
-
async requireOwnerLock(lock) {
|
|
21775
|
-
if (await lock.refresh()) return;
|
|
21776
|
-
throw new SupportPassportError("storage_conflict", "The support passport lock changed. Try again.", 409);
|
|
21777
|
-
}
|
|
21778
|
-
};
|
|
21779
|
-
|
|
21780
|
-
// src/support-passport/grant-contracts.ts
|
|
21781
|
-
import { z } from "zod";
|
|
21782
|
-
var IsoTimestampSchema = z.string().datetime({ offset: true }).refine((value) => parseIsoOffsetTimestamp(value) !== null, "timestamp must be a real date");
|
|
21783
|
-
var RevisionSchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
21784
|
-
var GrantIdSchema = z.string().uuid().transform((value) => value.toLowerCase());
|
|
21785
|
-
var SupportPassportGrantCardRefSchema = z.object({
|
|
21786
|
-
cardId: SupportPassportMemoryIdSchema,
|
|
21787
|
-
revision: RevisionSchema
|
|
21788
|
-
}).strict();
|
|
21789
|
-
var SupportPassportGrantStateSchema = z.object({
|
|
21790
|
-
schemaVersion: z.literal(1),
|
|
21791
|
-
stateVersion: z.number().int().positive(),
|
|
21792
|
-
grantId: GrantIdSchema,
|
|
21793
|
-
namespace: SupportPassportNamespaceSchema,
|
|
21794
|
-
principalHash: RevisionSchema,
|
|
21795
|
-
ownerLockKey: RevisionSchema,
|
|
21796
|
-
secretHash: RevisionSchema,
|
|
21797
|
-
cards: z.array(SupportPassportGrantCardRefSchema).min(1).max(8),
|
|
21798
|
-
createdAt: IsoTimestampSchema,
|
|
21799
|
-
expiresAt: IsoTimestampSchema,
|
|
21800
|
-
revokedAt: IsoTimestampSchema.optional()
|
|
21801
|
-
}).strict().superRefine((grant, ctx) => {
|
|
21802
|
-
const ids = /* @__PURE__ */ new Set();
|
|
21803
|
-
for (const [index, card] of grant.cards.entries()) {
|
|
21804
|
-
if (ids.has(card.cardId)) {
|
|
21805
|
-
ctx.addIssue({
|
|
21806
|
-
code: z.ZodIssueCode.custom,
|
|
21807
|
-
message: "card IDs must be unique",
|
|
21808
|
-
path: ["cards", index, "cardId"]
|
|
21809
|
-
});
|
|
21810
|
-
}
|
|
21811
|
-
ids.add(card.cardId);
|
|
21812
|
-
}
|
|
21813
|
-
if (Date.parse(grant.expiresAt) <= Date.parse(grant.createdAt)) {
|
|
21814
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "expiresAt must follow createdAt", path: ["expiresAt"] });
|
|
21815
|
-
}
|
|
21816
|
-
});
|
|
21817
|
-
var SupportPassportCreateGrantInputSchema = z.object({
|
|
21818
|
-
principal: z.string().trim().min(1).max(512),
|
|
21819
|
-
cards: z.array(SupportPassportGrantCardRefSchema).min(1).max(8),
|
|
21820
|
-
expiresAt: IsoTimestampSchema
|
|
21821
|
-
}).strict().superRefine((input, ctx) => {
|
|
21822
|
-
const ids = /* @__PURE__ */ new Set();
|
|
21823
|
-
for (const [index, card] of input.cards.entries()) {
|
|
21824
|
-
if (ids.has(card.cardId)) {
|
|
21825
|
-
ctx.addIssue({
|
|
21826
|
-
code: z.ZodIssueCode.custom,
|
|
21827
|
-
message: "card IDs must be unique",
|
|
21828
|
-
path: ["cards", index, "cardId"]
|
|
21829
|
-
});
|
|
21830
|
-
}
|
|
21831
|
-
ids.add(card.cardId);
|
|
21832
|
-
}
|
|
21833
|
-
});
|
|
21834
|
-
var SupportPassportOwnerGrantSchema = z.object({
|
|
21835
|
-
grantId: GrantIdSchema,
|
|
21836
|
-
stateVersion: z.number().int().positive(),
|
|
21837
|
-
cards: z.array(SupportPassportGrantCardRefSchema).min(1).max(8),
|
|
21838
|
-
createdAt: IsoTimestampSchema,
|
|
21839
|
-
expiresAt: IsoTimestampSchema,
|
|
21840
|
-
revokedAt: IsoTimestampSchema.optional(),
|
|
21841
|
-
status: z.enum(["active", "expired", "revoked"])
|
|
21842
|
-
}).strict();
|
|
21843
|
-
var SupportPassportCreatedGrantSchema = z.object({
|
|
21844
|
-
grant: SupportPassportOwnerGrantSchema,
|
|
21845
|
-
secret: z.string().regex(/^[A-Za-z0-9_-]{43}$/)
|
|
21846
|
-
}).strict();
|
|
21847
|
-
var SupportPassportPublicCardSchema = z.object({
|
|
21848
|
-
cardId: SupportPassportMemoryIdSchema,
|
|
21849
|
-
title: z.string().trim().min(1).max(80),
|
|
21850
|
-
statement: z.string().trim().min(1).max(500),
|
|
21851
|
-
category: SupportPassportCardCategorySchema,
|
|
21852
|
-
updatedAt: IsoTimestampSchema
|
|
21853
|
-
}).strict();
|
|
21854
|
-
var SupportPassportPublicGuideSchema = z.object({
|
|
21855
|
-
schemaVersion: z.literal(1),
|
|
21856
|
-
grantId: GrantIdSchema,
|
|
21857
|
-
expiresAt: IsoTimestampSchema,
|
|
21858
|
-
updatedAt: IsoTimestampSchema,
|
|
21859
|
-
cards: z.array(SupportPassportPublicCardSchema).min(1).max(8)
|
|
21860
|
-
}).strict();
|
|
21861
|
-
var SupportPassportRevokeGrantInputSchema = z.object({
|
|
21862
|
-
principal: z.string().trim().min(1).max(512),
|
|
21863
|
-
grantId: GrantIdSchema,
|
|
21864
|
-
expectedStateVersion: z.number().int().positive().optional()
|
|
21865
|
-
}).strict();
|
|
21866
|
-
var SupportPassportListGrantsInputSchema = z.object({
|
|
21867
|
-
principal: z.string().trim().min(1).max(512)
|
|
21868
|
-
}).strict();
|
|
21869
|
-
|
|
21870
|
-
// src/support-passport/grant-store.ts
|
|
21871
|
-
import { createHash as createHash10, randomBytes as randomBytes3, randomUUID as randomUUID3, timingSafeEqual } from "crypto";
|
|
21872
|
-
import { lstat as lstat4, open as open2, readdir as readdir4 } from "fs/promises";
|
|
21873
|
-
import path23 from "path";
|
|
21874
|
-
|
|
21875
|
-
// src/support-passport/private-file.ts
|
|
21876
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
21877
|
-
import { constants as fsConstants } from "fs";
|
|
21878
|
-
import { lstat as lstat3, mkdir as mkdir7, open, rename, rm, stat as stat4 } from "fs/promises";
|
|
21879
|
-
import path22 from "path";
|
|
21880
|
-
var UNSUPPORTED_DIRECTORY_SYNC_ERRORS = /* @__PURE__ */ new Set(["EINVAL", "ENOSYS", "ENOTSUP", "EOPNOTSUPP"]);
|
|
21881
|
-
var NON_WRITABLE_ANCESTOR_SYNC_ERRORS = /* @__PURE__ */ new Set(["EROFS", "EPERM", "EACCES"]);
|
|
21882
|
-
function assertStableDirectory(before, opened, after, errorMessage) {
|
|
21883
|
-
if (before.isSymbolicLink() || !before.isDirectory() || after.isSymbolicLink() || !after.isDirectory() || before.dev !== opened.dev || before.ino !== opened.ino || after.dev !== opened.dev || after.ino !== opened.ino) {
|
|
21884
|
-
throw new Error(errorMessage);
|
|
21885
|
-
}
|
|
21886
|
-
}
|
|
21887
|
-
function assertStableRegularFile(before, opened, after, errorMessage) {
|
|
21888
|
-
if (before.isSymbolicLink() || !before.isFile() || after.isSymbolicLink() || !after.isFile() || before.dev !== opened.dev || before.ino !== opened.ino || after.dev !== opened.dev || after.ino !== opened.ino || opened.nlink !== 1) {
|
|
21889
|
-
throw new Error(errorMessage);
|
|
21890
|
-
}
|
|
21891
|
-
}
|
|
21892
|
-
function openFlags(...flags) {
|
|
21893
|
-
let combined = 0;
|
|
21894
|
-
for (const flag of flags) combined |= typeof flag === "number" ? flag : 0;
|
|
21895
|
-
return combined;
|
|
21896
|
-
}
|
|
21897
|
-
function assertContainedPath(trustedRoot, directory, errorMessage) {
|
|
21898
|
-
const relative = path22.relative(path22.resolve(trustedRoot), path22.resolve(directory));
|
|
21899
|
-
if (relative === ".." || relative.startsWith(`..${path22.sep}`) || path22.isAbsolute(relative)) {
|
|
21900
|
-
throw new Error(errorMessage);
|
|
21901
|
-
}
|
|
21902
|
-
}
|
|
21903
|
-
async function openDirectoryNoFollow(directory, errorMessage) {
|
|
21904
|
-
const before = await lstat3(directory);
|
|
21905
|
-
if (before.isSymbolicLink() || !before.isDirectory()) throw new Error(errorMessage);
|
|
21906
|
-
const handle = await open(
|
|
21907
|
-
directory,
|
|
21908
|
-
openFlags(fsConstants.O_RDONLY, fsConstants.O_DIRECTORY, fsConstants.O_NOFOLLOW)
|
|
21909
|
-
);
|
|
21910
|
-
try {
|
|
21911
|
-
const opened = await handle.stat();
|
|
21912
|
-
assertStableDirectory(before, opened, await lstat3(directory), errorMessage);
|
|
21913
|
-
return { before, opened, handle };
|
|
21914
|
-
} catch (error) {
|
|
21915
|
-
await handle.close().catch(() => void 0);
|
|
21916
|
-
throw error;
|
|
21917
|
-
}
|
|
21918
|
-
}
|
|
21919
|
-
async function closeDirectoryHandles(handles) {
|
|
21920
|
-
for (const handle of handles.reverse()) await handle.close().catch(() => void 0);
|
|
21921
|
-
}
|
|
21922
|
-
async function syncDirectoryHandle(handle) {
|
|
21923
|
-
try {
|
|
21924
|
-
await handle.sync();
|
|
21925
|
-
} catch (error) {
|
|
21926
|
-
const code = error.code;
|
|
21927
|
-
if (!UNSUPPORTED_DIRECTORY_SYNC_ERRORS.has(code ?? "")) throw error;
|
|
21928
|
-
}
|
|
21929
|
-
}
|
|
21930
|
-
async function resolvePrivateDirectoryPath(directory, handle, opened, errorMessage, platform = process.platform) {
|
|
21931
|
-
const descriptorRoot = requirePrivateFileDescriptorRoot(platform, errorMessage);
|
|
21932
|
-
const pinnedPath = path22.join(descriptorRoot, String(handle.fd));
|
|
21933
|
-
const metadata = await stat4(pinnedPath);
|
|
21934
|
-
if (!metadata.isDirectory() || metadata.dev !== opened.dev || metadata.ino !== opened.ino) {
|
|
21935
|
-
throw new Error(errorMessage);
|
|
21936
|
-
}
|
|
21937
|
-
return pinnedPath;
|
|
21938
|
-
}
|
|
21939
|
-
function requirePrivateFileDescriptorRoot(platform, errorMessage) {
|
|
21940
|
-
if (platform === "linux") return "/proc/self/fd";
|
|
21941
|
-
if (platform === "darwin" || platform === "freebsd" || platform === "openbsd") return "/dev/fd";
|
|
21942
|
-
throw new Error(errorMessage);
|
|
21943
|
-
}
|
|
21944
|
-
async function openStableDirectoryFromRoot(trustedRoot, directory, errorMessage, platform = process.platform) {
|
|
21945
|
-
const root = path22.resolve(trustedRoot);
|
|
21946
|
-
const target = path22.resolve(directory);
|
|
21947
|
-
assertContainedPath(root, target, errorMessage);
|
|
21948
|
-
requirePrivateFileDescriptorRoot(platform, errorMessage);
|
|
21949
|
-
const relative = path22.relative(root, target);
|
|
21950
|
-
const components = relative === "" ? [] : relative.split(path22.sep);
|
|
21951
|
-
const handles = [];
|
|
21952
|
-
let currentPath = root;
|
|
21953
|
-
try {
|
|
21954
|
-
let current = await openDirectoryNoFollow(root, errorMessage);
|
|
21955
|
-
handles.push(current.handle);
|
|
21956
|
-
for (const component of components) {
|
|
21957
|
-
const pinnedParent = await resolvePrivateDirectoryPath(currentPath, current.handle, current.opened, errorMessage);
|
|
21958
|
-
const child = await openDirectoryNoFollow(path22.join(pinnedParent, component), errorMessage);
|
|
21959
|
-
handles.push(child.handle);
|
|
21960
|
-
assertStableDirectory(current.before, current.opened, await lstat3(currentPath), errorMessage);
|
|
21961
|
-
currentPath = path22.join(currentPath, component);
|
|
21962
|
-
current = child;
|
|
21963
|
-
}
|
|
21964
|
-
assertStableDirectory(current.before, current.opened, await lstat3(target), errorMessage);
|
|
21965
|
-
return {
|
|
21966
|
-
...current,
|
|
21967
|
-
handles,
|
|
21968
|
-
pinnedDirectory: await resolvePrivateDirectoryPath(
|
|
21969
|
-
target,
|
|
21970
|
-
current.handle,
|
|
21971
|
-
current.opened,
|
|
21972
|
-
errorMessage,
|
|
21973
|
-
platform
|
|
21974
|
-
)
|
|
21975
|
-
};
|
|
21976
|
-
} catch (error) {
|
|
21977
|
-
await closeDirectoryHandles(handles);
|
|
21978
|
-
throw error;
|
|
21979
|
-
}
|
|
21980
|
-
}
|
|
21981
|
-
async function ensurePrivateDirectoryNoFollow(trustedRoot, directory, errorMessage, syncVerifiedParent = syncDirectoryHandle, hardenExistingChildren = true, platform = process.platform) {
|
|
21982
|
-
const root = path22.resolve(trustedRoot);
|
|
21983
|
-
const target = path22.resolve(directory);
|
|
21984
|
-
assertContainedPath(root, target, errorMessage);
|
|
21985
|
-
const relative = path22.relative(root, target);
|
|
21986
|
-
requirePrivateFileDescriptorRoot(platform, errorMessage);
|
|
21987
|
-
const components = relative === "" ? [] : relative.split(path22.sep);
|
|
21988
|
-
const handles = [];
|
|
21989
|
-
let currentPath = root;
|
|
21990
|
-
try {
|
|
21991
|
-
let current = await openDirectoryNoFollow(root, errorMessage);
|
|
21992
|
-
handles.push(current.handle);
|
|
21993
|
-
for (const component of components) {
|
|
21994
|
-
const pinnedParent = await resolvePrivateDirectoryPath(currentPath, current.handle, current.opened, errorMessage);
|
|
21995
|
-
const childPath = path22.join(pinnedParent, component);
|
|
21996
|
-
let created = false;
|
|
21997
|
-
try {
|
|
21998
|
-
await mkdir7(childPath, { mode: 448 });
|
|
21999
|
-
created = true;
|
|
22000
|
-
} catch (error) {
|
|
22001
|
-
if (error.code !== "EEXIST") throw error;
|
|
22002
|
-
}
|
|
22003
|
-
await syncVerifiedParent(current.handle);
|
|
22004
|
-
const child = await openDirectoryNoFollow(childPath, errorMessage);
|
|
22005
|
-
handles.push(child.handle);
|
|
22006
|
-
if (created || hardenExistingChildren && (child.opened.mode & 511) !== 448) {
|
|
22007
|
-
await child.handle.chmod(448);
|
|
22008
|
-
}
|
|
22009
|
-
assertStableDirectory(current.before, current.opened, await lstat3(currentPath), errorMessage);
|
|
22010
|
-
currentPath = path22.join(currentPath, component);
|
|
22011
|
-
current = child;
|
|
22012
|
-
}
|
|
22013
|
-
assertStableDirectory(current.before, current.opened, await lstat3(target), errorMessage);
|
|
22014
|
-
} finally {
|
|
22015
|
-
await closeDirectoryHandles(handles);
|
|
22016
|
-
}
|
|
22017
|
-
}
|
|
22018
|
-
async function ensurePrivateDirectoryTreeNoFollow(directory, errorMessage, syncVerifiedParent = syncDirectoryHandle, platform = process.platform) {
|
|
22019
|
-
const target = path22.resolve(directory);
|
|
22020
|
-
const filesystemRoot = path22.parse(target).root;
|
|
22021
|
-
const rootMetadata = await stat4(filesystemRoot);
|
|
22022
|
-
await ensurePrivateDirectoryNoFollow(
|
|
22023
|
-
filesystemRoot,
|
|
22024
|
-
target,
|
|
22025
|
-
errorMessage,
|
|
22026
|
-
async (handle) => {
|
|
22027
|
-
try {
|
|
22028
|
-
await syncVerifiedParent(handle);
|
|
22029
|
-
} catch (error) {
|
|
22030
|
-
const code = error.code;
|
|
22031
|
-
const metadata = await handle.stat();
|
|
22032
|
-
if (metadata.ino === rootMetadata.ino && metadata.dev === rootMetadata.dev && NON_WRITABLE_ANCESTOR_SYNC_ERRORS.has(code ?? "")) {
|
|
22033
|
-
return;
|
|
22034
|
-
}
|
|
22035
|
-
throw error;
|
|
22036
|
-
}
|
|
22037
|
-
},
|
|
22038
|
-
false,
|
|
22039
|
-
platform
|
|
22040
|
-
);
|
|
22041
|
-
}
|
|
22042
|
-
async function withPrivateDirectoryNoFollow(trustedRoot, directory, errorMessage, task, platform = process.platform) {
|
|
22043
|
-
let directoryHandles = [];
|
|
22044
|
-
try {
|
|
22045
|
-
const stableDirectory = await openStableDirectoryFromRoot(trustedRoot, directory, errorMessage, platform);
|
|
22046
|
-
directoryHandles = stableDirectory.handles;
|
|
22047
|
-
const result = await task(stableDirectory.pinnedDirectory);
|
|
22048
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22049
|
-
return result;
|
|
22050
|
-
} finally {
|
|
22051
|
-
await closeDirectoryHandles(directoryHandles);
|
|
22052
|
-
}
|
|
22053
|
-
}
|
|
22054
|
-
async function readPrivateFileNoFollow(directory, filePath, errorMessage, trustedRoot = directory, platform = process.platform) {
|
|
22055
|
-
if (path22.dirname(filePath) !== path22.resolve(directory)) throw new Error(errorMessage);
|
|
22056
|
-
const targetName = path22.basename(filePath);
|
|
22057
|
-
let directoryHandles = [];
|
|
22058
|
-
let fileHandle;
|
|
22059
|
-
try {
|
|
22060
|
-
const stableDirectory = await openStableDirectoryFromRoot(trustedRoot, directory, errorMessage, platform);
|
|
22061
|
-
directoryHandles = stableDirectory.handles;
|
|
22062
|
-
const pinnedDirectory = stableDirectory.pinnedDirectory;
|
|
22063
|
-
const targetPath = path22.join(pinnedDirectory, targetName);
|
|
22064
|
-
const before = await lstat3(targetPath);
|
|
22065
|
-
if (before.isSymbolicLink() || !before.isFile()) throw new Error(errorMessage);
|
|
22066
|
-
try {
|
|
22067
|
-
fileHandle = await open(targetPath, openFlags(fsConstants.O_RDONLY, fsConstants.O_NOFOLLOW));
|
|
22068
|
-
} catch (error) {
|
|
22069
|
-
if (error.code === "ELOOP") throw new Error(errorMessage);
|
|
22070
|
-
throw error;
|
|
22071
|
-
}
|
|
22072
|
-
const fileMetadata = await fileHandle.stat();
|
|
22073
|
-
assertStableRegularFile(before, fileMetadata, await lstat3(targetPath), errorMessage);
|
|
22074
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22075
|
-
return await fileHandle.readFile("utf8");
|
|
22076
|
-
} finally {
|
|
22077
|
-
await fileHandle?.close().catch(() => void 0);
|
|
22078
|
-
await closeDirectoryHandles(directoryHandles);
|
|
22079
|
-
}
|
|
22080
|
-
}
|
|
22081
|
-
async function writePrivateFileAtomicallyNoFollow(directory, filePath, content, errorMessage, trustedRoot = directory, platform = process.platform) {
|
|
22082
|
-
if (path22.dirname(filePath) !== path22.resolve(directory)) throw new Error(errorMessage);
|
|
22083
|
-
const targetName = path22.basename(filePath);
|
|
22084
|
-
const tempName = `.${targetName}.${randomUUID2()}.tmp`;
|
|
22085
|
-
let tempPath;
|
|
22086
|
-
let directoryHandles = [];
|
|
22087
|
-
let fileHandle;
|
|
22088
|
-
try {
|
|
22089
|
-
const stableDirectory = await openStableDirectoryFromRoot(trustedRoot, directory, errorMessage, platform);
|
|
22090
|
-
directoryHandles = stableDirectory.handles;
|
|
22091
|
-
const pinnedDirectory = stableDirectory.pinnedDirectory;
|
|
22092
|
-
tempPath = path22.join(pinnedDirectory, tempName);
|
|
22093
|
-
const targetPath = path22.join(pinnedDirectory, targetName);
|
|
22094
|
-
try {
|
|
22095
|
-
fileHandle = await open(
|
|
22096
|
-
tempPath,
|
|
22097
|
-
openFlags(fsConstants.O_WRONLY, fsConstants.O_CREAT, fsConstants.O_EXCL, fsConstants.O_NOFOLLOW),
|
|
22098
|
-
384
|
|
22099
|
-
);
|
|
22100
|
-
} catch (error) {
|
|
22101
|
-
if (error.code === "ELOOP") throw new Error(errorMessage);
|
|
22102
|
-
throw error;
|
|
22103
|
-
}
|
|
22104
|
-
const fileMetadata = await fileHandle.stat();
|
|
22105
|
-
const tempMetadata = await lstat3(tempPath);
|
|
22106
|
-
assertStableRegularFile(tempMetadata, fileMetadata, await lstat3(tempPath), errorMessage);
|
|
22107
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22108
|
-
await fileHandle.chmod(384);
|
|
22109
|
-
await fileHandle.writeFile(content, "utf8");
|
|
22110
|
-
await fileHandle.sync();
|
|
22111
|
-
await fileHandle.close();
|
|
22112
|
-
fileHandle = void 0;
|
|
22113
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22114
|
-
await rename(tempPath, targetPath);
|
|
22115
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22116
|
-
if (stableDirectory.handle) await syncDirectoryHandle(stableDirectory.handle);
|
|
22117
|
-
} finally {
|
|
22118
|
-
await fileHandle?.close().catch(() => void 0);
|
|
22119
|
-
if (tempPath) await rm(tempPath, { force: true }).catch(() => void 0);
|
|
22120
|
-
await closeDirectoryHandles(directoryHandles);
|
|
22121
|
-
}
|
|
22122
|
-
}
|
|
22123
|
-
async function removePrivateFilesNoFollow(directory, fileNames, errorMessage, trustedRoot = directory, platform = process.platform) {
|
|
22124
|
-
if (fileNames.some(
|
|
22125
|
-
(fileName) => fileName.length === 0 || fileName === "." || fileName === ".." || path22.basename(fileName) !== fileName
|
|
22126
|
-
)) {
|
|
22127
|
-
throw new Error(errorMessage);
|
|
22128
|
-
}
|
|
22129
|
-
let directoryHandles = [];
|
|
22130
|
-
try {
|
|
22131
|
-
const stableDirectory = await openStableDirectoryFromRoot(trustedRoot, directory, errorMessage, platform);
|
|
22132
|
-
directoryHandles = stableDirectory.handles;
|
|
22133
|
-
const pinnedDirectory = stableDirectory.pinnedDirectory;
|
|
22134
|
-
for (const fileName of fileNames) {
|
|
22135
|
-
await rm(path22.join(pinnedDirectory, fileName), { force: true });
|
|
22136
|
-
}
|
|
22137
|
-
assertStableDirectory(stableDirectory.before, stableDirectory.opened, await lstat3(directory), errorMessage);
|
|
22138
|
-
if (stableDirectory.handle) await syncDirectoryHandle(stableDirectory.handle);
|
|
22139
|
-
} finally {
|
|
22140
|
-
await closeDirectoryHandles(directoryHandles);
|
|
22141
|
-
}
|
|
22142
|
-
}
|
|
22143
|
-
|
|
22144
|
-
// src/support-passport/grant-store.ts
|
|
22145
|
-
var GRANT_LOCK_STALE_MS = 3e4;
|
|
22146
|
-
var GRANT_LOCK_WAIT_MS = 5e3;
|
|
22147
|
-
var GRANT_LOCK_HEARTBEAT_MS = 1e4;
|
|
22148
|
-
var SAFE_GRANT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
22149
|
-
var UUID_INPUT = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
22150
|
-
var SAFE_OWNER_INDEX_HASH = /^[0-9a-f]{64}$/;
|
|
22151
|
-
var UNSUPPORTED_DIRECTORY_SYNC_ERRORS2 = /* @__PURE__ */ new Set(["EINVAL", "ENOSYS", "ENOTSUP", "EOPNOTSUPP"]);
|
|
22152
|
-
var MAX_OWNER_GRANT_HISTORY = 100;
|
|
22153
|
-
var MAX_OWNER_INDEX_RECOVERY_ATTEMPTS = 3;
|
|
22154
|
-
var OwnerIndexLockLostError = class extends Error {
|
|
22155
|
-
constructor(cause) {
|
|
22156
|
-
super("support passport owner index lock was lost", { cause });
|
|
22157
|
-
this.name = "OwnerIndexLockLostError";
|
|
22158
|
-
}
|
|
22159
|
-
};
|
|
22160
|
-
var MalformedGrantStateError = class extends Error {
|
|
22161
|
-
constructor(message = "support passport grant state is invalid", cause) {
|
|
22162
|
-
super(message, { cause });
|
|
22163
|
-
this.name = "MalformedGrantStateError";
|
|
22164
|
-
}
|
|
22165
|
-
};
|
|
22166
|
-
function sha256(domain, value) {
|
|
22167
|
-
return createHash10("sha256").update(domain).update("\0").update(value).digest("hex");
|
|
22168
|
-
}
|
|
22169
|
-
function hashesMatch(left, right) {
|
|
22170
|
-
const leftBytes = Buffer.from(left, "hex");
|
|
22171
|
-
const rightBytes = Buffer.from(right, "hex");
|
|
22172
|
-
return leftBytes.length === 32 && rightBytes.length === 32 && timingSafeEqual(leftBytes, rightBytes);
|
|
22173
|
-
}
|
|
22174
|
-
function sameGrantState(left, right) {
|
|
22175
|
-
return JSON.stringify(left) === JSON.stringify(right);
|
|
22176
|
-
}
|
|
22177
|
-
function newestGrantFirst(left, right) {
|
|
22178
|
-
return Date.parse(right.createdAt) - Date.parse(left.createdAt) || left.grantId.localeCompare(right.grantId);
|
|
22179
|
-
}
|
|
22180
|
-
function grantNotFound() {
|
|
22181
|
-
return new SupportPassportError("grant_not_found", "The share link was not found.", 404);
|
|
22182
|
-
}
|
|
22183
|
-
function warnCommitNotificationFailure(error) {
|
|
22184
|
-
log.warn(`support passport commit notification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
22185
|
-
}
|
|
22186
|
-
function notifySupportPassportCommitted(callback) {
|
|
22187
|
-
try {
|
|
22188
|
-
const completion = callback?.();
|
|
22189
|
-
if (completion) void Promise.resolve(completion).catch(warnCommitNotificationFailure);
|
|
22190
|
-
} catch (error) {
|
|
22191
|
-
warnCommitNotificationFailure(error);
|
|
22192
|
-
}
|
|
22193
|
-
}
|
|
22194
|
-
function normalizeGrantId(grantId) {
|
|
22195
|
-
if (typeof grantId !== "string" || !UUID_INPUT.test(grantId)) throw grantNotFound();
|
|
22196
|
-
return grantId.toLowerCase();
|
|
22197
|
-
}
|
|
22198
|
-
function normalizeNamespace(namespace) {
|
|
22199
|
-
const parsed = SupportPassportNamespaceSchema.safeParse(namespace);
|
|
22200
|
-
if (!parsed.success) {
|
|
22201
|
-
throw new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22202
|
-
}
|
|
22203
|
-
return parsed.data;
|
|
22204
|
-
}
|
|
22205
|
-
function normalizePrincipal(principal) {
|
|
22206
|
-
const normalized = typeof principal === "string" ? principal.trim() : "";
|
|
22207
|
-
if (normalized.length < 1 || normalized.length > 512) {
|
|
22208
|
-
throw new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22209
|
-
}
|
|
22210
|
-
return normalized;
|
|
22211
|
-
}
|
|
22212
|
-
async function syncDirectoryForDurability(directory, openDirectory = async (target) => await open2(target, "r")) {
|
|
22213
|
-
let handle;
|
|
22214
|
-
try {
|
|
22215
|
-
handle = await openDirectory(directory);
|
|
22216
|
-
await handle.sync();
|
|
22217
|
-
} catch (error) {
|
|
22218
|
-
const code = error.code;
|
|
22219
|
-
if (!UNSUPPORTED_DIRECTORY_SYNC_ERRORS2.has(code ?? "")) throw error;
|
|
22220
|
-
} finally {
|
|
22221
|
-
await handle?.close().catch(() => void 0);
|
|
22222
|
-
}
|
|
22223
|
-
}
|
|
22224
|
-
var SupportPassportGrantStore = class {
|
|
22225
|
-
memoryDir;
|
|
22226
|
-
grantsDir;
|
|
22227
|
-
ownerIndexesDir;
|
|
22228
|
-
memoryRootReady;
|
|
22229
|
-
safeDirectoriesReady;
|
|
22230
|
-
now;
|
|
22231
|
-
makeSecret;
|
|
22232
|
-
makeGrantId;
|
|
22233
|
-
runWithHeldFileLock;
|
|
22234
|
-
syncDirectory;
|
|
22235
|
-
constructor(options) {
|
|
22236
|
-
this.memoryDir = path23.resolve(expandTildePath(options.memoryDir));
|
|
22237
|
-
this.grantsDir = path23.join(this.memoryDir, "state", "support-passport", "grants");
|
|
22238
|
-
this.ownerIndexesDir = path23.join(this.grantsDir, "owners");
|
|
22239
|
-
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
22240
|
-
this.makeSecret = options.makeSecret ?? (() => randomBytes3(32));
|
|
22241
|
-
this.makeGrantId = options.makeGrantId ?? randomUUID3;
|
|
22242
|
-
this.runWithHeldFileLock = options.withHeldFileLock ?? withHeldFileLock;
|
|
22243
|
-
this.syncDirectory = options.syncDirectory ?? syncDirectoryForDurability;
|
|
22244
|
-
}
|
|
22245
|
-
async create(input, hooks = {}) {
|
|
22246
|
-
const mutationHooks = typeof hooks === "function" ? { beforeCommit: hooks } : hooks;
|
|
22247
|
-
const namespace = normalizeNamespace(input.namespace);
|
|
22248
|
-
const parsed = SupportPassportCreateGrantInputSchema.safeParse({
|
|
22249
|
-
principal: input.principal,
|
|
22250
|
-
cards: input.cards,
|
|
22251
|
-
expiresAt: input.expiresAt
|
|
22252
|
-
});
|
|
22253
|
-
if (!parsed.success) {
|
|
22254
|
-
throw new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22255
|
-
}
|
|
22256
|
-
const requestedAt = input.requestedAt ?? this.now();
|
|
22257
|
-
const durationMs = Date.parse(parsed.data.expiresAt) - requestedAt.getTime();
|
|
22258
|
-
if (!Number.isFinite(requestedAt.getTime()) || !Number.isFinite(durationMs) || durationMs < 3e5 || durationMs > 6048e5) {
|
|
22259
|
-
throw new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22260
|
-
}
|
|
22261
|
-
const principalHash = computeSupportPassportOwnerKey(parsed.data.principal);
|
|
22262
|
-
const ownerHash = this.ownerHash(namespace, principalHash);
|
|
22263
|
-
let committed;
|
|
22264
|
-
try {
|
|
22265
|
-
let finalized;
|
|
22266
|
-
try {
|
|
22267
|
-
finalized = await this.withOwnerIndexLock(ownerHash, async (lock) => {
|
|
22268
|
-
await this.requireAvailableOwnerGrantSlot(namespace, principalHash);
|
|
22269
|
-
committed = await this.withMutationLock(async (mutationLock) => {
|
|
22270
|
-
const secretBytes = this.makeSecret();
|
|
22271
|
-
if (!Buffer.isBuffer(secretBytes) || secretBytes.length !== 32) {
|
|
22272
|
-
throw new Error("SupportPassportGrantStore.makeSecret must return 32 bytes");
|
|
22273
|
-
}
|
|
22274
|
-
const rawGrantId = this.makeGrantId();
|
|
22275
|
-
if (!UUID_INPUT.test(rawGrantId)) {
|
|
22276
|
-
throw new Error("SupportPassportGrantStore.makeGrantId must return a UUID");
|
|
22277
|
-
}
|
|
22278
|
-
const grantId = rawGrantId.toLowerCase();
|
|
22279
|
-
const secret = secretBytes.toString("base64url");
|
|
22280
|
-
const createdAt = this.now();
|
|
22281
|
-
const createdAtMs = createdAt.getTime();
|
|
22282
|
-
const expiresAtMs = Date.parse(parsed.data.expiresAt);
|
|
22283
|
-
if (!Number.isFinite(createdAtMs) || requestedAt.getTime() > createdAtMs || expiresAtMs <= createdAtMs || expiresAtMs - createdAtMs > 6048e5) {
|
|
22284
|
-
throw new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22285
|
-
}
|
|
22286
|
-
const state = SupportPassportGrantStateSchema.parse({
|
|
22287
|
-
schemaVersion: 1,
|
|
22288
|
-
stateVersion: 1,
|
|
22289
|
-
grantId,
|
|
22290
|
-
namespace,
|
|
22291
|
-
principalHash,
|
|
22292
|
-
ownerLockKey: computeSupportPassportOwnerLockKey(namespace, parsed.data.principal),
|
|
22293
|
-
secretHash: sha256("support-passport-secret:v1", secret),
|
|
22294
|
-
cards: parsed.data.cards,
|
|
22295
|
-
createdAt: createdAt.toISOString(),
|
|
22296
|
-
expiresAt: parsed.data.expiresAt
|
|
22297
|
-
});
|
|
22298
|
-
await this.requireMutationLock(mutationLock);
|
|
22299
|
-
await mutationHooks.beforeCommit?.();
|
|
22300
|
-
await this.requireMutationLock(mutationLock);
|
|
22301
|
-
try {
|
|
22302
|
-
await this.writeState(state, true);
|
|
22303
|
-
} catch (error) {
|
|
22304
|
-
const persisted2 = await this.readState(state.grantId).catch(() => void 0);
|
|
22305
|
-
if (!persisted2 || !sameGrantState(persisted2, state)) throw error;
|
|
22306
|
-
try {
|
|
22307
|
-
await this.syncDirectory(this.grantsDir);
|
|
22308
|
-
} catch {
|
|
22309
|
-
await this.removeGrantStates([state.grantId]).catch(() => void 0);
|
|
22310
|
-
throw error;
|
|
22311
|
-
}
|
|
22312
|
-
}
|
|
22313
|
-
try {
|
|
22314
|
-
await this.writeOwnerMembership(state);
|
|
22315
|
-
} catch (error) {
|
|
22316
|
-
await this.removeStoredGrant(state).catch(() => void 0);
|
|
22317
|
-
throw error;
|
|
22318
|
-
}
|
|
22319
|
-
const persisted = { state, secret };
|
|
22320
|
-
committed = persisted;
|
|
22321
|
-
return persisted;
|
|
22322
|
-
});
|
|
22323
|
-
try {
|
|
22324
|
-
await this.addToOwnerIndex(committed.state, lock);
|
|
22325
|
-
} catch (error) {
|
|
22326
|
-
if (error instanceof OwnerIndexLockLostError) throw error;
|
|
22327
|
-
const indexed = await this.readOwnerIndexByHash(ownerHash).catch(() => void 0);
|
|
22328
|
-
if (!indexed?.includes(committed.state.grantId)) throw error;
|
|
22329
|
-
try {
|
|
22330
|
-
await this.syncDirectory(this.ownerIndexesDir);
|
|
22331
|
-
} catch {
|
|
22332
|
-
throw error;
|
|
22333
|
-
}
|
|
22334
|
-
await this.requireOwnerIndexLock(lock);
|
|
22335
|
-
}
|
|
22336
|
-
return committed;
|
|
22337
|
-
});
|
|
22338
|
-
} catch (error) {
|
|
22339
|
-
if (!(error instanceof OwnerIndexLockLostError) || !committed) throw error;
|
|
22340
|
-
finalized = await this.reconcileCreateAfterOwnerIndexLockLoss(committed);
|
|
22341
|
-
}
|
|
22342
|
-
notifySupportPassportCommitted(mutationHooks.onCommitted);
|
|
22343
|
-
return finalized;
|
|
22344
|
-
} catch (error) {
|
|
22345
|
-
if (committed) {
|
|
22346
|
-
await this.withGrantLock(committed.state.grantId, async (lock) => {
|
|
22347
|
-
await this.requireMutationLock(lock);
|
|
22348
|
-
await this.removeStoredGrant(committed.state);
|
|
22349
|
-
}).catch(() => void 0);
|
|
22350
|
-
}
|
|
22351
|
-
throw error;
|
|
22352
|
-
}
|
|
22353
|
-
}
|
|
22354
|
-
async authenticate(grantId, secret) {
|
|
22355
|
-
const normalizedGrantId = normalizeGrantId(grantId);
|
|
22356
|
-
if (typeof secret !== "string" || secret.length > 512) throw grantNotFound();
|
|
22357
|
-
let state;
|
|
22358
|
-
try {
|
|
22359
|
-
state = await this.readState(normalizedGrantId);
|
|
22360
|
-
} catch (error) {
|
|
22361
|
-
if (error.code === "ENOENT") throw grantNotFound();
|
|
22362
|
-
throw error;
|
|
22363
|
-
}
|
|
22364
|
-
const candidate = sha256("support-passport-secret:v1", secret);
|
|
22365
|
-
if (!hashesMatch(candidate, state.secretHash)) throw grantNotFound();
|
|
22366
|
-
if (state.revokedAt) {
|
|
22367
|
-
throw new SupportPassportError("grant_gone", "The share link is no longer active.", 410);
|
|
22368
|
-
}
|
|
22369
|
-
if (Date.parse(state.expiresAt) <= this.now().getTime()) {
|
|
22370
|
-
throw new SupportPassportError("grant_expired", "The share link has expired.", 410);
|
|
22371
|
-
}
|
|
22372
|
-
return state;
|
|
22373
|
-
}
|
|
22374
|
-
async withAuthenticatedGrant(grantId, secret, task, beforeReturn) {
|
|
22375
|
-
return await this.withGrantLock(grantId, async (lock) => {
|
|
22376
|
-
const state = await this.authenticate(grantId, secret);
|
|
22377
|
-
const result = await task(state);
|
|
22378
|
-
await this.requireMutationLock(lock);
|
|
22379
|
-
const finalState = await this.authenticate(grantId, secret);
|
|
22380
|
-
await this.requireMutationLock(lock);
|
|
22381
|
-
if (finalState.stateVersion !== state.stateVersion) {
|
|
22382
|
-
throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
22383
|
-
}
|
|
22384
|
-
this.requireActiveState(finalState);
|
|
22385
|
-
await beforeReturn?.(finalState);
|
|
22386
|
-
await this.requireMutationLock(lock);
|
|
22387
|
-
this.requireActiveState(finalState);
|
|
22388
|
-
return result;
|
|
22389
|
-
});
|
|
22390
|
-
}
|
|
22391
|
-
async listForOwner(namespace, principal) {
|
|
22392
|
-
const normalizedNamespace = normalizeNamespace(namespace);
|
|
22393
|
-
const principalHash = computeSupportPassportOwnerKey(normalizePrincipal(principal));
|
|
22394
|
-
const activeCutoff = this.now().getTime();
|
|
22395
|
-
const states = this.listedOwnerStates(
|
|
22396
|
-
await this.readOwnerMembershipStates(normalizedNamespace, principalHash),
|
|
22397
|
-
activeCutoff
|
|
22398
|
-
);
|
|
22399
|
-
return states.sort((a, b) => {
|
|
22400
|
-
const aActive = !a.revokedAt && Date.parse(a.expiresAt) > activeCutoff;
|
|
22401
|
-
const bActive = !b.revokedAt && Date.parse(b.expiresAt) > activeCutoff;
|
|
22402
|
-
if (aActive !== bActive) return aActive ? -1 : 1;
|
|
22403
|
-
return newestGrantFirst(a, b);
|
|
22404
|
-
});
|
|
22405
|
-
}
|
|
22406
|
-
async revoke(input, hooks = {}) {
|
|
22407
|
-
const mutationHooks = typeof hooks === "function" ? { beforeCommit: hooks } : hooks;
|
|
22408
|
-
const normalizedInput = { ...input, grantId: normalizeGrantId(input.grantId) };
|
|
22409
|
-
const namespace = normalizeNamespace(input.namespace);
|
|
22410
|
-
return await this.withGrantLock(normalizedInput.grantId, async (lock) => {
|
|
22411
|
-
let state;
|
|
22412
|
-
try {
|
|
22413
|
-
state = await this.readState(normalizedInput.grantId);
|
|
22414
|
-
} catch (error) {
|
|
22415
|
-
if (error.code === "ENOENT") throw grantNotFound();
|
|
22416
|
-
throw error;
|
|
22417
|
-
}
|
|
22418
|
-
const principalHash = computeSupportPassportOwnerKey(normalizePrincipal(input.principal));
|
|
22419
|
-
if (state.namespace !== namespace || !hashesMatch(state.principalHash, principalHash)) throw grantNotFound();
|
|
22420
|
-
if (state.revokedAt) {
|
|
22421
|
-
return state;
|
|
22422
|
-
}
|
|
22423
|
-
if (normalizedInput.expectedStateVersion !== void 0 && normalizedInput.expectedStateVersion !== state.stateVersion) {
|
|
22424
|
-
throw new SupportPassportError("state_conflict", "The share link changed after it was loaded.", 409);
|
|
22425
|
-
}
|
|
22426
|
-
const revoked = SupportPassportGrantStateSchema.parse({
|
|
22427
|
-
...state,
|
|
22428
|
-
stateVersion: state.stateVersion + 1,
|
|
22429
|
-
revokedAt: this.now().toISOString()
|
|
22430
|
-
});
|
|
22431
|
-
await this.requireMutationLock(lock);
|
|
22432
|
-
await mutationHooks.beforeCommit?.();
|
|
22433
|
-
await this.requireMutationLock(lock);
|
|
22434
|
-
try {
|
|
22435
|
-
await this.writeState(revoked);
|
|
22436
|
-
} catch (error) {
|
|
22437
|
-
const persisted = await this.readState(revoked.grantId).catch(() => void 0);
|
|
22438
|
-
if (!persisted || !sameGrantState(persisted, revoked)) throw error;
|
|
22439
|
-
await this.syncDirectory(this.grantsDir);
|
|
22440
|
-
}
|
|
22441
|
-
notifySupportPassportCommitted(mutationHooks.onCommitted);
|
|
22442
|
-
return revoked;
|
|
22443
|
-
});
|
|
22444
|
-
}
|
|
22445
|
-
filePath(grantId) {
|
|
22446
|
-
const normalizedGrantId = normalizeGrantId(grantId);
|
|
22447
|
-
return path23.join(this.grantsDir, `${normalizedGrantId}.json`);
|
|
22448
|
-
}
|
|
22449
|
-
ownerIndexPath(ownerHash) {
|
|
22450
|
-
if (!SAFE_OWNER_INDEX_HASH.test(ownerHash)) throw new Error("support passport owner index hash is invalid");
|
|
22451
|
-
return path23.join(this.ownerIndexesDir, `${ownerHash}.json`);
|
|
22452
|
-
}
|
|
22453
|
-
ownerHash(namespace, principalHash) {
|
|
22454
|
-
return sha256("support-passport-owner-index:v1", `${namespace}\0${principalHash}`);
|
|
22455
|
-
}
|
|
22456
|
-
async addToOwnerIndex(state, lock) {
|
|
22457
|
-
const ownerHash = this.ownerHash(state.namespace, state.principalHash);
|
|
22458
|
-
const ownerStates = (await this.readOwnerMembershipStates(state.namespace, state.principalHash)).filter((item) => item.grantId !== state.grantId).sort(newestGrantFirst);
|
|
22459
|
-
const current = ownerStates.map((item) => item.grantId);
|
|
22460
|
-
let retained = current;
|
|
22461
|
-
const indexedStates = [...ownerStates];
|
|
22462
|
-
if (current.length >= MAX_OWNER_GRANT_HISTORY) {
|
|
22463
|
-
const expiryCutoff = this.now().getTime();
|
|
22464
|
-
const active = indexedStates.filter((item) => !item.revokedAt && Date.parse(item.expiresAt) > expiryCutoff);
|
|
22465
|
-
if (active.length >= MAX_OWNER_GRANT_HISTORY) {
|
|
22466
|
-
throw new SupportPassportError(
|
|
22467
|
-
"invalid_input",
|
|
22468
|
-
"A support passport can contain at most 100 active share links.",
|
|
22469
|
-
400
|
|
22470
|
-
);
|
|
22471
|
-
}
|
|
22472
|
-
const inactive = indexedStates.filter((item) => item.revokedAt || Date.parse(item.expiresAt) <= expiryCutoff).sort(newestGrantFirst);
|
|
22473
|
-
retained = [
|
|
22474
|
-
...active.map((item) => item.grantId),
|
|
22475
|
-
...inactive.slice(0, MAX_OWNER_GRANT_HISTORY - active.length - 1).map((item) => item.grantId)
|
|
22476
|
-
];
|
|
22477
|
-
}
|
|
22478
|
-
const grantIds = [...retained, state.grantId];
|
|
22479
|
-
const retainedIds = new Set(grantIds);
|
|
22480
|
-
const indexedStateById = new Map(indexedStates.map((indexedState) => [indexedState.grantId, indexedState]));
|
|
22481
|
-
const evictedGrantIds = current.filter((grantId) => !retainedIds.has(grantId));
|
|
22482
|
-
await this.writeOwnerIndexWhileLocked(ownerHash, grantIds, lock);
|
|
22483
|
-
try {
|
|
22484
|
-
for (const grantId of evictedGrantIds) {
|
|
22485
|
-
await this.withGrantLock(grantId, async (grantLock) => {
|
|
22486
|
-
await this.requireMutationLock(grantLock);
|
|
22487
|
-
const evictedState = indexedStateById.get(grantId);
|
|
22488
|
-
if (evictedState) await this.removeStoredGrant(evictedState);
|
|
22489
|
-
else await this.removeGrantStates([grantId]);
|
|
22490
|
-
});
|
|
22491
|
-
}
|
|
22492
|
-
} catch (error) {
|
|
22493
|
-
log.warn(
|
|
22494
|
-
`support passport could not remove inactive grant state: ${error instanceof Error ? error.message : String(error)}`
|
|
22495
|
-
);
|
|
22496
|
-
}
|
|
22497
|
-
}
|
|
22498
|
-
async removeGrantStates(grantIds) {
|
|
22499
|
-
if (grantIds.length === 0) return;
|
|
22500
|
-
for (const grantId of grantIds) {
|
|
22501
|
-
if (!SAFE_GRANT_ID.test(grantId)) throw grantNotFound();
|
|
22502
|
-
}
|
|
22503
|
-
await removePrivateFilesNoFollow(
|
|
22504
|
-
this.grantsDir,
|
|
22505
|
-
grantIds.map((grantId) => `${grantId}.json`),
|
|
22506
|
-
"support passport grant files must be regular files in a stable directory",
|
|
22507
|
-
path23.parse(this.memoryDir).root
|
|
22508
|
-
);
|
|
22509
|
-
}
|
|
22510
|
-
ownerMembershipDirectory(ownerHash) {
|
|
22511
|
-
if (!SAFE_OWNER_INDEX_HASH.test(ownerHash)) throw new Error("support passport owner index hash is invalid");
|
|
22512
|
-
return path23.join(this.ownerIndexesDir, ownerHash);
|
|
22513
|
-
}
|
|
22514
|
-
async ensureOwnerMembershipDirectory(ownerHash) {
|
|
22515
|
-
const directory = this.ownerMembershipDirectory(ownerHash);
|
|
22516
|
-
await ensurePrivateDirectoryTreeNoFollow(
|
|
22517
|
-
directory,
|
|
22518
|
-
"support passport owner membership must remain inside the memory directory"
|
|
22519
|
-
);
|
|
22520
|
-
return directory;
|
|
22521
|
-
}
|
|
22522
|
-
async writeOwnerMembership(state) {
|
|
22523
|
-
const ownerHash = this.ownerHash(state.namespace, state.principalHash);
|
|
22524
|
-
const directory = await this.ensureOwnerMembershipDirectory(ownerHash);
|
|
22525
|
-
await writePrivateFileAtomicallyNoFollow(
|
|
22526
|
-
directory,
|
|
22527
|
-
path23.join(directory, `${state.grantId}.json`),
|
|
22528
|
-
`${JSON.stringify({ schemaVersion: 1, grantId: state.grantId })}
|
|
22529
|
-
`,
|
|
22530
|
-
"support passport owner membership must be regular files in a stable directory",
|
|
22531
|
-
path23.parse(this.memoryDir).root
|
|
22532
|
-
);
|
|
22533
|
-
}
|
|
22534
|
-
async removeOwnerMembership(state) {
|
|
22535
|
-
const ownerHash = this.ownerHash(state.namespace, state.principalHash);
|
|
22536
|
-
const directory = await this.ensureOwnerMembershipDirectory(ownerHash);
|
|
22537
|
-
await removePrivateFilesNoFollow(
|
|
22538
|
-
directory,
|
|
22539
|
-
[`${state.grantId}.json`],
|
|
22540
|
-
"support passport owner membership must be regular files in a stable directory",
|
|
22541
|
-
path23.parse(this.memoryDir).root
|
|
22542
|
-
);
|
|
22543
|
-
}
|
|
22544
|
-
async removeStoredGrant(state) {
|
|
22545
|
-
await this.removeGrantStates([state.grantId]);
|
|
22546
|
-
await this.removeOwnerMembership(state);
|
|
22547
|
-
}
|
|
22548
|
-
async writeOwnerIndexWhileLocked(ownerHash, grantIds, lock) {
|
|
22549
|
-
await this.requireOwnerIndexLock(lock);
|
|
22550
|
-
await this.writeOwnerIndex(ownerHash, grantIds);
|
|
22551
|
-
await this.requireOwnerIndexLock(lock);
|
|
22552
|
-
}
|
|
22553
|
-
async reconcileCreateAfterOwnerIndexLockLoss(committed) {
|
|
22554
|
-
const ownerHash = this.ownerHash(committed.state.namespace, committed.state.principalHash);
|
|
22555
|
-
for (let attempt = 1; attempt <= MAX_OWNER_INDEX_RECOVERY_ATTEMPTS; attempt += 1) {
|
|
22556
|
-
try {
|
|
22557
|
-
return await this.withOwnerIndexLock(
|
|
22558
|
-
ownerHash,
|
|
22559
|
-
async (lock) => await this.reconcileCommittedGrant(committed, ownerHash, lock)
|
|
22560
|
-
);
|
|
22561
|
-
} catch (error) {
|
|
22562
|
-
if (!(error instanceof OwnerIndexLockLostError)) throw error;
|
|
22563
|
-
}
|
|
22564
|
-
}
|
|
22565
|
-
throw new SupportPassportError("storage_conflict", "The share link store changed during the request.", 409);
|
|
22566
|
-
}
|
|
22567
|
-
async reconcileCommittedGrant(committed, ownerHash, lock) {
|
|
22568
|
-
const persisted = await this.readState(committed.state.grantId).catch(() => void 0);
|
|
22569
|
-
if (!persisted || !sameGrantState(persisted, committed.state)) {
|
|
22570
|
-
throw new SupportPassportError("storage_conflict", "The share link store changed during the request.", 409);
|
|
22571
|
-
}
|
|
22572
|
-
const ownerStates = await this.readOwnerMembershipStates(committed.state.namespace, committed.state.principalHash);
|
|
22573
|
-
const committedIndex = ownerStates.findIndex((state) => state.grantId === committed.state.grantId);
|
|
22574
|
-
if (committedIndex === -1) ownerStates.push(committed.state);
|
|
22575
|
-
else ownerStates[committedIndex] = committed.state;
|
|
22576
|
-
const activeCutoff = this.now().getTime();
|
|
22577
|
-
const active = ownerStates.filter((state) => !state.revokedAt && Date.parse(state.expiresAt) > activeCutoff);
|
|
22578
|
-
if (active.length > MAX_OWNER_GRANT_HISTORY) {
|
|
22579
|
-
await this.withGrantLock(committed.state.grantId, async (grantLock) => {
|
|
22580
|
-
await this.requireMutationLock(grantLock);
|
|
22581
|
-
await this.removeStoredGrant(committed.state);
|
|
22582
|
-
});
|
|
22583
|
-
const committedIndex2 = ownerStates.findIndex((state) => state.grantId === committed.state.grantId);
|
|
22584
|
-
if (committedIndex2 !== -1) ownerStates.splice(committedIndex2, 1);
|
|
22585
|
-
}
|
|
22586
|
-
const retained = this.retainedOwnerStates(ownerStates, activeCutoff);
|
|
22587
|
-
await this.writeOwnerIndexWhileLocked(
|
|
22588
|
-
ownerHash,
|
|
22589
|
-
retained.map((state) => state.grantId),
|
|
22590
|
-
lock
|
|
22591
|
-
);
|
|
22592
|
-
const retainedIds = new Set(retained.map((state) => state.grantId));
|
|
22593
|
-
for (const state of ownerStates) {
|
|
22594
|
-
if (retainedIds.has(state.grantId)) continue;
|
|
22595
|
-
try {
|
|
22596
|
-
await this.withGrantLock(state.grantId, async (grantLock) => {
|
|
22597
|
-
await this.requireMutationLock(grantLock);
|
|
22598
|
-
await this.removeStoredGrant(state);
|
|
22599
|
-
});
|
|
22600
|
-
} catch (error) {
|
|
22601
|
-
log.warn(
|
|
22602
|
-
`support passport could not remove inactive grant state: ${error instanceof Error ? error.message : String(error)}`
|
|
22603
|
-
);
|
|
22604
|
-
}
|
|
22605
|
-
}
|
|
22606
|
-
if (active.length > MAX_OWNER_GRANT_HISTORY) {
|
|
22607
|
-
throw new SupportPassportError("storage_conflict", "The share link store changed during the request.", 409);
|
|
22608
|
-
}
|
|
22609
|
-
return committed;
|
|
22610
|
-
}
|
|
22611
|
-
retainedOwnerStates(states, activeCutoff) {
|
|
22612
|
-
const active = states.filter((state) => !state.revokedAt && Date.parse(state.expiresAt) > activeCutoff);
|
|
22613
|
-
if (active.length > MAX_OWNER_GRANT_HISTORY) {
|
|
22614
|
-
throw new SupportPassportError("storage_conflict", "The share link store contains too many active links.", 409);
|
|
22615
|
-
}
|
|
22616
|
-
const inactive = states.filter((state) => state.revokedAt || Date.parse(state.expiresAt) <= activeCutoff).sort(newestGrantFirst);
|
|
22617
|
-
return [...active, ...inactive.slice(0, MAX_OWNER_GRANT_HISTORY - active.length)];
|
|
22618
|
-
}
|
|
22619
|
-
listedOwnerStates(states, activeCutoff) {
|
|
22620
|
-
const active = states.filter((state) => !state.revokedAt && Date.parse(state.expiresAt) > activeCutoff);
|
|
22621
|
-
const inactive = states.filter((state) => state.revokedAt || Date.parse(state.expiresAt) <= activeCutoff).sort(newestGrantFirst);
|
|
22622
|
-
return [...active, ...inactive.slice(0, Math.max(0, MAX_OWNER_GRANT_HISTORY - active.length))];
|
|
22623
|
-
}
|
|
22624
|
-
async requireAvailableOwnerGrantSlot(namespace, principalHash) {
|
|
22625
|
-
const activeCutoff = this.now().getTime();
|
|
22626
|
-
const active = (await this.readOwnerMembershipStates(namespace, principalHash)).filter(
|
|
22627
|
-
(state) => !state.revokedAt && Date.parse(state.expiresAt) > activeCutoff
|
|
22628
|
-
);
|
|
22629
|
-
if (active.length >= MAX_OWNER_GRANT_HISTORY) {
|
|
22630
|
-
throw new SupportPassportError(
|
|
22631
|
-
"invalid_input",
|
|
22632
|
-
"A support passport can contain at most 100 active share links.",
|
|
22633
|
-
400
|
|
22634
|
-
);
|
|
22635
|
-
}
|
|
22636
|
-
}
|
|
22637
|
-
async readOwnerMembershipStates(namespace, principalHash) {
|
|
22638
|
-
await this.ensureSafeDirectories();
|
|
22639
|
-
const ownerHash = this.ownerHash(namespace, principalHash);
|
|
22640
|
-
const directory = await this.ensureOwnerMembershipDirectory(ownerHash);
|
|
22641
|
-
const grantIds = await withPrivateDirectoryNoFollow(
|
|
22642
|
-
path23.parse(this.memoryDir).root,
|
|
22643
|
-
directory,
|
|
22644
|
-
"support passport owner membership must be regular files in a stable directory",
|
|
22645
|
-
async (pinnedDirectory) => {
|
|
22646
|
-
const entries = await readdir4(pinnedDirectory, { withFileTypes: true });
|
|
22647
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -5)).filter((grantId) => SAFE_GRANT_ID.test(grantId));
|
|
22648
|
-
}
|
|
22649
|
-
);
|
|
22650
|
-
const ownerStates = [];
|
|
22651
|
-
for (const grantId of grantIds) {
|
|
22652
|
-
try {
|
|
22653
|
-
const state = await this.readState(grantId);
|
|
22654
|
-
if (state.namespace === namespace && hashesMatch(state.principalHash, principalHash)) {
|
|
22655
|
-
ownerStates.push(state);
|
|
22656
|
-
}
|
|
22657
|
-
} catch (error) {
|
|
22658
|
-
if (error.code === "ENOENT" || error instanceof MalformedGrantStateError) continue;
|
|
22659
|
-
throw error;
|
|
22660
|
-
}
|
|
22661
|
-
}
|
|
22662
|
-
return ownerStates;
|
|
22663
|
-
}
|
|
22664
|
-
async readOwnerIndexByHash(ownerHash) {
|
|
22665
|
-
await this.ensureSafeDirectories();
|
|
22666
|
-
const filePath = this.ownerIndexPath(ownerHash);
|
|
22667
|
-
let content;
|
|
22668
|
-
try {
|
|
22669
|
-
content = await readPrivateFileNoFollow(
|
|
22670
|
-
this.ownerIndexesDir,
|
|
22671
|
-
filePath,
|
|
22672
|
-
"support passport owner indexes must be regular files in a stable directory",
|
|
22673
|
-
path23.parse(this.memoryDir).root
|
|
22674
|
-
);
|
|
22675
|
-
} catch (error) {
|
|
22676
|
-
if (error.code === "ENOENT") return [];
|
|
22677
|
-
throw error;
|
|
22678
|
-
}
|
|
22679
|
-
const parsed = JSON.parse(content);
|
|
22680
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
22681
|
-
throw new Error("support passport owner index is invalid");
|
|
22682
|
-
}
|
|
22683
|
-
const record = parsed;
|
|
22684
|
-
const grantIds = record.grantIds;
|
|
22685
|
-
if (record.schemaVersion !== 1 || record.ownerHash !== ownerHash || !Array.isArray(grantIds)) {
|
|
22686
|
-
throw new Error("support passport owner index is invalid");
|
|
22687
|
-
}
|
|
22688
|
-
if (grantIds.some((grantId) => typeof grantId !== "string" || !SAFE_GRANT_ID.test(grantId))) {
|
|
22689
|
-
throw new Error("support passport owner index is invalid");
|
|
22690
|
-
}
|
|
22691
|
-
const uniqueGrantIds = new Set(grantIds);
|
|
22692
|
-
if (uniqueGrantIds.size !== grantIds.length || uniqueGrantIds.size > MAX_OWNER_GRANT_HISTORY) {
|
|
22693
|
-
throw new Error("support passport owner index is invalid");
|
|
22694
|
-
}
|
|
22695
|
-
return [...uniqueGrantIds];
|
|
22696
|
-
}
|
|
22697
|
-
async writeOwnerIndex(ownerHash, grantIds) {
|
|
22698
|
-
const filePath = this.ownerIndexPath(ownerHash);
|
|
22699
|
-
try {
|
|
22700
|
-
const metadata = await lstat4(filePath);
|
|
22701
|
-
if (metadata.isSymbolicLink() || !metadata.isFile()) {
|
|
22702
|
-
throw new Error("support passport owner indexes must be regular files");
|
|
22703
|
-
}
|
|
22704
|
-
} catch (error) {
|
|
22705
|
-
if (error.code !== "ENOENT") throw error;
|
|
22706
|
-
}
|
|
22707
|
-
await writePrivateFileAtomicallyNoFollow(
|
|
22708
|
-
this.ownerIndexesDir,
|
|
22709
|
-
filePath,
|
|
22710
|
-
`${JSON.stringify({ schemaVersion: 1, ownerHash, grantIds }, null, 2)}
|
|
22711
|
-
`,
|
|
22712
|
-
"support passport owner indexes must be regular files in a stable directory",
|
|
22713
|
-
path23.parse(this.memoryDir).root
|
|
22714
|
-
);
|
|
22715
|
-
}
|
|
22716
|
-
async readState(grantId) {
|
|
22717
|
-
await this.ensureSafeDirectories();
|
|
22718
|
-
const filePath = this.filePath(grantId);
|
|
22719
|
-
const content = await readPrivateFileNoFollow(
|
|
22720
|
-
this.grantsDir,
|
|
22721
|
-
filePath,
|
|
22722
|
-
"support passport grant files must be regular files in a stable directory",
|
|
22723
|
-
path23.parse(this.memoryDir).root
|
|
22724
|
-
);
|
|
22725
|
-
try {
|
|
22726
|
-
const state = SupportPassportGrantStateSchema.parse(JSON.parse(content));
|
|
22727
|
-
if (state.grantId !== grantId) {
|
|
22728
|
-
throw new MalformedGrantStateError("support passport grant ID must match its file name");
|
|
22729
|
-
}
|
|
22730
|
-
return state;
|
|
22731
|
-
} catch (error) {
|
|
22732
|
-
if (error instanceof MalformedGrantStateError) throw error;
|
|
22733
|
-
if (error instanceof SyntaxError || error.name === "ZodError") {
|
|
22734
|
-
throw new MalformedGrantStateError(void 0, error);
|
|
22735
|
-
}
|
|
22736
|
-
throw error;
|
|
22737
|
-
}
|
|
22738
|
-
}
|
|
22739
|
-
async writeState(state, requireAbsent = false) {
|
|
22740
|
-
const filePath = this.filePath(state.grantId);
|
|
22741
|
-
try {
|
|
22742
|
-
const metadata = await lstat4(filePath);
|
|
22743
|
-
if (metadata.isSymbolicLink() || !metadata.isFile())
|
|
22744
|
-
throw new Error("support passport grant files must be regular files");
|
|
22745
|
-
if (requireAbsent) {
|
|
22746
|
-
throw new SupportPassportError("storage_conflict", "A new share link could not be allocated.", 409);
|
|
22747
|
-
}
|
|
22748
|
-
} catch (error) {
|
|
22749
|
-
if (error.code !== "ENOENT") throw error;
|
|
22750
|
-
}
|
|
22751
|
-
await writePrivateFileAtomicallyNoFollow(
|
|
22752
|
-
this.grantsDir,
|
|
22753
|
-
filePath,
|
|
22754
|
-
`${JSON.stringify(state, null, 2)}
|
|
22755
|
-
`,
|
|
22756
|
-
"support passport grant files must be regular files in a stable directory",
|
|
22757
|
-
path23.parse(this.memoryDir).root
|
|
22758
|
-
);
|
|
22759
|
-
}
|
|
22760
|
-
async ensureSafeDirectories() {
|
|
22761
|
-
if (!this.safeDirectoriesReady) {
|
|
22762
|
-
this.safeDirectoriesReady = (async () => {
|
|
22763
|
-
await this.ensureMemoryRoot();
|
|
22764
|
-
await ensurePrivateDirectoryNoFollow(
|
|
22765
|
-
this.memoryDir,
|
|
22766
|
-
this.ownerIndexesDir,
|
|
22767
|
-
"support passport grant directories must remain inside the memory directory",
|
|
22768
|
-
void 0,
|
|
22769
|
-
true
|
|
22770
|
-
);
|
|
22771
|
-
})();
|
|
22772
|
-
}
|
|
22773
|
-
const currentAttempt = this.safeDirectoriesReady;
|
|
22774
|
-
try {
|
|
22775
|
-
await currentAttempt;
|
|
22776
|
-
} catch (error) {
|
|
22777
|
-
if (this.safeDirectoriesReady === currentAttempt) this.safeDirectoriesReady = void 0;
|
|
22778
|
-
throw error;
|
|
22779
|
-
}
|
|
22780
|
-
}
|
|
22781
|
-
async ensureMemoryRoot() {
|
|
22782
|
-
const configuredMemoryDir = this.memoryDir;
|
|
22783
|
-
if (!this.memoryRootReady) {
|
|
22784
|
-
this.memoryRootReady = (async () => {
|
|
22785
|
-
await ensurePrivateDirectoryTreeNoFollow(
|
|
22786
|
-
configuredMemoryDir,
|
|
22787
|
-
"support passport memory directory must be a stable directory",
|
|
22788
|
-
void 0
|
|
22789
|
-
);
|
|
22790
|
-
this.memoryDir = configuredMemoryDir;
|
|
22791
|
-
this.grantsDir = path23.join(configuredMemoryDir, "state", "support-passport", "grants");
|
|
22792
|
-
this.ownerIndexesDir = path23.join(this.grantsDir, "owners");
|
|
22793
|
-
})();
|
|
22794
|
-
}
|
|
22795
|
-
const currentAttempt = this.memoryRootReady;
|
|
22796
|
-
try {
|
|
22797
|
-
await currentAttempt;
|
|
22798
|
-
} catch (error) {
|
|
22799
|
-
if (this.memoryRootReady === currentAttempt) this.memoryRootReady = void 0;
|
|
22800
|
-
throw error;
|
|
22801
|
-
}
|
|
22802
|
-
}
|
|
22803
|
-
async withMutationLock(task) {
|
|
22804
|
-
await this.ensureSafeDirectories();
|
|
22805
|
-
return await withPrivateDirectoryNoFollow(
|
|
22806
|
-
path23.parse(this.memoryDir).root,
|
|
22807
|
-
this.grantsDir,
|
|
22808
|
-
"support passport grant lock directory must remain inside the memory directory",
|
|
22809
|
-
async (pinnedDirectory) => await this.withExclusiveLock(
|
|
22810
|
-
`support-passport-grants:${this.grantsDir}`,
|
|
22811
|
-
path23.join(pinnedDirectory, ".grants.lock"),
|
|
22812
|
-
task
|
|
22813
|
-
)
|
|
22814
|
-
);
|
|
22815
|
-
}
|
|
22816
|
-
async withGrantLock(grantId, task) {
|
|
22817
|
-
const normalizedGrantId = normalizeGrantId(grantId);
|
|
22818
|
-
await this.ensureSafeDirectories();
|
|
22819
|
-
return await withPrivateDirectoryNoFollow(
|
|
22820
|
-
path23.parse(this.memoryDir).root,
|
|
22821
|
-
this.grantsDir,
|
|
22822
|
-
"support passport grant lock directory must remain inside the memory directory",
|
|
22823
|
-
async (pinnedDirectory) => await this.withExclusiveLock(
|
|
22824
|
-
`support-passport-grant:${this.grantsDir}:${normalizedGrantId}`,
|
|
22825
|
-
path23.join(pinnedDirectory, `.${normalizedGrantId}.lock`),
|
|
22826
|
-
task
|
|
22827
|
-
)
|
|
22828
|
-
);
|
|
22829
|
-
}
|
|
22830
|
-
async withOwnerIndexLock(ownerHash, task) {
|
|
22831
|
-
await this.ensureSafeDirectories();
|
|
22832
|
-
return await withPrivateDirectoryNoFollow(
|
|
22833
|
-
path23.parse(this.memoryDir).root,
|
|
22834
|
-
this.ownerIndexesDir,
|
|
22835
|
-
"support passport owner lock directory must remain inside the memory directory",
|
|
22836
|
-
async (pinnedDirectory) => await this.withExclusiveLock(
|
|
22837
|
-
`support-passport-owner:${this.ownerIndexesDir}:${ownerHash}`,
|
|
22838
|
-
path23.join(pinnedDirectory, `.${ownerHash}.lock`),
|
|
22839
|
-
task
|
|
22840
|
-
)
|
|
22841
|
-
);
|
|
22842
|
-
}
|
|
22843
|
-
async withExclusiveLock(serializationKey, lockPath, task) {
|
|
22844
|
-
return await serializeMutations(
|
|
22845
|
-
serializationKey,
|
|
22846
|
-
() => this.runWithHeldFileLock(
|
|
22847
|
-
lockPath,
|
|
22848
|
-
{
|
|
22849
|
-
staleMs: GRANT_LOCK_STALE_MS,
|
|
22850
|
-
maxWaitMs: GRANT_LOCK_WAIT_MS,
|
|
22851
|
-
heartbeatMs: GRANT_LOCK_HEARTBEAT_MS
|
|
22852
|
-
},
|
|
22853
|
-
async (acquired, lock) => {
|
|
22854
|
-
if (!acquired) {
|
|
22855
|
-
throw new SupportPassportError("storage_conflict", "The share link store is busy. Try again.", 409);
|
|
22856
|
-
}
|
|
22857
|
-
return await task(lock);
|
|
22858
|
-
}
|
|
22859
|
-
)
|
|
22860
|
-
);
|
|
22861
|
-
}
|
|
22862
|
-
async requireMutationLock(lock) {
|
|
22863
|
-
if (await lock.refresh()) return;
|
|
22864
|
-
throw new SupportPassportError("storage_conflict", "The share link store changed during the request.", 409);
|
|
22865
|
-
}
|
|
22866
|
-
async requireOwnerIndexLock(lock) {
|
|
22867
|
-
try {
|
|
22868
|
-
await this.requireMutationLock(lock);
|
|
22869
|
-
} catch (error) {
|
|
22870
|
-
throw new OwnerIndexLockLostError(error);
|
|
22871
|
-
}
|
|
22872
|
-
}
|
|
22873
|
-
requireActiveState(state) {
|
|
22874
|
-
if (state.revokedAt) {
|
|
22875
|
-
throw new SupportPassportError("grant_gone", "The share link is no longer active.", 410);
|
|
22876
|
-
}
|
|
22877
|
-
if (Date.parse(state.expiresAt) <= this.now().getTime()) {
|
|
22878
|
-
throw new SupportPassportError("grant_expired", "The share link has expired.", 410);
|
|
22879
|
-
}
|
|
22880
|
-
}
|
|
22881
|
-
};
|
|
22882
|
-
|
|
22883
|
-
// src/support-passport/grant-service.ts
|
|
22884
|
-
function invalidInput2() {
|
|
22885
|
-
return new SupportPassportError("invalid_input", "The share link request is invalid.", 400);
|
|
22886
|
-
}
|
|
22887
|
-
var SupportPassportGrantService = class {
|
|
22888
|
-
grantStore;
|
|
22889
|
-
resolveOwner;
|
|
22890
|
-
resolveNamespace;
|
|
22891
|
-
now;
|
|
22892
|
-
constructor(dependencies) {
|
|
22893
|
-
this.grantStore = dependencies.grantStore;
|
|
22894
|
-
this.resolveOwner = dependencies.resolveOwner;
|
|
22895
|
-
this.resolveNamespace = dependencies.resolveNamespace;
|
|
22896
|
-
this.now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
22897
|
-
}
|
|
22898
|
-
async createGrant(input, options = {}) {
|
|
22899
|
-
const requestedAt = this.now();
|
|
22900
|
-
const parsed = SupportPassportCreateGrantInputSchema.safeParse(input);
|
|
22901
|
-
if (!parsed.success) throw invalidInput2();
|
|
22902
|
-
const owner = await this.resolveOwnerScope(parsed.data.principal);
|
|
22903
|
-
return await withSupportPassportOwnerLock(
|
|
22904
|
-
owner.storage,
|
|
22905
|
-
{ namespace: owner.namespace, principal: owner.principal },
|
|
22906
|
-
async (ownerLock) => {
|
|
22907
|
-
options.signal?.throwIfAborted();
|
|
22908
|
-
const ownerHash = computeSupportPassportOwnerKey(owner.principal);
|
|
22909
|
-
const cardsById = new Map(
|
|
22910
|
-
this.projectOwnedCards(
|
|
22911
|
-
await owner.storage.readAllMemories(),
|
|
22912
|
-
owner.namespace,
|
|
22913
|
-
ownerHash
|
|
22914
|
-
).map((card) => [card.card.cardId, card])
|
|
22915
|
-
);
|
|
22916
|
-
for (const cardRef of parsed.data.cards) {
|
|
22917
|
-
const stored = cardsById.get(cardRef.cardId);
|
|
22918
|
-
if (!stored || stored.namespace !== owner.namespace || stored.owner !== ownerHash || stored.card.status !== "active") {
|
|
22919
|
-
throw new SupportPassportError("invalid_card_status", "Only approved support cards can be shared.", 409);
|
|
22920
|
-
}
|
|
22921
|
-
if (stored.card.revision !== cardRef.revision) {
|
|
22922
|
-
throw new SupportPassportError("revision_conflict", "A support card changed after it was selected.", 409);
|
|
22923
|
-
}
|
|
22924
|
-
if (!this.publicCard(stored.card).success) {
|
|
22925
|
-
throw new SupportPassportError("card_data_invalid", "The support card data is invalid.", 500);
|
|
22926
|
-
}
|
|
22927
|
-
}
|
|
22928
|
-
const created = await this.grantStore.create(
|
|
22929
|
-
{
|
|
22930
|
-
namespace: owner.namespace,
|
|
22931
|
-
principal: owner.principal,
|
|
22932
|
-
cards: parsed.data.cards,
|
|
22933
|
-
expiresAt: parsed.data.expiresAt,
|
|
22934
|
-
requestedAt
|
|
22935
|
-
},
|
|
22936
|
-
{
|
|
22937
|
-
beforeCommit: async () => {
|
|
22938
|
-
options.signal?.throwIfAborted();
|
|
22939
|
-
await requireSupportPassportOwnerLock(ownerLock);
|
|
22940
|
-
}
|
|
22941
|
-
}
|
|
22942
|
-
);
|
|
22943
|
-
try {
|
|
22944
|
-
await requireSupportPassportOwnerLock(ownerLock);
|
|
22945
|
-
} catch (error) {
|
|
22946
|
-
await this.revokeCommittedGrant(created, owner);
|
|
22947
|
-
throw error;
|
|
22948
|
-
}
|
|
22949
|
-
if (options.signal?.aborted) {
|
|
22950
|
-
await this.revokeCommittedGrant(created, owner);
|
|
22951
|
-
options.signal.throwIfAborted();
|
|
22952
|
-
}
|
|
22953
|
-
const output = SupportPassportCreatedGrantSchema.parse({
|
|
22954
|
-
grant: this.ownerGrant(created.state),
|
|
22955
|
-
secret: created.secret
|
|
22956
|
-
});
|
|
22957
|
-
notifySupportPassportCommitted(options.onCommitted);
|
|
22958
|
-
return output;
|
|
22959
|
-
}
|
|
22960
|
-
);
|
|
22961
|
-
}
|
|
22962
|
-
async listGrants(input) {
|
|
22963
|
-
const parsed = SupportPassportListGrantsInputSchema.safeParse(input);
|
|
22964
|
-
if (!parsed.success) throw invalidInput2();
|
|
22965
|
-
const owner = await this.resolveOwnerScope(parsed.data.principal);
|
|
22966
|
-
return (await this.grantStore.listForOwner(owner.namespace, owner.principal)).map(
|
|
22967
|
-
(state) => this.ownerGrant(state)
|
|
22968
|
-
);
|
|
22969
|
-
}
|
|
22970
|
-
async revokeGrant(input, options = {}) {
|
|
22971
|
-
const parsed = SupportPassportRevokeGrantInputSchema.safeParse(input);
|
|
22972
|
-
if (!parsed.success) throw invalidInput2();
|
|
22973
|
-
const owner = await this.resolveOwnerScope(parsed.data.principal);
|
|
22974
|
-
return await withSupportPassportOwnerLock(
|
|
22975
|
-
owner.storage,
|
|
22976
|
-
{ namespace: owner.namespace, principal: owner.principal },
|
|
22977
|
-
async (ownerLock) => {
|
|
22978
|
-
options.signal?.throwIfAborted();
|
|
22979
|
-
const state = await this.grantStore.revoke(
|
|
22980
|
-
{
|
|
22981
|
-
grantId: parsed.data.grantId,
|
|
22982
|
-
namespace: owner.namespace,
|
|
22983
|
-
principal: owner.principal,
|
|
22984
|
-
expectedStateVersion: parsed.data.expectedStateVersion
|
|
22985
|
-
},
|
|
22986
|
-
{
|
|
22987
|
-
beforeCommit: async () => {
|
|
22988
|
-
options.signal?.throwIfAborted();
|
|
22989
|
-
await requireSupportPassportOwnerLock(ownerLock);
|
|
22990
|
-
}
|
|
22991
|
-
}
|
|
22992
|
-
);
|
|
22993
|
-
const output = this.ownerGrant(state);
|
|
22994
|
-
notifySupportPassportCommitted(options.onCommitted);
|
|
22995
|
-
return output;
|
|
22996
|
-
}
|
|
22997
|
-
);
|
|
22998
|
-
}
|
|
22999
|
-
async readGrant(input) {
|
|
23000
|
-
if (!input || typeof input.grantId !== "string" || typeof input.secret !== "string") {
|
|
23001
|
-
throw new SupportPassportError("grant_not_found", "The share link was not found.", 404);
|
|
23002
|
-
}
|
|
23003
|
-
return await this.readGrantAttempt(input);
|
|
23004
|
-
}
|
|
23005
|
-
async readGrantAttempt(input) {
|
|
23006
|
-
const initialState = await this.grantStore.authenticate(input.grantId, input.secret);
|
|
23007
|
-
const storage = await this.resolveNamespace(initialState.namespace);
|
|
23008
|
-
const initialSnapshot = await this.readStoredCardSnapshot(
|
|
23009
|
-
storage,
|
|
23010
|
-
initialState.namespace,
|
|
23011
|
-
initialState.principalHash
|
|
23012
|
-
);
|
|
23013
|
-
const cards = this.readGrantCards(initialSnapshot, initialState);
|
|
23014
|
-
const firstCard = cards[0];
|
|
23015
|
-
if (!firstCard) throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
23016
|
-
const updatedAt = cards.reduce((latest, card) => {
|
|
23017
|
-
return Date.parse(card.updatedAt) > Date.parse(latest) ? card.updatedAt : latest;
|
|
23018
|
-
}, firstCard.updatedAt);
|
|
23019
|
-
return await withSupportPassportOwnerLock(
|
|
23020
|
-
storage,
|
|
23021
|
-
{ namespace: initialState.namespace, ownerKey: initialState.ownerLockKey },
|
|
23022
|
-
async (ownerLock) => {
|
|
23023
|
-
return await this.grantStore.withAuthenticatedGrant(
|
|
23024
|
-
input.grantId,
|
|
23025
|
-
input.secret,
|
|
23026
|
-
async (finalState) => {
|
|
23027
|
-
if (finalState.namespace !== initialState.namespace) {
|
|
23028
|
-
throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
23029
|
-
}
|
|
23030
|
-
await requireSupportPassportOwnerLock(ownerLock);
|
|
23031
|
-
const currentSnapshot = await this.readStoredCardSnapshot(
|
|
23032
|
-
storage,
|
|
23033
|
-
finalState.namespace,
|
|
23034
|
-
finalState.principalHash
|
|
23035
|
-
);
|
|
23036
|
-
const currentCards = this.readGrantCards(currentSnapshot, finalState);
|
|
23037
|
-
await requireSupportPassportOwnerLock(ownerLock);
|
|
23038
|
-
if (JSON.stringify(currentCards) !== JSON.stringify(cards)) {
|
|
23039
|
-
throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
23040
|
-
}
|
|
23041
|
-
return SupportPassportPublicGuideSchema.parse({
|
|
23042
|
-
schemaVersion: 1,
|
|
23043
|
-
grantId: finalState.grantId,
|
|
23044
|
-
expiresAt: finalState.expiresAt,
|
|
23045
|
-
updatedAt,
|
|
23046
|
-
cards
|
|
23047
|
-
});
|
|
23048
|
-
},
|
|
23049
|
-
async () => await requireSupportPassportOwnerLock(ownerLock)
|
|
23050
|
-
);
|
|
23051
|
-
}
|
|
23052
|
-
);
|
|
23053
|
-
}
|
|
23054
|
-
readGrantCards(snapshot, state) {
|
|
23055
|
-
return state.cards.map((cardRef) => {
|
|
23056
|
-
const stored = snapshot.cardsById.get(cardRef.cardId);
|
|
23057
|
-
if (!stored || stored.namespace !== state.namespace || stored.owner !== state.principalHash || stored.card.status !== "active" || stored.card.revision !== cardRef.revision) {
|
|
23058
|
-
throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
23059
|
-
}
|
|
23060
|
-
const publicCard = this.publicCard(stored.card);
|
|
23061
|
-
if (!publicCard.success) {
|
|
23062
|
-
throw new SupportPassportError("grant_stale", "The shared support guide has changed.", 410);
|
|
23063
|
-
}
|
|
23064
|
-
return publicCard.data;
|
|
23065
|
-
});
|
|
23066
|
-
}
|
|
23067
|
-
async readStoredCardSnapshot(storage, namespace, owner) {
|
|
23068
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
23069
|
-
const before = this.cardSnapshotVersion(storage);
|
|
23070
|
-
const memories = await storage.readAllMemories();
|
|
23071
|
-
const after = this.cardSnapshotVersion(storage);
|
|
23072
|
-
if (before !== after) continue;
|
|
23073
|
-
const cards = this.projectOwnedCards(memories, namespace, owner);
|
|
23074
|
-
const snapshot = {
|
|
23075
|
-
version: after,
|
|
23076
|
-
cardsById: new Map(cards.map((card) => [card.card.cardId, card]))
|
|
23077
|
-
};
|
|
23078
|
-
return snapshot;
|
|
23079
|
-
}
|
|
23080
|
-
throw new SupportPassportError("storage_conflict", "The support card list changed during review.", 409);
|
|
23081
|
-
}
|
|
23082
|
-
projectOwnedCards(memories, namespace, owner) {
|
|
23083
|
-
const cards = memories.map((memory) => projectSupportPassportCard(memory)).filter(
|
|
23084
|
-
(card) => card !== null && card.namespace === namespace && card.owner === owner
|
|
23085
|
-
);
|
|
23086
|
-
const cardIds = /* @__PURE__ */ new Set();
|
|
23087
|
-
for (const card of cards) {
|
|
23088
|
-
if (cardIds.has(card.card.cardId)) {
|
|
23089
|
-
throw new SupportPassportError("card_data_invalid", "Support card IDs must be unique.", 500);
|
|
23090
|
-
}
|
|
23091
|
-
cardIds.add(card.card.cardId);
|
|
23092
|
-
}
|
|
23093
|
-
return cards;
|
|
23094
|
-
}
|
|
23095
|
-
cardSnapshotVersion(storage) {
|
|
23096
|
-
return `${storage.getCorpusScanVersion()}:${storage.hotCacheKeyId()}`;
|
|
23097
|
-
}
|
|
23098
|
-
async revokeCommittedGrant(created, owner) {
|
|
23099
|
-
try {
|
|
23100
|
-
await this.grantStore.revoke({
|
|
23101
|
-
grantId: created.state.grantId,
|
|
23102
|
-
namespace: owner.namespace,
|
|
23103
|
-
principal: owner.principal,
|
|
23104
|
-
expectedStateVersion: created.state.stateVersion
|
|
23105
|
-
});
|
|
23106
|
-
} catch {
|
|
23107
|
-
throw new SupportPassportError(
|
|
23108
|
-
"storage_conflict",
|
|
23109
|
-
"A share link could not be stopped after owner access changed. Review the active share list.",
|
|
23110
|
-
500
|
|
23111
|
-
);
|
|
23112
|
-
}
|
|
23113
|
-
}
|
|
23114
|
-
publicCard(card) {
|
|
23115
|
-
return SupportPassportPublicCardSchema.safeParse({
|
|
23116
|
-
cardId: card.cardId,
|
|
23117
|
-
title: card.title,
|
|
23118
|
-
statement: card.statement,
|
|
23119
|
-
category: card.category,
|
|
23120
|
-
updatedAt: card.updatedAt
|
|
23121
|
-
});
|
|
23122
|
-
}
|
|
23123
|
-
async resolveOwnerScope(principal) {
|
|
23124
|
-
const requestedPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal });
|
|
23125
|
-
const owner = await this.resolveOwner(principal);
|
|
23126
|
-
const namespace = SupportPassportNamespaceSchema.safeParse(owner.namespace);
|
|
23127
|
-
const ownerPrincipal = SupportPassportListCardsInputSchema.safeParse({ principal: owner.principal });
|
|
23128
|
-
if (!requestedPrincipal.success || !namespace.success || !ownerPrincipal.success || ownerPrincipal.data.principal !== requestedPrincipal.data.principal) {
|
|
23129
|
-
throw new SupportPassportError("card_data_invalid", "The support passport owner scope is invalid.", 500);
|
|
23130
|
-
}
|
|
23131
|
-
return { ...owner, principal: ownerPrincipal.data.principal, namespace: namespace.data };
|
|
23132
|
-
}
|
|
23133
|
-
ownerGrant(state) {
|
|
23134
|
-
const status = state.revokedAt ? "revoked" : Date.parse(state.expiresAt) <= this.now().getTime() ? "expired" : "active";
|
|
23135
|
-
return SupportPassportOwnerGrantSchema.parse({
|
|
23136
|
-
grantId: state.grantId,
|
|
23137
|
-
stateVersion: state.stateVersion,
|
|
23138
|
-
cards: state.cards,
|
|
23139
|
-
createdAt: state.createdAt,
|
|
23140
|
-
expiresAt: state.expiresAt,
|
|
23141
|
-
revokedAt: state.revokedAt,
|
|
23142
|
-
status
|
|
23143
|
-
});
|
|
23144
|
-
}
|
|
23145
|
-
};
|
|
23146
|
-
|
|
23147
|
-
// src/relay/mission-fixture.ts
|
|
23148
|
-
var RELAY_DEMO_MISSION_ID = "checkout-token-recovery";
|
|
23149
|
-
var RELAY_DEMO_NAMESPACE = "relay-build-week";
|
|
23150
|
-
var sourceEvidence = {
|
|
23151
|
-
kind: "source",
|
|
23152
|
-
id: "source-checkout-contract",
|
|
23153
|
-
label: "Checkout token contract",
|
|
23154
|
-
locator: "fixture://checkout-service/src/token-policy.ts",
|
|
23155
|
-
capture: "fixture"
|
|
23156
|
-
};
|
|
23157
|
-
var testEvidence = {
|
|
23158
|
-
kind: "test",
|
|
23159
|
-
id: "test-checkout-contract",
|
|
23160
|
-
label: "Checkout integration contract",
|
|
23161
|
-
locator: "fixture://checkout-service/test/token-policy.test.ts",
|
|
23162
|
-
capture: "fixture"
|
|
23163
|
-
};
|
|
23164
|
-
var approvalEvidence = {
|
|
23165
|
-
kind: "approval",
|
|
23166
|
-
id: "approval-build-week-operator",
|
|
23167
|
-
label: "Human approval receipt",
|
|
23168
|
-
locator: "fixture://relay/approvals/correction-token-refresh.json",
|
|
23169
|
-
capture: "fixture"
|
|
23170
|
-
};
|
|
23171
|
-
var correctionEvidence = {
|
|
23172
|
-
kind: "correction",
|
|
23173
|
-
id: "correction-token-refresh",
|
|
23174
|
-
label: "Applied Remnic correction",
|
|
23175
|
-
locator: "fixture://remnic/corrections/correction-token-refresh.json",
|
|
23176
|
-
capture: "fixture"
|
|
23177
|
-
};
|
|
23178
|
-
function at(second) {
|
|
23179
|
-
return `2026-07-17T18:00:${String(second).padStart(2, "0")}.000Z`;
|
|
23180
|
-
}
|
|
23181
|
-
function createRelayMissionFixture() {
|
|
23182
|
-
return [
|
|
23183
|
-
{
|
|
23184
|
-
occurredAt: at(0),
|
|
23185
|
-
idempotencyKey: "fixture-001",
|
|
23186
|
-
payload: {
|
|
23187
|
-
kind: "mission_started",
|
|
23188
|
-
title: "The checkout token split",
|
|
23189
|
-
objective: "Resolve a conflicting token refresh policy and prove a cold agent acts on it.",
|
|
23190
|
-
runMode: "fixture",
|
|
23191
|
-
evidence: [sourceEvidence]
|
|
23192
|
-
}
|
|
23193
|
-
},
|
|
23194
|
-
{
|
|
23195
|
-
occurredAt: at(2),
|
|
23196
|
-
idempotencyKey: "fixture-002",
|
|
23197
|
-
payload: {
|
|
23198
|
-
kind: "agent_status",
|
|
23199
|
-
agentId: "agent-atlas",
|
|
23200
|
-
sessionId: "session-atlas",
|
|
23201
|
-
label: "Atlas",
|
|
23202
|
-
role: "Checkout implementation",
|
|
23203
|
-
status: "working",
|
|
23204
|
-
evidence: [sourceEvidence]
|
|
23205
|
-
}
|
|
23206
|
-
},
|
|
23207
|
-
{
|
|
23208
|
-
occurredAt: at(3),
|
|
23209
|
-
idempotencyKey: "fixture-003",
|
|
23210
|
-
payload: {
|
|
23211
|
-
kind: "agent_status",
|
|
23212
|
-
agentId: "agent-nova",
|
|
23213
|
-
sessionId: "session-nova",
|
|
23214
|
-
label: "Nova",
|
|
23215
|
-
role: "Integration verification",
|
|
23216
|
-
status: "working",
|
|
23217
|
-
evidence: [testEvidence]
|
|
23218
|
-
}
|
|
23219
|
-
},
|
|
23220
|
-
{
|
|
23221
|
-
occurredAt: at(6),
|
|
23222
|
-
idempotencyKey: "fixture-004",
|
|
23223
|
-
payload: {
|
|
23224
|
-
kind: "agent_output",
|
|
23225
|
-
agentId: "agent-atlas",
|
|
23226
|
-
sessionId: "session-atlas",
|
|
23227
|
-
outputId: "output-atlas-policy",
|
|
23228
|
-
summary: "Implemented a new token for every checkout retry.",
|
|
23229
|
-
evidence: [
|
|
23230
|
-
{
|
|
23231
|
-
kind: "agent_output",
|
|
23232
|
-
id: "output-atlas-policy",
|
|
23233
|
-
label: "Atlas one-shot output",
|
|
23234
|
-
locator: "fixture://codex/atlas/final-output.txt",
|
|
23235
|
-
capture: "fixture"
|
|
23236
|
-
}
|
|
23237
|
-
]
|
|
23238
|
-
}
|
|
23239
|
-
},
|
|
23240
|
-
{
|
|
23241
|
-
occurredAt: at(7),
|
|
23242
|
-
idempotencyKey: "fixture-005",
|
|
23243
|
-
payload: {
|
|
23244
|
-
kind: "belief_observed",
|
|
23245
|
-
agentId: "agent-atlas",
|
|
23246
|
-
sessionId: "session-atlas",
|
|
23247
|
-
beliefId: "belief-new-token-every-request",
|
|
23248
|
-
decisionId: "decision-new-token-every-request",
|
|
23249
|
-
statement: "Mint a new checkout token for every request and retry.",
|
|
23250
|
-
confidence: 0.91,
|
|
23251
|
-
evidence: [
|
|
23252
|
-
{
|
|
23253
|
-
kind: "memory",
|
|
23254
|
-
id: "memory-stale-token-policy",
|
|
23255
|
-
label: "Stale project decision",
|
|
23256
|
-
locator: "fixture://remnic/memories/memory-stale-token-policy.md",
|
|
23257
|
-
capture: "fixture"
|
|
23258
|
-
}
|
|
23259
|
-
]
|
|
23260
|
-
}
|
|
23261
|
-
},
|
|
23262
|
-
{
|
|
23263
|
-
occurredAt: at(9),
|
|
23264
|
-
idempotencyKey: "fixture-006",
|
|
23265
|
-
payload: {
|
|
23266
|
-
kind: "agent_output",
|
|
23267
|
-
agentId: "agent-nova",
|
|
23268
|
-
sessionId: "session-nova",
|
|
23269
|
-
outputId: "output-nova-policy",
|
|
23270
|
-
summary: "The contract requires one token per checkout session, refreshed only after expiry.",
|
|
23271
|
-
evidence: [
|
|
23272
|
-
{
|
|
23273
|
-
kind: "agent_output",
|
|
23274
|
-
id: "output-nova-policy",
|
|
23275
|
-
label: "Nova one-shot output",
|
|
23276
|
-
locator: "fixture://codex/nova/final-output.txt",
|
|
23277
|
-
capture: "fixture"
|
|
23278
|
-
},
|
|
23279
|
-
sourceEvidence
|
|
23280
|
-
]
|
|
23281
|
-
}
|
|
23282
|
-
},
|
|
23283
|
-
{
|
|
23284
|
-
occurredAt: at(10),
|
|
23285
|
-
idempotencyKey: "fixture-007",
|
|
23286
|
-
payload: {
|
|
23287
|
-
kind: "belief_observed",
|
|
23288
|
-
agentId: "agent-nova",
|
|
23289
|
-
sessionId: "session-nova",
|
|
23290
|
-
beliefId: "belief-refresh-after-expiry",
|
|
23291
|
-
decisionId: "decision-refresh-after-expiry",
|
|
23292
|
-
statement: "Reuse the checkout-session token and refresh it only after expiry.",
|
|
23293
|
-
confidence: 0.98,
|
|
23294
|
-
evidence: [sourceEvidence]
|
|
23295
|
-
}
|
|
23296
|
-
},
|
|
23297
|
-
{
|
|
23298
|
-
occurredAt: at(12),
|
|
23299
|
-
idempotencyKey: "fixture-008",
|
|
23300
|
-
payload: {
|
|
23301
|
-
kind: "conflict_detected",
|
|
23302
|
-
conflictId: "conflict-token-lifecycle",
|
|
23303
|
-
decisionIds: ["decision-refresh-after-expiry", "decision-new-token-every-request"],
|
|
23304
|
-
agentIds: ["agent-nova", "agent-atlas"],
|
|
23305
|
-
summary: "The agents disagree on whether retries reuse or rotate the checkout token.",
|
|
23306
|
-
evidence: [sourceEvidence, testEvidence]
|
|
21100
|
+
},
|
|
21101
|
+
{
|
|
21102
|
+
occurredAt: at(12),
|
|
21103
|
+
idempotencyKey: "fixture-008",
|
|
21104
|
+
payload: {
|
|
21105
|
+
kind: "conflict_detected",
|
|
21106
|
+
conflictId: "conflict-token-lifecycle",
|
|
21107
|
+
decisionIds: ["decision-refresh-after-expiry", "decision-new-token-every-request"],
|
|
21108
|
+
agentIds: ["agent-nova", "agent-atlas"],
|
|
21109
|
+
summary: "The agents disagree on whether retries reuse or rotate the checkout token.",
|
|
21110
|
+
evidence: [sourceEvidence, testEvidence]
|
|
23307
21111
|
}
|
|
23308
21112
|
},
|
|
23309
21113
|
{
|
|
@@ -23889,9 +21693,9 @@ function readStructuralSymbol(entry) {
|
|
|
23889
21693
|
const rec = entry;
|
|
23890
21694
|
const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
|
|
23891
21695
|
if (!symbol) return null;
|
|
23892
|
-
const
|
|
21696
|
+
const path35 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
|
|
23893
21697
|
const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
|
|
23894
|
-
const item =
|
|
21698
|
+
const item = path35 !== void 0 && kind !== void 0 ? { symbol, path: path35, kind } : path35 !== void 0 ? { symbol, path: path35 } : kind !== void 0 ? { symbol, kind } : { symbol };
|
|
23895
21699
|
return item;
|
|
23896
21700
|
}
|
|
23897
21701
|
function classifySpawnError(err) {
|
|
@@ -23965,7 +21769,7 @@ var DEFAULT_GRACE_PERIOD_DAYS = 7;
|
|
|
23965
21769
|
|
|
23966
21770
|
// src/binary-lifecycle/backend.ts
|
|
23967
21771
|
import fsp from "fs/promises";
|
|
23968
|
-
import
|
|
21772
|
+
import path21 from "path";
|
|
23969
21773
|
var FilesystemBackend = class {
|
|
23970
21774
|
type = "filesystem";
|
|
23971
21775
|
basePath;
|
|
@@ -23973,27 +21777,27 @@ var FilesystemBackend = class {
|
|
|
23973
21777
|
if (!basePath || basePath.trim().length === 0) {
|
|
23974
21778
|
throw new Error("FilesystemBackend requires a non-empty basePath");
|
|
23975
21779
|
}
|
|
23976
|
-
this.basePath =
|
|
21780
|
+
this.basePath = path21.resolve(basePath);
|
|
23977
21781
|
}
|
|
23978
21782
|
resolveRemotePath(remotePath) {
|
|
23979
|
-
const resolved =
|
|
23980
|
-
const relative =
|
|
23981
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
21783
|
+
const resolved = path21.isAbsolute(remotePath) ? path21.resolve(remotePath) : path21.resolve(this.basePath, remotePath);
|
|
21784
|
+
const relative = path21.relative(this.basePath, resolved);
|
|
21785
|
+
if (relative === ".." || relative.startsWith(`..${path21.sep}`) || path21.isAbsolute(relative)) {
|
|
23982
21786
|
throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
23983
21787
|
}
|
|
23984
21788
|
return resolved;
|
|
23985
21789
|
}
|
|
23986
21790
|
isInsideBase(candidate, realBase) {
|
|
23987
|
-
const relative =
|
|
23988
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
21791
|
+
const relative = path21.relative(realBase, candidate);
|
|
21792
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path21.sep}`) && !path21.isAbsolute(relative);
|
|
23989
21793
|
}
|
|
23990
21794
|
async realBasePathIfExists() {
|
|
23991
21795
|
try {
|
|
23992
|
-
const
|
|
23993
|
-
if (
|
|
21796
|
+
const stat5 = await fsp.lstat(this.basePath);
|
|
21797
|
+
if (stat5.isSymbolicLink()) {
|
|
23994
21798
|
throw new Error(`FilesystemBackend basePath must not be a symlink: ${this.basePath}`);
|
|
23995
21799
|
}
|
|
23996
|
-
if (!
|
|
21800
|
+
if (!stat5.isDirectory()) {
|
|
23997
21801
|
throw new Error(`FilesystemBackend basePath must be a directory: ${this.basePath}`);
|
|
23998
21802
|
}
|
|
23999
21803
|
return await fsp.realpath(this.basePath);
|
|
@@ -24014,19 +21818,19 @@ var FilesystemBackend = class {
|
|
|
24014
21818
|
}
|
|
24015
21819
|
async ensureSafeParentDirectory(dest) {
|
|
24016
21820
|
const realBase = await this.ensureBaseDirectory();
|
|
24017
|
-
const destDir =
|
|
24018
|
-
const relativeDir =
|
|
24019
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
21821
|
+
const destDir = path21.dirname(dest);
|
|
21822
|
+
const relativeDir = path21.relative(this.basePath, destDir);
|
|
21823
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path21.sep);
|
|
24020
21824
|
let current = this.basePath;
|
|
24021
21825
|
for (const segment of segments) {
|
|
24022
21826
|
if (segment === "." || segment === "") continue;
|
|
24023
|
-
current =
|
|
21827
|
+
current = path21.join(current, segment);
|
|
24024
21828
|
try {
|
|
24025
|
-
const
|
|
24026
|
-
if (
|
|
21829
|
+
const stat5 = await fsp.lstat(current);
|
|
21830
|
+
if (stat5.isSymbolicLink()) {
|
|
24027
21831
|
throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);
|
|
24028
21832
|
}
|
|
24029
|
-
if (!
|
|
21833
|
+
if (!stat5.isDirectory()) {
|
|
24030
21834
|
throw new Error(`FilesystemBackend remotePath parent is not a directory: ${current}`);
|
|
24031
21835
|
}
|
|
24032
21836
|
} catch (err) {
|
|
@@ -24048,26 +21852,26 @@ var FilesystemBackend = class {
|
|
|
24048
21852
|
if (realBase === null) {
|
|
24049
21853
|
return null;
|
|
24050
21854
|
}
|
|
24051
|
-
const destDir =
|
|
24052
|
-
const relativeDir =
|
|
24053
|
-
const segments = relativeDir === "" ? [] : relativeDir.split(
|
|
21855
|
+
const destDir = path21.dirname(dest);
|
|
21856
|
+
const relativeDir = path21.relative(this.basePath, destDir);
|
|
21857
|
+
const segments = relativeDir === "" ? [] : relativeDir.split(path21.sep);
|
|
24054
21858
|
let current = this.basePath;
|
|
24055
21859
|
for (const segment of segments) {
|
|
24056
21860
|
if (segment === "." || segment === "") continue;
|
|
24057
|
-
current =
|
|
24058
|
-
let
|
|
21861
|
+
current = path21.join(current, segment);
|
|
21862
|
+
let stat5;
|
|
24059
21863
|
try {
|
|
24060
|
-
|
|
21864
|
+
stat5 = await fsp.lstat(current);
|
|
24061
21865
|
} catch (err) {
|
|
24062
21866
|
if (err.code === "ENOENT") {
|
|
24063
21867
|
return null;
|
|
24064
21868
|
}
|
|
24065
21869
|
throw err;
|
|
24066
21870
|
}
|
|
24067
|
-
if (
|
|
21871
|
+
if (stat5.isSymbolicLink()) {
|
|
24068
21872
|
throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);
|
|
24069
21873
|
}
|
|
24070
|
-
if (!
|
|
21874
|
+
if (!stat5.isDirectory()) {
|
|
24071
21875
|
return null;
|
|
24072
21876
|
}
|
|
24073
21877
|
}
|
|
@@ -24082,11 +21886,11 @@ var FilesystemBackend = class {
|
|
|
24082
21886
|
throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${JSON.stringify(remotePath)}`);
|
|
24083
21887
|
}
|
|
24084
21888
|
try {
|
|
24085
|
-
const
|
|
24086
|
-
if (
|
|
21889
|
+
const stat5 = await fsp.lstat(dest);
|
|
21890
|
+
if (stat5.isSymbolicLink()) {
|
|
24087
21891
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24088
21892
|
}
|
|
24089
|
-
if (!
|
|
21893
|
+
if (!stat5.isFile()) {
|
|
24090
21894
|
return null;
|
|
24091
21895
|
}
|
|
24092
21896
|
} catch (err) {
|
|
@@ -24102,14 +21906,14 @@ var FilesystemBackend = class {
|
|
|
24102
21906
|
return dest;
|
|
24103
21907
|
}
|
|
24104
21908
|
async upload(localPath, remotePath) {
|
|
24105
|
-
if (
|
|
21909
|
+
if (path21.isAbsolute(remotePath)) {
|
|
24106
21910
|
throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);
|
|
24107
21911
|
}
|
|
24108
21912
|
const dest = this.resolveRemotePath(remotePath);
|
|
24109
21913
|
const realBase = await this.ensureSafeParentDirectory(dest);
|
|
24110
21914
|
try {
|
|
24111
|
-
const
|
|
24112
|
-
if (
|
|
21915
|
+
const stat5 = await fsp.lstat(dest);
|
|
21916
|
+
if (stat5.isSymbolicLink()) {
|
|
24113
21917
|
throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);
|
|
24114
21918
|
}
|
|
24115
21919
|
} catch (err) {
|
|
@@ -24175,7 +21979,7 @@ function createBackend(cfg) {
|
|
|
24175
21979
|
|
|
24176
21980
|
// src/binary-lifecycle/scanner.ts
|
|
24177
21981
|
import fsp2 from "fs/promises";
|
|
24178
|
-
import
|
|
21982
|
+
import path22 from "path";
|
|
24179
21983
|
import crypto from "crypto";
|
|
24180
21984
|
function matchesPatterns(filename, patterns) {
|
|
24181
21985
|
const lower = filename.toLowerCase();
|
|
@@ -24200,8 +22004,8 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24200
22004
|
return;
|
|
24201
22005
|
}
|
|
24202
22006
|
for (const entry of entries) {
|
|
24203
|
-
const fullPath =
|
|
24204
|
-
const relativePath =
|
|
22007
|
+
const fullPath = path22.join(dir, entry.name);
|
|
22008
|
+
const relativePath = path22.relative(memoryDir, fullPath).split(path22.sep).join("/");
|
|
24205
22009
|
if (entry.isDirectory()) {
|
|
24206
22010
|
if (entry.name === ".binary-lifecycle") continue;
|
|
24207
22011
|
await walk(fullPath);
|
|
@@ -24210,12 +22014,12 @@ async function scanForBinaries(memoryDir, config, manifest) {
|
|
|
24210
22014
|
if (!entry.isFile()) continue;
|
|
24211
22015
|
if (!matchesPatterns(entry.name, config.scanPatterns)) continue;
|
|
24212
22016
|
try {
|
|
24213
|
-
const
|
|
24214
|
-
if (
|
|
24215
|
-
if (
|
|
22017
|
+
const stat5 = await fsp2.stat(fullPath);
|
|
22018
|
+
if (stat5.size > config.maxBinarySizeBytes) continue;
|
|
22019
|
+
if (stat5.size === 0) continue;
|
|
24216
22020
|
const existing = tracked.get(relativePath);
|
|
24217
22021
|
if (existing) {
|
|
24218
|
-
if (existing.sizeBytes !==
|
|
22022
|
+
if (existing.sizeBytes !== stat5.size) {
|
|
24219
22023
|
results.push(relativePath);
|
|
24220
22024
|
continue;
|
|
24221
22025
|
}
|
|
@@ -24241,15 +22045,15 @@ async function hashFile(filePath) {
|
|
|
24241
22045
|
|
|
24242
22046
|
// src/binary-lifecycle/manifest.ts
|
|
24243
22047
|
import fsp3 from "fs/promises";
|
|
24244
|
-
import
|
|
22048
|
+
import path23 from "path";
|
|
24245
22049
|
import crypto2 from "crypto";
|
|
24246
22050
|
var MANIFEST_DIR = ".binary-lifecycle";
|
|
24247
22051
|
var MANIFEST_FILE = "manifest.json";
|
|
24248
22052
|
function manifestDir(memoryDir) {
|
|
24249
|
-
return
|
|
22053
|
+
return path23.join(memoryDir, MANIFEST_DIR);
|
|
24250
22054
|
}
|
|
24251
22055
|
function manifestPath(memoryDir) {
|
|
24252
|
-
return
|
|
22056
|
+
return path23.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);
|
|
24253
22057
|
}
|
|
24254
22058
|
async function readManifest(memoryDir) {
|
|
24255
22059
|
const filePath = manifestPath(memoryDir);
|
|
@@ -24301,13 +22105,13 @@ function emptyManifest() {
|
|
|
24301
22105
|
|
|
24302
22106
|
// src/binary-lifecycle/pipeline.ts
|
|
24303
22107
|
import fsp4 from "fs/promises";
|
|
24304
|
-
import
|
|
22108
|
+
import path24 from "path";
|
|
24305
22109
|
import crypto3 from "crypto";
|
|
24306
22110
|
var historicalIdCache = new HistoricalEntityCanonicalIdCache();
|
|
24307
22111
|
function isRecallCorpusMarkdown(mdPath, memoryDir) {
|
|
24308
|
-
const rel =
|
|
24309
|
-
if (rel.startsWith("..") ||
|
|
24310
|
-
const top = rel.split(
|
|
22112
|
+
const rel = path24.relative(memoryDir, mdPath);
|
|
22113
|
+
if (rel.startsWith("..") || path24.isAbsolute(rel)) return false;
|
|
22114
|
+
const top = rel.split(path24.sep)[0];
|
|
24311
22115
|
return RECALL_FALLBACK_DIRS.includes(top);
|
|
24312
22116
|
}
|
|
24313
22117
|
async function hashFile2(filePath) {
|
|
@@ -24331,13 +22135,13 @@ function escapeRegex(s) {
|
|
|
24331
22135
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24332
22136
|
}
|
|
24333
22137
|
function resolveManifestAssetPath(memoryDir, originalPath) {
|
|
24334
|
-
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") ||
|
|
22138
|
+
if (originalPath.length === 0 || originalPath.includes("\0") || originalPath.includes("\\") || path24.isAbsolute(originalPath) || path24.win32.isAbsolute(originalPath)) {
|
|
24335
22139
|
return null;
|
|
24336
22140
|
}
|
|
24337
|
-
const memoryRoot =
|
|
24338
|
-
const fullPath =
|
|
24339
|
-
const relative =
|
|
24340
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${
|
|
22141
|
+
const memoryRoot = path24.resolve(memoryDir);
|
|
22142
|
+
const fullPath = path24.resolve(memoryRoot, originalPath);
|
|
22143
|
+
const relative = path24.relative(memoryRoot, fullPath);
|
|
22144
|
+
if (relative === "" || relative === ".." || relative.startsWith(`..${path24.sep}`) || path24.isAbsolute(relative)) {
|
|
24341
22145
|
return null;
|
|
24342
22146
|
}
|
|
24343
22147
|
return fullPath;
|
|
@@ -24348,7 +22152,7 @@ function validateBinaryLifecycleConfig(config) {
|
|
|
24348
22152
|
}
|
|
24349
22153
|
}
|
|
24350
22154
|
function remotePathForAsset(backend, relPath) {
|
|
24351
|
-
const normalized = relPath.split(
|
|
22155
|
+
const normalized = relPath.split(path24.sep).join("/");
|
|
24352
22156
|
if (backend.type === "filesystem") {
|
|
24353
22157
|
return `.binary-lifecycle/mirrors/${normalized}`;
|
|
24354
22158
|
}
|
|
@@ -24361,11 +22165,11 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
24361
22165
|
let mirrored = 0;
|
|
24362
22166
|
const errors = [];
|
|
24363
22167
|
for (const relPath of newPaths) {
|
|
24364
|
-
const fullPath =
|
|
22168
|
+
const fullPath = path24.join(memoryDir, relPath);
|
|
24365
22169
|
try {
|
|
24366
|
-
const
|
|
22170
|
+
const stat5 = await fsp4.stat(fullPath);
|
|
24367
22171
|
const contentHash = await hashFile2(fullPath);
|
|
24368
|
-
const ext =
|
|
22172
|
+
const ext = path24.extname(relPath);
|
|
24369
22173
|
const mimeType = guessMimeType(ext);
|
|
24370
22174
|
const remotePath = remotePathForAsset(backend, relPath);
|
|
24371
22175
|
let backendLocation = remotePath;
|
|
@@ -24378,7 +22182,7 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
24378
22182
|
mirroredPath: backendLocation,
|
|
24379
22183
|
...redirectPath ? { redirectPath } : {},
|
|
24380
22184
|
contentHash,
|
|
24381
|
-
sizeBytes:
|
|
22185
|
+
sizeBytes: stat5.size,
|
|
24382
22186
|
mimeType,
|
|
24383
22187
|
mirroredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24384
22188
|
status: "mirrored"
|
|
@@ -24391,7 +22195,7 @@ async function stageMirror(memoryDir, newPaths, backend, assets, log2, dryRun) {
|
|
|
24391
22195
|
assets.push(record);
|
|
24392
22196
|
}
|
|
24393
22197
|
mirrored++;
|
|
24394
|
-
log2.info(`[binary-lifecycle] mirrored: ${relPath} (${
|
|
22198
|
+
log2.info(`[binary-lifecycle] mirrored: ${relPath} (${stat5.size} bytes)${dryRun ? " [dry-run]" : ""}`);
|
|
24395
22199
|
} catch (err) {
|
|
24396
22200
|
const msg = `mirror failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`;
|
|
24397
22201
|
log2.error(`[binary-lifecycle] ${msg}`);
|
|
@@ -24425,8 +22229,8 @@ async function stageRedirect(memoryDir, assets, log2, dryRun, readMarkdownFile,
|
|
|
24425
22229
|
const pattern = markdownReferencePattern(asset, assetAbsolute, mdPath);
|
|
24426
22230
|
if (!pattern.test(content)) continue;
|
|
24427
22231
|
pattern.lastIndex = 0;
|
|
24428
|
-
const updated = content.replace(pattern, (_match,
|
|
24429
|
-
return `${
|
|
22232
|
+
const updated = content.replace(pattern, (_match, open, _target, close) => {
|
|
22233
|
+
return `${open}${markdownTargetForAsset(asset)}${close}`;
|
|
24430
22234
|
});
|
|
24431
22235
|
updates.push({ mdPath, content: updated });
|
|
24432
22236
|
} catch (err) {
|
|
@@ -24503,7 +22307,7 @@ async function stageRedirect(memoryDir, assets, log2, dryRun, readMarkdownFile,
|
|
|
24503
22307
|
for (const update of updates) {
|
|
24504
22308
|
try {
|
|
24505
22309
|
await withRawEntityPageMutation(memoryDir, update.mdPath, async () => {
|
|
24506
|
-
const stateDir =
|
|
22310
|
+
const stateDir = path24.join(memoryDir, "state");
|
|
24507
22311
|
const kind = classifyEntityRefWritePath(memoryDir, update.mdPath);
|
|
24508
22312
|
if (kind === "memory") {
|
|
24509
22313
|
const idsAtWrite = historicalIdCache.get(stateDir);
|
|
@@ -24597,10 +22401,10 @@ async function countRemainingLocalReferences(memoryDir, asset, assetAbsolute, md
|
|
|
24597
22401
|
return { remaining, errors };
|
|
24598
22402
|
}
|
|
24599
22403
|
function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
24600
|
-
const mdDir =
|
|
22404
|
+
const mdDir = path24.dirname(mdPath);
|
|
24601
22405
|
const candidates = /* @__PURE__ */ new Set();
|
|
24602
22406
|
const addCandidate = (candidate) => {
|
|
24603
|
-
const normalized = candidate.split(
|
|
22407
|
+
const normalized = candidate.split(path24.sep).join("/");
|
|
24604
22408
|
if (normalized.length === 0) return;
|
|
24605
22409
|
candidates.add(normalized);
|
|
24606
22410
|
const isParentTraversal = normalized === ".." || normalized.startsWith("../");
|
|
@@ -24608,10 +22412,10 @@ function markdownReferencePattern(asset, assetAbsolute, mdPath) {
|
|
|
24608
22412
|
candidates.add(`./${normalized}`);
|
|
24609
22413
|
}
|
|
24610
22414
|
};
|
|
24611
|
-
addCandidate(
|
|
24612
|
-
const originalPath = asset.originalPath.split(
|
|
24613
|
-
const originalAsFileRelative =
|
|
24614
|
-
if (
|
|
22415
|
+
addCandidate(path24.relative(mdDir, assetAbsolute));
|
|
22416
|
+
const originalPath = asset.originalPath.split(path24.sep).join("/");
|
|
22417
|
+
const originalAsFileRelative = path24.resolve(mdDir, ...originalPath.split("/"));
|
|
22418
|
+
if (path24.resolve(originalAsFileRelative) === path24.resolve(assetAbsolute)) {
|
|
24615
22419
|
addCandidate(originalPath);
|
|
24616
22420
|
}
|
|
24617
22421
|
addCandidate(`/${originalPath}`);
|
|
@@ -24707,7 +22511,7 @@ async function findMarkdownFiles(dir) {
|
|
|
24707
22511
|
return;
|
|
24708
22512
|
}
|
|
24709
22513
|
for (const entry of entries) {
|
|
24710
|
-
const full =
|
|
22514
|
+
const full = path24.join(current, entry.name);
|
|
24711
22515
|
if (entry.isDirectory()) {
|
|
24712
22516
|
if (entry.name === ".binary-lifecycle") continue;
|
|
24713
22517
|
await walk(full);
|
|
@@ -24782,7 +22586,7 @@ async function runBinaryLifecyclePipeline(memoryDir, config, backend, log2, opts
|
|
|
24782
22586
|
|
|
24783
22587
|
// src/projection/index.ts
|
|
24784
22588
|
import fs from "fs";
|
|
24785
|
-
import
|
|
22589
|
+
import path25 from "path";
|
|
24786
22590
|
var VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);
|
|
24787
22591
|
async function generateContextTree(options) {
|
|
24788
22592
|
const startTime = Date.now();
|
|
@@ -24797,8 +22601,8 @@ async function generateContextTree(options) {
|
|
|
24797
22601
|
let nodesGenerated = 0;
|
|
24798
22602
|
let nodesSkipped = 0;
|
|
24799
22603
|
const categoryCounts = {};
|
|
24800
|
-
const resolvedMemoryDir =
|
|
24801
|
-
const resolvedOutputDir =
|
|
22604
|
+
const resolvedMemoryDir = path25.resolve(memoryDir);
|
|
22605
|
+
const resolvedOutputDir = path25.resolve(outputDir);
|
|
24802
22606
|
const requestedCategories = validateProjectionCategories(filterCategories);
|
|
24803
22607
|
const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);
|
|
24804
22608
|
assertNotSymlink(resolvedOutputDir, "context tree outputDir");
|
|
@@ -24836,7 +22640,7 @@ async function generateContextTree(options) {
|
|
|
24836
22640
|
}
|
|
24837
22641
|
}
|
|
24838
22642
|
if (includeEntities) {
|
|
24839
|
-
const entitiesDir =
|
|
22643
|
+
const entitiesDir = path25.join(memoryDir, "entities");
|
|
24840
22644
|
if (fs.existsSync(entitiesDir)) {
|
|
24841
22645
|
assertSafeInputRoot(realMemoryDir, entitiesDir, "entities root");
|
|
24842
22646
|
categoryCounts["entity"] = 0;
|
|
@@ -24848,7 +22652,7 @@ async function generateContextTree(options) {
|
|
|
24848
22652
|
continue;
|
|
24849
22653
|
}
|
|
24850
22654
|
const content = fs.readFileSync(filePath, "utf8");
|
|
24851
|
-
const fileName =
|
|
22655
|
+
const fileName = path25.basename(filePath, ".md");
|
|
24852
22656
|
const node = projectEntityNode(fileName, content);
|
|
24853
22657
|
const outputPath = resolveContainedOutputPath(realOutputDir, "entities", `${fileName}.md`);
|
|
24854
22658
|
writeProjectedContent(realOutputDir, outputPath, node.content);
|
|
@@ -24860,7 +22664,7 @@ async function generateContextTree(options) {
|
|
|
24860
22664
|
}
|
|
24861
22665
|
const shouldIncludeQuestions = includeQuestions && (requestedCategories === void 0 || requestedCategories.includes("question"));
|
|
24862
22666
|
if (shouldIncludeQuestions) {
|
|
24863
|
-
const questionsDir =
|
|
22667
|
+
const questionsDir = path25.join(memoryDir, "questions");
|
|
24864
22668
|
if (fs.existsSync(questionsDir)) {
|
|
24865
22669
|
assertSafeInputRoot(realMemoryDir, questionsDir, "questions root");
|
|
24866
22670
|
categoryCounts["question"] = 0;
|
|
@@ -24901,8 +22705,8 @@ async function generateContextTree(options) {
|
|
|
24901
22705
|
};
|
|
24902
22706
|
}
|
|
24903
22707
|
function isPathInside(root, candidate) {
|
|
24904
|
-
const relative =
|
|
24905
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
22708
|
+
const relative = path25.relative(root, candidate);
|
|
22709
|
+
return relative === "" || !relative.startsWith("..") && !path25.isAbsolute(relative);
|
|
24906
22710
|
}
|
|
24907
22711
|
function assertNotSymlink(targetPath, label) {
|
|
24908
22712
|
try {
|
|
@@ -24915,21 +22719,21 @@ function assertNotSymlink(targetPath, label) {
|
|
|
24915
22719
|
}
|
|
24916
22720
|
}
|
|
24917
22721
|
function assertSafeMemoryRoot(targetPath) {
|
|
24918
|
-
const
|
|
24919
|
-
if (
|
|
22722
|
+
const stat5 = fs.lstatSync(targetPath);
|
|
22723
|
+
if (stat5.isSymbolicLink()) {
|
|
24920
22724
|
throw new Error(`memoryDir must not be a symlink: ${targetPath}`);
|
|
24921
22725
|
}
|
|
24922
|
-
if (!
|
|
22726
|
+
if (!stat5.isDirectory()) {
|
|
24923
22727
|
throw new Error(`memoryDir must be a directory: ${targetPath}`);
|
|
24924
22728
|
}
|
|
24925
22729
|
return fs.realpathSync(targetPath);
|
|
24926
22730
|
}
|
|
24927
22731
|
function assertSafeInputRoot(realMemoryDir, targetPath, label) {
|
|
24928
|
-
const
|
|
24929
|
-
if (
|
|
22732
|
+
const stat5 = fs.lstatSync(targetPath);
|
|
22733
|
+
if (stat5.isSymbolicLink()) {
|
|
24930
22734
|
throw new Error(`${label} must not be a symlink: ${targetPath}`);
|
|
24931
22735
|
}
|
|
24932
|
-
if (!
|
|
22736
|
+
if (!stat5.isDirectory()) {
|
|
24933
22737
|
throw new Error(`${label} must be a directory: ${targetPath}`);
|
|
24934
22738
|
}
|
|
24935
22739
|
const realTarget = fs.realpathSync(targetPath);
|
|
@@ -24939,15 +22743,15 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
|
|
|
24939
22743
|
}
|
|
24940
22744
|
function assertSafeOutputTarget(realOutputDir, outputPath) {
|
|
24941
22745
|
let current = realOutputDir;
|
|
24942
|
-
const relative =
|
|
24943
|
-
if (relative.startsWith("..") ||
|
|
22746
|
+
const relative = path25.relative(realOutputDir, outputPath);
|
|
22747
|
+
if (relative.startsWith("..") || path25.isAbsolute(relative)) {
|
|
24944
22748
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
24945
22749
|
}
|
|
24946
|
-
for (const segment of relative.split(
|
|
24947
|
-
current =
|
|
22750
|
+
for (const segment of relative.split(path25.sep).filter(Boolean)) {
|
|
22751
|
+
current = path25.join(current, segment);
|
|
24948
22752
|
try {
|
|
24949
|
-
const
|
|
24950
|
-
if (
|
|
22753
|
+
const stat5 = fs.lstatSync(current);
|
|
22754
|
+
if (stat5.isSymbolicLink()) {
|
|
24951
22755
|
throw new Error(`context tree output path contains symlink: ${current}`);
|
|
24952
22756
|
}
|
|
24953
22757
|
} catch (err) {
|
|
@@ -24974,17 +22778,17 @@ function validateProjectionCategories(categories) {
|
|
|
24974
22778
|
return validated;
|
|
24975
22779
|
}
|
|
24976
22780
|
function resolveContainedOutputPath(outputRoot, ...segments) {
|
|
24977
|
-
const resolved =
|
|
24978
|
-
const relative =
|
|
24979
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
22781
|
+
const resolved = path25.resolve(outputRoot, ...segments);
|
|
22782
|
+
const relative = path25.relative(outputRoot, resolved);
|
|
22783
|
+
if (relative === "" || !relative.startsWith("..") && !path25.isAbsolute(relative)) {
|
|
24980
22784
|
return resolved;
|
|
24981
22785
|
}
|
|
24982
22786
|
throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
|
|
24983
22787
|
}
|
|
24984
22788
|
function writeProjectedContent(realOutputDir, outputPath, generatedContent) {
|
|
24985
22789
|
assertSafeOutputTarget(realOutputDir, outputPath);
|
|
24986
|
-
fs.mkdirSync(
|
|
24987
|
-
const realParent = fs.realpathSync(
|
|
22790
|
+
fs.mkdirSync(path25.dirname(outputPath), { recursive: true });
|
|
22791
|
+
const realParent = fs.realpathSync(path25.dirname(outputPath));
|
|
24988
22792
|
if (!isPathInside(realOutputDir, realParent)) {
|
|
24989
22793
|
throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
|
|
24990
22794
|
}
|
|
@@ -25023,7 +22827,7 @@ function walkR(dir, realMemoryDir) {
|
|
|
25023
22827
|
const results = [];
|
|
25024
22828
|
function walk(directory) {
|
|
25025
22829
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
25026
|
-
const fullPath =
|
|
22830
|
+
const fullPath = path25.join(directory, entry.name);
|
|
25027
22831
|
if (entry.isSymbolicLink()) {
|
|
25028
22832
|
throw new Error(`context tree input path contains symlink: ${fullPath}`);
|
|
25029
22833
|
}
|
|
@@ -25076,13 +22880,13 @@ function extractBody(content) {
|
|
|
25076
22880
|
}
|
|
25077
22881
|
function projectNode(filePath, category, fm, rawContent) {
|
|
25078
22882
|
const body = extractBody(rawContent);
|
|
25079
|
-
const fileName =
|
|
25080
|
-
const dateDir =
|
|
22883
|
+
const fileName = path25.basename(filePath, ".md");
|
|
22884
|
+
const dateDir = path25.basename(path25.dirname(filePath));
|
|
25081
22885
|
let relPath;
|
|
25082
22886
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateDir)) {
|
|
25083
|
-
relPath =
|
|
22887
|
+
relPath = path25.join(category, dateDir, `${fileName}.md`);
|
|
25084
22888
|
} else {
|
|
25085
|
-
relPath =
|
|
22889
|
+
relPath = path25.join(category, `${fileName}.md`);
|
|
25086
22890
|
}
|
|
25087
22891
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25088
22892
|
const md = `# ${fm.id}
|
|
@@ -25128,7 +22932,7 @@ function projectEntityNode(fileName, content) {
|
|
|
25128
22932
|
${content}
|
|
25129
22933
|
`;
|
|
25130
22934
|
return {
|
|
25131
|
-
path:
|
|
22935
|
+
path: path25.join("entities", `${fileName}.md`),
|
|
25132
22936
|
category: "entity",
|
|
25133
22937
|
title: fileName,
|
|
25134
22938
|
content: md,
|
|
@@ -25181,7 +22985,7 @@ function generateIndex(categoryCounts, outputDir) {
|
|
|
25181
22985
|
|
|
25182
22986
|
// src/onboarding/index.ts
|
|
25183
22987
|
import fs2 from "fs";
|
|
25184
|
-
import
|
|
22988
|
+
import path26 from "path";
|
|
25185
22989
|
var LANGUAGE_RULES = [
|
|
25186
22990
|
{
|
|
25187
22991
|
language: "TypeScript",
|
|
@@ -25283,7 +23087,7 @@ function onboard(options) {
|
|
|
25283
23087
|
maxDepth = 6,
|
|
25284
23088
|
excludeDirs = []
|
|
25285
23089
|
} = options;
|
|
25286
|
-
const directory =
|
|
23090
|
+
const directory = path26.resolve(options.directory ?? process.cwd());
|
|
25287
23091
|
let rootStat;
|
|
25288
23092
|
try {
|
|
25289
23093
|
rootStat = fs2.statSync(directory);
|
|
@@ -25325,7 +23129,7 @@ function walkDir(root, exclude, maxDepth) {
|
|
|
25325
23129
|
}
|
|
25326
23130
|
for (const entry of entries) {
|
|
25327
23131
|
if (exclude.has(entry.name)) continue;
|
|
25328
|
-
const fullPath =
|
|
23132
|
+
const fullPath = path26.join(dir, entry.name);
|
|
25329
23133
|
if (entry.isDirectory()) {
|
|
25330
23134
|
walk(fullPath, depth + 1);
|
|
25331
23135
|
} else if (entry.isFile()) {
|
|
@@ -25340,11 +23144,11 @@ function detectLanguages(files, root) {
|
|
|
25340
23144
|
const results = [];
|
|
25341
23145
|
const extCounts = /* @__PURE__ */ new Map();
|
|
25342
23146
|
for (const f of files) {
|
|
25343
|
-
const ext =
|
|
23147
|
+
const ext = path26.extname(f).toLowerCase();
|
|
25344
23148
|
if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
25345
23149
|
}
|
|
25346
23150
|
const rootFiles = new Set(
|
|
25347
|
-
files.filter((f) =>
|
|
23151
|
+
files.filter((f) => path26.dirname(f) === root).map((f) => path26.basename(f))
|
|
25348
23152
|
);
|
|
25349
23153
|
for (const rule of LANGUAGE_RULES) {
|
|
25350
23154
|
const evidence = [];
|
|
@@ -25388,7 +23192,7 @@ function detectLanguages(files, root) {
|
|
|
25388
23192
|
}
|
|
25389
23193
|
function detectShape(files, root) {
|
|
25390
23194
|
const rootFiles = new Set(
|
|
25391
|
-
files.filter((f) =>
|
|
23195
|
+
files.filter((f) => path26.dirname(f) === root).map((f) => path26.basename(f))
|
|
25392
23196
|
);
|
|
25393
23197
|
const rootDirs = /* @__PURE__ */ new Set();
|
|
25394
23198
|
try {
|
|
@@ -25399,7 +23203,7 @@ function detectShape(files, root) {
|
|
|
25399
23203
|
}
|
|
25400
23204
|
const evidence = [];
|
|
25401
23205
|
if (rootFiles.has("package.json")) {
|
|
25402
|
-
const pkg = readJsonSafe(
|
|
23206
|
+
const pkg = readJsonSafe(path26.join(root, "package.json"));
|
|
25403
23207
|
if (pkg?.workspaces) {
|
|
25404
23208
|
evidence.push("package.json has workspaces");
|
|
25405
23209
|
return { shape: "monorepo", evidence };
|
|
@@ -25413,13 +23217,13 @@ function detectShape(files, root) {
|
|
|
25413
23217
|
evidence.push("workspace manifest found");
|
|
25414
23218
|
return { shape: "workspace", evidence };
|
|
25415
23219
|
}
|
|
25416
|
-
const cargoToml = readTomlWorkspace(
|
|
23220
|
+
const cargoToml = readTomlWorkspace(path26.join(root, "Cargo.toml"));
|
|
25417
23221
|
if (cargoToml) {
|
|
25418
23222
|
evidence.push("Cargo.toml has workspace");
|
|
25419
23223
|
return { shape: "workspace", evidence };
|
|
25420
23224
|
}
|
|
25421
23225
|
if (rootFiles.has("package.json")) {
|
|
25422
|
-
const pkg = readJsonSafe(
|
|
23226
|
+
const pkg = readJsonSafe(path26.join(root, "package.json"));
|
|
25423
23227
|
if (pkg?.exports || pkg?.main) {
|
|
25424
23228
|
if (pkg?.bin) {
|
|
25425
23229
|
evidence.push("package.json has bin");
|
|
@@ -25453,8 +23257,8 @@ function discoverDocs(files, root) {
|
|
|
25453
23257
|
{ pattern: /^\.editorconfig$/i, kind: "config" }
|
|
25454
23258
|
];
|
|
25455
23259
|
for (const filePath of files) {
|
|
25456
|
-
const basename =
|
|
25457
|
-
const relPath =
|
|
23260
|
+
const basename = path26.basename(filePath).toLowerCase();
|
|
23261
|
+
const relPath = path26.relative(root, filePath);
|
|
25458
23262
|
let kind;
|
|
25459
23263
|
for (const { pattern, kind: k } of docPatterns) {
|
|
25460
23264
|
if (pattern.test(basename)) {
|
|
@@ -25466,7 +23270,7 @@ function discoverDocs(files, root) {
|
|
|
25466
23270
|
kind = "docs";
|
|
25467
23271
|
}
|
|
25468
23272
|
if (!kind && (basename.endsWith(".md") || basename.endsWith(".mdx"))) {
|
|
25469
|
-
if (
|
|
23273
|
+
if (path26.dirname(relPath) === "." || isUnderDocsDir(relPath)) {
|
|
25470
23274
|
kind = "docs";
|
|
25471
23275
|
}
|
|
25472
23276
|
}
|
|
@@ -25487,7 +23291,7 @@ function discoverDocs(files, root) {
|
|
|
25487
23291
|
return docs;
|
|
25488
23292
|
}
|
|
25489
23293
|
function isUnderDocsDir(relPath) {
|
|
25490
|
-
const parts = relPath.split(
|
|
23294
|
+
const parts = relPath.split(path26.sep);
|
|
25491
23295
|
return parts[0] === "docs" || parts[0] === "doc" || parts[0] === "documentation";
|
|
25492
23296
|
}
|
|
25493
23297
|
function buildPlan(languages, shape, docs, _root) {
|
|
@@ -25531,7 +23335,7 @@ function readTomlWorkspace(filePath) {
|
|
|
25531
23335
|
|
|
25532
23336
|
// src/curation/index.ts
|
|
25533
23337
|
import fs3 from "fs";
|
|
25534
|
-
import
|
|
23338
|
+
import path27 from "path";
|
|
25535
23339
|
import crypto4 from "crypto";
|
|
25536
23340
|
async function curate(options) {
|
|
25537
23341
|
const startTime = Date.now();
|
|
@@ -25616,18 +23420,18 @@ async function curate(options) {
|
|
|
25616
23420
|
};
|
|
25617
23421
|
}
|
|
25618
23422
|
function resolveTargets(targetPath) {
|
|
25619
|
-
const
|
|
25620
|
-
if (
|
|
23423
|
+
const stat5 = fs3.statSync(targetPath);
|
|
23424
|
+
if (stat5.isFile()) return [targetPath];
|
|
25621
23425
|
const results = [];
|
|
25622
23426
|
const extensions = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
25623
23427
|
function walk(dir) {
|
|
25624
23428
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
25625
|
-
const fullPath =
|
|
23429
|
+
const fullPath = path27.join(dir, entry.name);
|
|
25626
23430
|
if (entry.isDirectory()) {
|
|
25627
23431
|
if (entry.name !== "node_modules" && entry.name !== ".git") {
|
|
25628
23432
|
walk(fullPath);
|
|
25629
23433
|
}
|
|
25630
|
-
} else if (extensions.has(
|
|
23434
|
+
} else if (extensions.has(path27.extname(entry.name).toLowerCase())) {
|
|
25631
23435
|
results.push(fullPath);
|
|
25632
23436
|
}
|
|
25633
23437
|
}
|
|
@@ -25636,12 +23440,12 @@ function resolveTargets(targetPath) {
|
|
|
25636
23440
|
return results;
|
|
25637
23441
|
}
|
|
25638
23442
|
function resolveProvenanceRoot(targetPath) {
|
|
25639
|
-
const resolvedTarget =
|
|
25640
|
-
const
|
|
25641
|
-
return
|
|
23443
|
+
const resolvedTarget = path27.resolve(targetPath);
|
|
23444
|
+
const stat5 = fs3.statSync(resolvedTarget);
|
|
23445
|
+
return stat5.isFile() ? path27.dirname(resolvedTarget) : resolvedTarget;
|
|
25642
23446
|
}
|
|
25643
23447
|
function extractStatements(content, filePath, projectRoot, source, sourceFileHash, categoryOverride, confidence, entityRef, tags) {
|
|
25644
|
-
const relativePath =
|
|
23448
|
+
const relativePath = path27.relative(projectRoot, path27.resolve(filePath)) || path27.basename(filePath);
|
|
25645
23449
|
const statements = [];
|
|
25646
23450
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25647
23451
|
const paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter((p) => p.length > 20 && p.length < 2e3);
|
|
@@ -25735,7 +23539,7 @@ function loadExistingMemories(memoryDir) {
|
|
|
25735
23539
|
if (!fs3.existsSync(memoryDir)) return result;
|
|
25736
23540
|
const dirs = ALL_CATEGORY_DIRS;
|
|
25737
23541
|
for (const dir of dirs) {
|
|
25738
|
-
const fullDir =
|
|
23542
|
+
const fullDir = path27.join(memoryDir, dir);
|
|
25739
23543
|
if (!fs3.existsSync(fullDir)) continue;
|
|
25740
23544
|
walkFiles(fullDir, (filePath) => {
|
|
25741
23545
|
const content = readFileSafe(filePath);
|
|
@@ -25758,11 +23562,11 @@ function writeStatement(stmt, memoryDir) {
|
|
|
25758
23562
|
const now = /* @__PURE__ */ new Date();
|
|
25759
23563
|
const dateDir = now.toISOString().split("T")[0];
|
|
25760
23564
|
const categoryDir = getCategoryDir(memoryDir, stmt.category);
|
|
25761
|
-
const dir =
|
|
23565
|
+
const dir = path27.join(categoryDir, dateDir);
|
|
25762
23566
|
fs3.mkdirSync(dir, { recursive: true });
|
|
25763
23567
|
const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;
|
|
25764
|
-
const filePath =
|
|
25765
|
-
const historicalIds = historicalIdCache2.get(
|
|
23568
|
+
const filePath = path27.join(dir, fileName);
|
|
23569
|
+
const historicalIds = historicalIdCache2.get(path27.join(memoryDir, "state"));
|
|
25766
23570
|
const rawBody = `${[
|
|
25767
23571
|
"---",
|
|
25768
23572
|
`id: ${stmt.id}`,
|
|
@@ -25785,7 +23589,7 @@ ${stmt.content}
|
|
|
25785
23589
|
fs3.writeFileSync(filePath, body);
|
|
25786
23590
|
try {
|
|
25787
23591
|
repairContentAfterJournalMoveSync({
|
|
25788
|
-
stateDir:
|
|
23592
|
+
stateDir: path27.join(memoryDir, "state"),
|
|
25789
23593
|
cache: historicalIdCache2,
|
|
25790
23594
|
idsAtWrite: historicalIds,
|
|
25791
23595
|
rawContent: rawBody,
|
|
@@ -25846,7 +23650,7 @@ function extractBody2(content) {
|
|
|
25846
23650
|
}
|
|
25847
23651
|
function walkFiles(dir, callback) {
|
|
25848
23652
|
for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
25849
|
-
const fullPath =
|
|
23653
|
+
const fullPath = path27.join(dir, entry.name);
|
|
25850
23654
|
if (entry.isDirectory()) {
|
|
25851
23655
|
walkFiles(fullPath, callback);
|
|
25852
23656
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -25858,7 +23662,7 @@ function walkFiles(dir, callback) {
|
|
|
25858
23662
|
// src/dedup/index.ts
|
|
25859
23663
|
import crypto5 from "crypto";
|
|
25860
23664
|
import fs4 from "fs";
|
|
25861
|
-
import
|
|
23665
|
+
import path28 from "path";
|
|
25862
23666
|
var DEFAULT_DEDUP_THRESHOLD = 0.85;
|
|
25863
23667
|
var DEFAULT_MAX_LOAD = 1e4;
|
|
25864
23668
|
function normalizeThreshold(value, defaultValue) {
|
|
@@ -26052,7 +23856,7 @@ function loadMemories(memoryDir, categories, maxLoad = 1e4) {
|
|
|
26052
23856
|
const memoryRootReal = fs4.realpathSync(memoryDir);
|
|
26053
23857
|
for (const category of allCategories) {
|
|
26054
23858
|
if (result.length >= maxLoad) break;
|
|
26055
|
-
const dir =
|
|
23859
|
+
const dir = path28.join(memoryDir, category);
|
|
26056
23860
|
if (!fs4.existsSync(dir)) continue;
|
|
26057
23861
|
const categoryStat = fs4.lstatSync(dir);
|
|
26058
23862
|
if (categoryStat.isSymbolicLink()) {
|
|
@@ -26113,15 +23917,15 @@ function extractBody3(content) {
|
|
|
26113
23917
|
return match ? match[1].trim() : content.trim();
|
|
26114
23918
|
}
|
|
26115
23919
|
function assertPathInsideRoot2(rootReal, targetReal, sourcePath) {
|
|
26116
|
-
const rel =
|
|
26117
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
23920
|
+
const rel = path28.relative(rootReal, targetReal);
|
|
23921
|
+
if (rel === "" || !rel.startsWith("..") && !path28.isAbsolute(rel)) {
|
|
26118
23922
|
return;
|
|
26119
23923
|
}
|
|
26120
23924
|
throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);
|
|
26121
23925
|
}
|
|
26122
23926
|
function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
26123
23927
|
for (const entry of fs4.readdirSync(dir, { withFileTypes: true })) {
|
|
26124
|
-
const fullPath =
|
|
23928
|
+
const fullPath = path28.join(dir, entry.name);
|
|
26125
23929
|
const entryStat = fs4.lstatSync(fullPath);
|
|
26126
23930
|
if (entryStat.isSymbolicLink()) {
|
|
26127
23931
|
throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);
|
|
@@ -26139,10 +23943,10 @@ function walkMdFiles(dir, memoryRootReal, categoryRootReal, callback) {
|
|
|
26139
23943
|
|
|
26140
23944
|
// src/review/index.ts
|
|
26141
23945
|
import fs5 from "fs";
|
|
26142
|
-
import
|
|
23946
|
+
import path29 from "path";
|
|
26143
23947
|
var historicalIdCache3 = new HistoricalEntityCanonicalIdCache();
|
|
26144
23948
|
function writeReviewFileCanonicalized(memoryDir, filePath, content) {
|
|
26145
|
-
const stateDir =
|
|
23949
|
+
const stateDir = path29.join(memoryDir, "state");
|
|
26146
23950
|
const idsAtWrite = historicalIdCache3.get(stateDir);
|
|
26147
23951
|
let originalBytes = null;
|
|
26148
23952
|
try {
|
|
@@ -26176,21 +23980,21 @@ function writeReviewFileCanonicalized(memoryDir, filePath, content) {
|
|
|
26176
23980
|
var DEFAULT_CONFIDENCE_THRESHOLD = 0.7;
|
|
26177
23981
|
function realMemoryRoot(memoryDir) {
|
|
26178
23982
|
try {
|
|
26179
|
-
const
|
|
26180
|
-
if (!
|
|
23983
|
+
const stat5 = fs5.lstatSync(memoryDir);
|
|
23984
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) return null;
|
|
26181
23985
|
return fs5.realpathSync(memoryDir);
|
|
26182
23986
|
} catch {
|
|
26183
23987
|
return null;
|
|
26184
23988
|
}
|
|
26185
23989
|
}
|
|
26186
23990
|
function isPathInside2(rootReal, candidateReal) {
|
|
26187
|
-
const relative =
|
|
26188
|
-
return relative === "" || !!relative && !relative.startsWith("..") && !
|
|
23991
|
+
const relative = path29.relative(rootReal, candidateReal);
|
|
23992
|
+
return relative === "" || !!relative && !relative.startsWith("..") && !path29.isAbsolute(relative);
|
|
26189
23993
|
}
|
|
26190
23994
|
function isSafeDirectory(rootReal, dir) {
|
|
26191
23995
|
try {
|
|
26192
|
-
const
|
|
26193
|
-
if (!
|
|
23996
|
+
const stat5 = fs5.lstatSync(dir);
|
|
23997
|
+
if (!stat5.isDirectory() || stat5.isSymbolicLink()) return false;
|
|
26194
23998
|
return isPathInside2(rootReal, fs5.realpathSync(dir));
|
|
26195
23999
|
} catch {
|
|
26196
24000
|
return false;
|
|
@@ -26228,7 +24032,7 @@ function listReviewItems(options) {
|
|
|
26228
24032
|
if (filterReason && item.reviewReason !== filterReason) return;
|
|
26229
24033
|
items.push(item);
|
|
26230
24034
|
};
|
|
26231
|
-
const suggestionsDir =
|
|
24035
|
+
const suggestionsDir = path29.join(memoryDir, "suggestions");
|
|
26232
24036
|
if (!isLimitReached() && fs5.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {
|
|
26233
24037
|
walkMd(rootReal, suggestionsDir, (filePath, content) => {
|
|
26234
24038
|
if (isLimitReached()) return true;
|
|
@@ -26249,7 +24053,7 @@ function listReviewItems(options) {
|
|
|
26249
24053
|
return isLimitReached();
|
|
26250
24054
|
});
|
|
26251
24055
|
}
|
|
26252
|
-
const reviewDir =
|
|
24056
|
+
const reviewDir = path29.join(memoryDir, "review");
|
|
26253
24057
|
if (!isLimitReached() && fs5.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {
|
|
26254
24058
|
walkMd(rootReal, reviewDir, (filePath, content) => {
|
|
26255
24059
|
if (isLimitReached()) return true;
|
|
@@ -26274,7 +24078,7 @@ function listReviewItems(options) {
|
|
|
26274
24078
|
const categories = ALL_CATEGORY_DIRS;
|
|
26275
24079
|
for (const category of categories) {
|
|
26276
24080
|
if (isLimitReached()) break;
|
|
26277
|
-
const dir =
|
|
24081
|
+
const dir = path29.join(memoryDir, category);
|
|
26278
24082
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
26279
24083
|
walkMd(rootReal, dir, (filePath, content) => {
|
|
26280
24084
|
if (isLimitReached()) return true;
|
|
@@ -26356,9 +24160,9 @@ function approveItem(memoryDir, itemId, options) {
|
|
|
26356
24160
|
const targetDir = getCategoryDir(memoryDir, category);
|
|
26357
24161
|
const dateDir = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
26358
24162
|
ensureSafeDirectory(rootReal, targetDir);
|
|
26359
|
-
const outputPath =
|
|
26360
|
-
ensureSafeDirectory(rootReal,
|
|
26361
|
-
const reviewStateDir =
|
|
24163
|
+
const outputPath = path29.join(targetDir, dateDir, path29.basename(found.filePath));
|
|
24164
|
+
ensureSafeDirectory(rootReal, path29.dirname(outputPath));
|
|
24165
|
+
const reviewStateDir = path29.join(memoryDir, "state");
|
|
26362
24166
|
const idsAtWrite = historicalIdCache3.get(reviewStateDir);
|
|
26363
24167
|
const promotedWritten = canonicalizeEntityRefFrontmatter(updatedContent, idsAtWrite);
|
|
26364
24168
|
const promotedPath = writeFileWithoutClobber(outputPath, promotedWritten, itemId);
|
|
@@ -26435,13 +24239,13 @@ function findReviewFileById(memoryDir, id, options = {}) {
|
|
|
26435
24239
|
const rootReal = realMemoryRoot(memoryDir);
|
|
26436
24240
|
if (!rootReal) return null;
|
|
26437
24241
|
for (const loc of ["suggestions", "review"]) {
|
|
26438
|
-
const dir =
|
|
24242
|
+
const dir = path29.join(memoryDir, loc);
|
|
26439
24243
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
26440
24244
|
const found = findFileById(rootReal, dir, id);
|
|
26441
24245
|
if (found) return { filePath: found, location: "queue" };
|
|
26442
24246
|
}
|
|
26443
24247
|
for (const category of ALL_CATEGORY_DIRS) {
|
|
26444
|
-
const dir =
|
|
24248
|
+
const dir = path29.join(memoryDir, category);
|
|
26445
24249
|
if (!fs5.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;
|
|
26446
24250
|
const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));
|
|
26447
24251
|
if (found) return { filePath: found, location: "category" };
|
|
@@ -26517,10 +24321,10 @@ function readFileSafe3(filePath) {
|
|
|
26517
24321
|
}
|
|
26518
24322
|
}
|
|
26519
24323
|
function writeFileWithoutClobber(basePath, content, discriminator) {
|
|
26520
|
-
const parsed =
|
|
24324
|
+
const parsed = path29.parse(basePath);
|
|
26521
24325
|
const safeDiscriminator = sanitizeFilePart(discriminator);
|
|
26522
24326
|
for (let attempt = 0; attempt < 1e3; attempt++) {
|
|
26523
|
-
const candidate = attempt === 0 ? basePath :
|
|
24327
|
+
const candidate = attempt === 0 ? basePath : path29.join(
|
|
26524
24328
|
parsed.dir,
|
|
26525
24329
|
`${parsed.name}-${safeDiscriminator}${attempt === 1 ? "" : `-${attempt}`}${parsed.ext || ".md"}`
|
|
26526
24330
|
);
|
|
@@ -26576,7 +24380,7 @@ function extractBody4(content) {
|
|
|
26576
24380
|
function walkMd(rootReal, dir, callback) {
|
|
26577
24381
|
if (!isSafeDirectory(rootReal, dir)) return false;
|
|
26578
24382
|
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
26579
|
-
const fullPath =
|
|
24383
|
+
const fullPath = path29.join(dir, entry.name);
|
|
26580
24384
|
if (entry.isSymbolicLink()) continue;
|
|
26581
24385
|
if (entry.isDirectory()) {
|
|
26582
24386
|
if (walkMd(rootReal, fullPath, callback)) return true;
|
|
@@ -26591,7 +24395,7 @@ function walkMdPaths(rootReal, dir) {
|
|
|
26591
24395
|
const results = [];
|
|
26592
24396
|
if (!isSafeDirectory(rootReal, dir)) return results;
|
|
26593
24397
|
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
26594
|
-
const fullPath =
|
|
24398
|
+
const fullPath = path29.join(dir, entry.name);
|
|
26595
24399
|
if (entry.isSymbolicLink()) continue;
|
|
26596
24400
|
if (entry.isDirectory()) {
|
|
26597
24401
|
results.push(...walkMdPaths(rootReal, fullPath));
|
|
@@ -26604,7 +24408,7 @@ function walkMdPaths(rootReal, dir) {
|
|
|
26604
24408
|
|
|
26605
24409
|
// src/sync/index.ts
|
|
26606
24410
|
import fs6 from "fs";
|
|
26607
|
-
import
|
|
24411
|
+
import path30 from "path";
|
|
26608
24412
|
import crypto6 from "crypto";
|
|
26609
24413
|
var DEFAULT_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".mdx", ".rst"]);
|
|
26610
24414
|
var DEFAULT_EXCLUDE2 = /* @__PURE__ */ new Set([
|
|
@@ -26626,7 +24430,7 @@ function syncChanges(options) {
|
|
|
26626
24430
|
} = options;
|
|
26627
24431
|
const extSet = new Set(extensions);
|
|
26628
24432
|
const excludeSet = /* @__PURE__ */ new Set([...DEFAULT_EXCLUDE2, ...excludeDirs]);
|
|
26629
|
-
const stateFilePath = options.stateFile ??
|
|
24433
|
+
const stateFilePath = options.stateFile ?? path30.join(memoryDir, ".sync-state.json");
|
|
26630
24434
|
const prevState = loadState(stateFilePath);
|
|
26631
24435
|
const currentFiles = scanFiles(sourceDir, extSet, excludeSet);
|
|
26632
24436
|
const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);
|
|
@@ -26642,7 +24446,7 @@ function syncChanges(options) {
|
|
|
26642
24446
|
for (const [relPath, hash] of Object.entries(currentFiles)) {
|
|
26643
24447
|
newState.fileHashes[relPath] = hash;
|
|
26644
24448
|
}
|
|
26645
|
-
fs6.mkdirSync(
|
|
24449
|
+
fs6.mkdirSync(path30.dirname(stateFilePath), { recursive: true });
|
|
26646
24450
|
fs6.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));
|
|
26647
24451
|
}
|
|
26648
24452
|
return {
|
|
@@ -26708,13 +24512,13 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26708
24512
|
}
|
|
26709
24513
|
for (const entry of entries) {
|
|
26710
24514
|
if (exclude.has(entry.name)) continue;
|
|
26711
|
-
const fullPath =
|
|
24515
|
+
const fullPath = path30.join(dir, entry.name);
|
|
26712
24516
|
if (entry.isDirectory()) {
|
|
26713
24517
|
walk(fullPath);
|
|
26714
24518
|
} else if (entry.isFile()) {
|
|
26715
|
-
const ext =
|
|
24519
|
+
const ext = path30.extname(entry.name).toLowerCase();
|
|
26716
24520
|
if (!extensions.has(ext)) continue;
|
|
26717
|
-
const relPath =
|
|
24521
|
+
const relPath = path30.relative(root, fullPath);
|
|
26718
24522
|
try {
|
|
26719
24523
|
const content = fs6.readFileSync(fullPath, "utf8");
|
|
26720
24524
|
result[relPath] = hashContent3(content);
|
|
@@ -26729,7 +24533,7 @@ function scanFiles(root, extensions, exclude) {
|
|
|
26729
24533
|
function computeDiff(current, previous, sourceDir) {
|
|
26730
24534
|
const changes = [];
|
|
26731
24535
|
for (const [relPath, hash] of Object.entries(current)) {
|
|
26732
|
-
const fullPath =
|
|
24536
|
+
const fullPath = path30.join(sourceDir, relPath);
|
|
26733
24537
|
if (!(relPath in previous)) {
|
|
26734
24538
|
let size = 0;
|
|
26735
24539
|
try {
|
|
@@ -26762,7 +24566,7 @@ function computeDiff(current, previous, sourceDir) {
|
|
|
26762
24566
|
for (const relPath of Object.keys(previous)) {
|
|
26763
24567
|
if (!(relPath in current)) {
|
|
26764
24568
|
changes.push({
|
|
26765
|
-
filePath:
|
|
24569
|
+
filePath: path30.join(sourceDir, relPath),
|
|
26766
24570
|
relativePath: relPath,
|
|
26767
24571
|
type: "deleted",
|
|
26768
24572
|
currentHash: "",
|
|
@@ -26792,21 +24596,21 @@ function hashContent3(content) {
|
|
|
26792
24596
|
import { spawnSync } from "child_process";
|
|
26793
24597
|
import crypto7 from "crypto";
|
|
26794
24598
|
import fs7 from "fs";
|
|
26795
|
-
import
|
|
24599
|
+
import path31 from "path";
|
|
26796
24600
|
var historicalIdCache4 = new HistoricalEntityCanonicalIdCache();
|
|
26797
24601
|
var MANIFEST_VERSION = 1;
|
|
26798
24602
|
var MANIFEST_LOCK_STALE_MS = 3e4;
|
|
26799
24603
|
var MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 1e4;
|
|
26800
24604
|
var MANIFEST_LOCK_SLEEP_MS = 20;
|
|
26801
24605
|
function normalizeSpaceMemoryDir(memoryDir) {
|
|
26802
|
-
return
|
|
24606
|
+
return path31.resolve(memoryDir);
|
|
26803
24607
|
}
|
|
26804
24608
|
function getSpacesDir(baseDir) {
|
|
26805
24609
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
26806
|
-
return
|
|
24610
|
+
return path31.join(homeDir, ".config", "engram", "spaces");
|
|
26807
24611
|
}
|
|
26808
24612
|
function getManifestPath(baseDir) {
|
|
26809
|
-
return
|
|
24613
|
+
return path31.join(getSpacesDir(baseDir), "manifest.json");
|
|
26810
24614
|
}
|
|
26811
24615
|
function loadManifest(baseDir, memoryDirOverride) {
|
|
26812
24616
|
if (fs7.existsSync(getManifestPath(baseDir))) {
|
|
@@ -26853,9 +24657,9 @@ function readManifestUnlocked(baseDir, memoryDirOverride, options = {}) {
|
|
|
26853
24657
|
}
|
|
26854
24658
|
function saveManifestUnlocked(manifest, baseDir) {
|
|
26855
24659
|
const manifestPath2 = getManifestPath(baseDir);
|
|
26856
|
-
const manifestDir2 =
|
|
24660
|
+
const manifestDir2 = path31.dirname(manifestPath2);
|
|
26857
24661
|
fs7.mkdirSync(manifestDir2, { recursive: true });
|
|
26858
|
-
const tempPath =
|
|
24662
|
+
const tempPath = path31.join(manifestDir2, `.manifest.${process.pid}.${Date.now()}.${crypto7.randomUUID()}.tmp`);
|
|
26859
24663
|
try {
|
|
26860
24664
|
fs7.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}
|
|
26861
24665
|
`, { flag: "wx" });
|
|
@@ -26870,7 +24674,7 @@ function saveManifestUnlocked(manifest, baseDir) {
|
|
|
26870
24674
|
}
|
|
26871
24675
|
function withManifestLock(baseDir, operation) {
|
|
26872
24676
|
const lockDir = `${getManifestPath(baseDir)}.lock`;
|
|
26873
|
-
fs7.mkdirSync(
|
|
24677
|
+
fs7.mkdirSync(path31.dirname(lockDir), { recursive: true });
|
|
26874
24678
|
const lockOwner = acquireManifestLock(lockDir);
|
|
26875
24679
|
try {
|
|
26876
24680
|
return operation();
|
|
@@ -26896,7 +24700,7 @@ function acquireManifestLock(lockDir) {
|
|
|
26896
24700
|
try {
|
|
26897
24701
|
fs7.mkdirSync(lockDir, { recursive: false });
|
|
26898
24702
|
try {
|
|
26899
|
-
fs7.writeFileSync(
|
|
24703
|
+
fs7.writeFileSync(path31.join(lockDir, "owner"), `${owner}
|
|
26900
24704
|
`, { flag: "wx" });
|
|
26901
24705
|
} catch (error) {
|
|
26902
24706
|
fs7.rmSync(lockDir, { recursive: true, force: true });
|
|
@@ -26926,7 +24730,7 @@ function acquireManifestLock(lockDir) {
|
|
|
26926
24730
|
}
|
|
26927
24731
|
function releaseManifestLock(lockDir, owner) {
|
|
26928
24732
|
try {
|
|
26929
|
-
const ownerPath =
|
|
24733
|
+
const ownerPath = path31.join(lockDir, "owner");
|
|
26930
24734
|
if (fs7.readFileSync(ownerPath, "utf8").trim() === owner) {
|
|
26931
24735
|
fs7.rmSync(lockDir, { recursive: true, force: true });
|
|
26932
24736
|
}
|
|
@@ -26942,7 +24746,7 @@ function removeStaleManifestLock(lockDir) {
|
|
|
26942
24746
|
try {
|
|
26943
24747
|
fs7.mkdirSync(reclaimDir, { recursive: false });
|
|
26944
24748
|
try {
|
|
26945
|
-
fs7.writeFileSync(
|
|
24749
|
+
fs7.writeFileSync(path31.join(reclaimDir, "owner"), `${reclaimOwner}
|
|
26946
24750
|
`, { flag: "wx" });
|
|
26947
24751
|
} catch (error) {
|
|
26948
24752
|
fs7.rmSync(reclaimDir, { recursive: true, force: true });
|
|
@@ -27007,9 +24811,9 @@ function removeStaleManifestReclaimLock(reclaimDir) {
|
|
|
27007
24811
|
fs7.rmSync(tombstoneDir, { recursive: true, force: true });
|
|
27008
24812
|
}
|
|
27009
24813
|
function readManifestLockSnapshot(lockDir) {
|
|
27010
|
-
let
|
|
24814
|
+
let stat5;
|
|
27011
24815
|
try {
|
|
27012
|
-
|
|
24816
|
+
stat5 = fs7.statSync(lockDir);
|
|
27013
24817
|
} catch (error) {
|
|
27014
24818
|
if (error.code === "ENOENT") {
|
|
27015
24819
|
return void 0;
|
|
@@ -27017,11 +24821,11 @@ function readManifestLockSnapshot(lockDir) {
|
|
|
27017
24821
|
throw error;
|
|
27018
24822
|
}
|
|
27019
24823
|
try {
|
|
27020
|
-
const owner = fs7.readFileSync(
|
|
27021
|
-
return { mtimeMs:
|
|
24824
|
+
const owner = fs7.readFileSync(path31.join(lockDir, "owner"), "utf8").trim();
|
|
24825
|
+
return { mtimeMs: stat5.mtimeMs, owner };
|
|
27022
24826
|
} catch (error) {
|
|
27023
24827
|
if (error.code === "ENOENT") {
|
|
27024
|
-
return { mtimeMs:
|
|
24828
|
+
return { mtimeMs: stat5.mtimeMs };
|
|
27025
24829
|
}
|
|
27026
24830
|
throw error;
|
|
27027
24831
|
}
|
|
@@ -27089,8 +24893,8 @@ function sleepSync(ms) {
|
|
|
27089
24893
|
}
|
|
27090
24894
|
function createPersonalSpace(baseDir, memoryDirOverride) {
|
|
27091
24895
|
const homeDir = baseDir ?? resolveHomeDir();
|
|
27092
|
-
const standalonePath =
|
|
27093
|
-
const openclawPath =
|
|
24896
|
+
const standalonePath = path31.join(homeDir, ".engram", "memory");
|
|
24897
|
+
const openclawPath = path31.join(homeDir, ".openclaw", "workspace", "memory", "local");
|
|
27094
24898
|
const memoryDir = memoryDirOverride ?? readEnvVar("REMNIC_MEMORY_DIR") ?? readEnvVar("ENGRAM_MEMORY_DIR") ?? (fs7.existsSync(standalonePath) ? standalonePath : fs7.existsSync(openclawPath) ? openclawPath : standalonePath);
|
|
27095
24899
|
const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);
|
|
27096
24900
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27119,7 +24923,7 @@ function createSpace(options) {
|
|
|
27119
24923
|
const id = options.name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
27120
24924
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
27121
24925
|
const memoryDir = normalizeSpaceMemoryDir(
|
|
27122
|
-
options.memoryDir ??
|
|
24926
|
+
options.memoryDir ?? path31.join(getSpacesDir(options.baseDir), id, "memory")
|
|
27123
24927
|
);
|
|
27124
24928
|
const space = updateManifest(options.baseDir, (manifest) => {
|
|
27125
24929
|
if (manifest.spaces.some((s) => s.id === id)) {
|
|
@@ -27340,14 +25144,14 @@ async function mergeSpaces(sourceSpaceId, targetSpaceId, options) {
|
|
|
27340
25144
|
};
|
|
27341
25145
|
}
|
|
27342
25146
|
function getAuditLog(baseDir) {
|
|
27343
|
-
const auditPath =
|
|
25147
|
+
const auditPath = path31.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
27344
25148
|
if (!fs7.existsSync(auditPath)) return [];
|
|
27345
25149
|
const lines = fs7.readFileSync(auditPath, "utf8").trim().split("\n");
|
|
27346
25150
|
return lines.filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
27347
25151
|
}
|
|
27348
25152
|
function appendAudit(entry, baseDir) {
|
|
27349
|
-
const auditPath =
|
|
27350
|
-
fs7.mkdirSync(
|
|
25153
|
+
const auditPath = path31.join(getSpacesDir(baseDir), "audit.jsonl");
|
|
25154
|
+
fs7.mkdirSync(path31.dirname(auditPath), { recursive: true });
|
|
27351
25155
|
const full = {
|
|
27352
25156
|
id: crypto7.randomUUID(),
|
|
27353
25157
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -27368,11 +25172,11 @@ async function copyMemories(sourceDir, targetDir, options) {
|
|
|
27368
25172
|
sourceFiles.filter((p) => {
|
|
27369
25173
|
const rp = safeRealpath(p);
|
|
27370
25174
|
if (!rp || !isPathInsideRoot(rp, sourceRoot)) return false;
|
|
27371
|
-
const rel =
|
|
27372
|
-
const mapped =
|
|
25175
|
+
const rel = path31.relative(sourceRoot, rp);
|
|
25176
|
+
const mapped = path31.resolve(targetRoot, rel);
|
|
27373
25177
|
if (!isPathInsideRoot(mapped, targetRoot)) return false;
|
|
27374
25178
|
return classifyEntityRefWritePath(targetRoot, mapped) === "entity";
|
|
27375
|
-
}).map((p) =>
|
|
25179
|
+
}).map((p) => path31.basename(p, ".md"))
|
|
27376
25180
|
);
|
|
27377
25181
|
const firstEntityId = sourceEntityIds.values().next().value;
|
|
27378
25182
|
if (firstEntityId === void 0) {
|
|
@@ -27380,7 +25184,7 @@ async function copyMemories(sourceDir, targetDir, options) {
|
|
|
27380
25184
|
}
|
|
27381
25185
|
return withRawEntityPageMutation(
|
|
27382
25186
|
targetRoot,
|
|
27383
|
-
|
|
25187
|
+
path31.join(targetRoot, "entities", `${firstEntityId}.md`),
|
|
27384
25188
|
async () => copyPreparedMemories(
|
|
27385
25189
|
sourceFiles,
|
|
27386
25190
|
sourceRoot,
|
|
@@ -27407,14 +25211,14 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27407
25211
|
continue;
|
|
27408
25212
|
}
|
|
27409
25213
|
const content = fs7.readFileSync(sourcePath, "utf8");
|
|
27410
|
-
const relativePath =
|
|
27411
|
-
const targetPath =
|
|
25214
|
+
const relativePath = path31.relative(sourceRoot, sourceRealPath);
|
|
25215
|
+
const targetPath = path31.resolve(targetRoot, relativePath);
|
|
27412
25216
|
if (!isPathInsideRoot(targetPath, targetRoot)) {
|
|
27413
25217
|
skipped++;
|
|
27414
25218
|
continue;
|
|
27415
25219
|
}
|
|
27416
25220
|
const targetKind = classifyEntityRefWritePath(targetRoot, targetPath);
|
|
27417
|
-
const idsAtCompare = historicalIdCache4.get(
|
|
25221
|
+
const idsAtCompare = historicalIdCache4.get(path31.join(targetRoot, "state"));
|
|
27418
25222
|
const sourceRef = targetKind === "memory" ? readEntityRefFromFrontmatter(content) : null;
|
|
27419
25223
|
const refHasSourceClaimant = sourceRef !== null && sourceEntityIds.has(sourceRef);
|
|
27420
25224
|
const canonicalContent = targetKind === "memory" && !refHasSourceClaimant ? canonicalizeEntityRefFrontmatter(content, idsAtCompare) : content;
|
|
@@ -27441,7 +25245,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27441
25245
|
if (fs7.existsSync(targetPath) && !options?.force) {
|
|
27442
25246
|
const targetContent = fs7.readFileSync(targetPath, "utf8");
|
|
27443
25247
|
const targetHash = hashContent4(targetContent);
|
|
27444
|
-
if (hashContent4(canonicalContent) === targetHash && historicalIdCache4.get(
|
|
25248
|
+
if (hashContent4(canonicalContent) === targetHash && historicalIdCache4.get(path31.join(targetRoot, "state")) === idsAtCompare) {
|
|
27445
25249
|
skipped++;
|
|
27446
25250
|
continue;
|
|
27447
25251
|
}
|
|
@@ -27457,13 +25261,13 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27457
25261
|
continue;
|
|
27458
25262
|
}
|
|
27459
25263
|
}
|
|
27460
|
-
fs7.mkdirSync(
|
|
27461
|
-
const targetParentRealPath = safeRealpath(
|
|
25264
|
+
fs7.mkdirSync(path31.dirname(targetPath), { recursive: true });
|
|
25265
|
+
const targetParentRealPath = safeRealpath(path31.dirname(targetPath));
|
|
27462
25266
|
if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {
|
|
27463
25267
|
skipped++;
|
|
27464
25268
|
continue;
|
|
27465
25269
|
}
|
|
27466
|
-
const stateDir =
|
|
25270
|
+
const stateDir = path31.join(targetRoot, "state");
|
|
27467
25271
|
if (targetKind === "memory" && !refHasSourceClaimant) {
|
|
27468
25272
|
const idsAtWrite = historicalIdCache4.get(stateDir);
|
|
27469
25273
|
const written = canonicalizeEntityRefFrontmatter(content, idsAtWrite);
|
|
@@ -27507,7 +25311,7 @@ function copyPreparedMemories(sourceFiles, sourceRoot, targetRoot, sourceEntityI
|
|
|
27507
25311
|
bumpMemoryCorpusVersionForDir(targetRoot);
|
|
27508
25312
|
}
|
|
27509
25313
|
if (reconcileNeeded) {
|
|
27510
|
-
requestEntityCanonicalIdReconcileSync(
|
|
25314
|
+
requestEntityCanonicalIdReconcileSync(path31.join(targetRoot, "state"));
|
|
27511
25315
|
}
|
|
27512
25316
|
return { merged, conflicts, skipped };
|
|
27513
25317
|
}
|
|
@@ -27518,7 +25322,7 @@ function walkMd2(dir) {
|
|
|
27518
25322
|
const results = [];
|
|
27519
25323
|
function walk(d) {
|
|
27520
25324
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
27521
|
-
const fullPath =
|
|
25325
|
+
const fullPath = path31.join(d, entry.name);
|
|
27522
25326
|
if (entry.isSymbolicLink()) {
|
|
27523
25327
|
continue;
|
|
27524
25328
|
}
|
|
@@ -27547,8 +25351,8 @@ function safeRealpath(filePath) {
|
|
|
27547
25351
|
}
|
|
27548
25352
|
}
|
|
27549
25353
|
function isPathInsideRoot(candidatePath, rootPath) {
|
|
27550
|
-
const relative =
|
|
27551
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
25354
|
+
const relative = path31.relative(rootPath, candidatePath);
|
|
25355
|
+
return relative === "" || !relative.startsWith("..") && !path31.isAbsolute(relative);
|
|
27552
25356
|
}
|
|
27553
25357
|
function parseSimpleFrontmatter(content) {
|
|
27554
25358
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -27669,7 +25473,7 @@ var REMNIC_RECALL_DECISION_RULES = `## When to Use Recall vs Direct Read
|
|
|
27669
25473
|
// src/memory-extension/codex-publisher.ts
|
|
27670
25474
|
import fs8 from "fs";
|
|
27671
25475
|
import os from "os";
|
|
27672
|
-
import
|
|
25476
|
+
import path32 from "path";
|
|
27673
25477
|
var REMNIC_EXTENSION_DIR_NAME = "remnic";
|
|
27674
25478
|
function resolveEnvHome(env) {
|
|
27675
25479
|
if (env === void 0) return resolveHomeDir();
|
|
@@ -27678,12 +25482,12 @@ function resolveEnvHome(env) {
|
|
|
27678
25482
|
function expandTildeWithHome(input, homeDir) {
|
|
27679
25483
|
if (input === "~") return homeDir;
|
|
27680
25484
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
27681
|
-
return
|
|
25485
|
+
return path32.join(homeDir, input.slice(2));
|
|
27682
25486
|
}
|
|
27683
25487
|
return input;
|
|
27684
25488
|
}
|
|
27685
25489
|
function normalizeHostRoot(input, homeDir) {
|
|
27686
|
-
return
|
|
25490
|
+
return path32.resolve(expandTildeWithHome(input.trim(), homeDir));
|
|
27687
25491
|
}
|
|
27688
25492
|
var CodexMemoryExtensionPublisher = class {
|
|
27689
25493
|
hostId = "codex";
|
|
@@ -27697,12 +25501,12 @@ var CodexMemoryExtensionPublisher = class {
|
|
|
27697
25501
|
async resolveExtensionRoot(env) {
|
|
27698
25502
|
const homeDir = resolveEnvHome(env);
|
|
27699
25503
|
const codexHomeInput = env === void 0 ? readEnvVar("CODEX_HOME")?.trim() : env.CODEX_HOME?.trim();
|
|
27700
|
-
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) :
|
|
27701
|
-
return
|
|
25504
|
+
const codexHome = codexHomeInput ? normalizeHostRoot(codexHomeInput, homeDir) : path32.resolve(homeDir, ".codex");
|
|
25505
|
+
return path32.join(codexHome, "memories_extensions", REMNIC_EXTENSION_DIR_NAME);
|
|
27702
25506
|
}
|
|
27703
25507
|
async isHostAvailable() {
|
|
27704
25508
|
try {
|
|
27705
|
-
const home = readEnvVar("CODEX_HOME")?.trim() ||
|
|
25509
|
+
const home = readEnvVar("CODEX_HOME")?.trim() || path32.join(resolveHomeDir(), ".codex");
|
|
27706
25510
|
return fs8.existsSync(home);
|
|
27707
25511
|
} catch {
|
|
27708
25512
|
return false;
|
|
@@ -27753,7 +25557,7 @@ When running inside the Codex phase-2 consolidation sandbox:
|
|
|
27753
25557
|
}
|
|
27754
25558
|
async publish(ctx) {
|
|
27755
25559
|
const extensionRoot = await this.resolveExtensionRoot();
|
|
27756
|
-
const instructionsPath =
|
|
25560
|
+
const instructionsPath = path32.join(extensionRoot, "instructions.md");
|
|
27757
25561
|
const filesWritten = [];
|
|
27758
25562
|
const skipped = [];
|
|
27759
25563
|
ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);
|
|
@@ -28127,9 +25931,9 @@ async function generateActivityMemories(date, digestBody, config, deps) {
|
|
|
28127
25931
|
}
|
|
28128
25932
|
|
|
28129
25933
|
// src/session-summaries/index.ts
|
|
28130
|
-
import { createHash as
|
|
28131
|
-
import { lstat as
|
|
28132
|
-
import
|
|
25934
|
+
import { createHash as createHash9 } from "crypto";
|
|
25935
|
+
import { lstat as lstat3, mkdir as mkdir7, readFile as readFile7, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
25936
|
+
import path33 from "path";
|
|
28133
25937
|
|
|
28134
25938
|
// src/session-summaries/adapters.ts
|
|
28135
25939
|
var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
|
|
@@ -28629,28 +26433,28 @@ var DEFAULT_MAX_FILES = 5e3;
|
|
|
28629
26433
|
var DEFAULT_MAX_SESSIONS = 500;
|
|
28630
26434
|
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".jsonl"]);
|
|
28631
26435
|
function shortHash(value, length = 16) {
|
|
28632
|
-
return
|
|
26436
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
28633
26437
|
}
|
|
28634
26438
|
async function listTranscriptFiles(root, maxFiles) {
|
|
28635
26439
|
const out = [];
|
|
28636
26440
|
let truncated = false;
|
|
28637
|
-
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${
|
|
26441
|
+
const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path33.sep}` : entryName;
|
|
28638
26442
|
async function visit(dir) {
|
|
28639
26443
|
if (truncated) return;
|
|
28640
|
-
const entries = (await
|
|
26444
|
+
const entries = (await readdir4(dir, { withFileTypes: true })).sort(
|
|
28641
26445
|
(a, b) => entrySortKey(a.name, a.isDirectory()).localeCompare(entrySortKey(b.name, b.isDirectory()))
|
|
28642
26446
|
);
|
|
28643
26447
|
for (const entry of entries) {
|
|
28644
26448
|
if (truncated) return;
|
|
28645
26449
|
if (entry.name.startsWith(".")) continue;
|
|
28646
26450
|
if (entry.isSymbolicLink()) continue;
|
|
28647
|
-
const fullPath =
|
|
26451
|
+
const fullPath = path33.join(dir, entry.name);
|
|
28648
26452
|
if (entry.isDirectory()) {
|
|
28649
26453
|
await visit(fullPath);
|
|
28650
26454
|
continue;
|
|
28651
26455
|
}
|
|
28652
26456
|
if (!entry.isFile()) continue;
|
|
28653
|
-
const ext =
|
|
26457
|
+
const ext = path33.extname(entry.name).toLowerCase();
|
|
28654
26458
|
if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
|
|
28655
26459
|
out.push(fullPath);
|
|
28656
26460
|
if (out.length > maxFiles) {
|
|
@@ -28677,7 +26481,7 @@ function normalizeInputDir(inputDir) {
|
|
|
28677
26481
|
if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
|
|
28678
26482
|
throw new Error("inputDir must be a non-empty string");
|
|
28679
26483
|
}
|
|
28680
|
-
return
|
|
26484
|
+
return path33.resolve(expandTildePath(inputDir.trim()));
|
|
28681
26485
|
}
|
|
28682
26486
|
function initRoleCounts() {
|
|
28683
26487
|
return {
|
|
@@ -28772,11 +26576,11 @@ function buildDraft(options) {
|
|
|
28772
26576
|
}
|
|
28773
26577
|
async function collectLocalSessionSummaries(options) {
|
|
28774
26578
|
const inputDir = normalizeInputDir(options.inputDir);
|
|
28775
|
-
const inputLstat = await
|
|
26579
|
+
const inputLstat = await lstat3(inputDir);
|
|
28776
26580
|
if (inputLstat.isSymbolicLink()) {
|
|
28777
26581
|
throw new Error(`inputDir must not be a symbolic link: ${options.inputDir}`);
|
|
28778
26582
|
}
|
|
28779
|
-
const inputStat = await
|
|
26583
|
+
const inputStat = await stat4(inputDir);
|
|
28780
26584
|
if (!inputStat.isDirectory()) {
|
|
28781
26585
|
throw new Error(`inputDir must be a directory: ${options.inputDir}`);
|
|
28782
26586
|
}
|
|
@@ -28834,11 +26638,11 @@ async function collectLocalSessionSummaries(options) {
|
|
|
28834
26638
|
continue;
|
|
28835
26639
|
}
|
|
28836
26640
|
seenFileHashes.add(fileHash);
|
|
28837
|
-
const fileExtension =
|
|
26641
|
+
const fileExtension = path33.extname(filePath).toLowerCase();
|
|
28838
26642
|
const parsed = await adapter.parseFile(
|
|
28839
26643
|
{
|
|
28840
26644
|
content,
|
|
28841
|
-
fileName:
|
|
26645
|
+
fileName: path33.basename(filePath),
|
|
28842
26646
|
fileExtension,
|
|
28843
26647
|
fileRef: fileHash
|
|
28844
26648
|
},
|
|
@@ -28894,7 +26698,7 @@ async function collectLocalSessionSummaries(options) {
|
|
|
28894
26698
|
}
|
|
28895
26699
|
async function readRedactionConfig(pathLike) {
|
|
28896
26700
|
if (!pathLike) return void 0;
|
|
28897
|
-
const raw = await readFile7(
|
|
26701
|
+
const raw = await readFile7(path33.resolve(expandTildePath(pathLike)), "utf-8");
|
|
28898
26702
|
const parsed = JSON.parse(raw);
|
|
28899
26703
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
28900
26704
|
throw new Error("redaction config must be a JSON object");
|
|
@@ -28907,21 +26711,21 @@ function toJsonl(drafts) {
|
|
|
28907
26711
|
}
|
|
28908
26712
|
function defaultDraftOutputPath(memoryDir, generatedAt) {
|
|
28909
26713
|
const stamp = generatedAt.replace(/[:.]/g, "-");
|
|
28910
|
-
return
|
|
28911
|
-
|
|
26714
|
+
return path33.join(
|
|
26715
|
+
path33.resolve(expandTildePath(memoryDir)),
|
|
28912
26716
|
"state",
|
|
28913
26717
|
"session-summary-drafts",
|
|
28914
26718
|
`session-summaries-${stamp}.jsonl`
|
|
28915
26719
|
);
|
|
28916
26720
|
}
|
|
28917
26721
|
async function writeDrafts(filePath, drafts) {
|
|
28918
|
-
await
|
|
26722
|
+
await mkdir7(path33.dirname(filePath), { recursive: true });
|
|
28919
26723
|
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
28920
26724
|
try {
|
|
28921
26725
|
await writeFile7(tempPath, toJsonl(drafts), "utf-8");
|
|
28922
|
-
await
|
|
26726
|
+
await rename(tempPath, filePath);
|
|
28923
26727
|
} catch (error) {
|
|
28924
|
-
await
|
|
26728
|
+
await rm(tempPath, { force: true });
|
|
28925
26729
|
throw error;
|
|
28926
26730
|
}
|
|
28927
26731
|
}
|
|
@@ -28933,7 +26737,7 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
28933
26737
|
});
|
|
28934
26738
|
const wroteFiles = [];
|
|
28935
26739
|
if (options.output) {
|
|
28936
|
-
const outputPath =
|
|
26740
|
+
const outputPath = path33.resolve(expandTildePath(options.output));
|
|
28937
26741
|
await writeDrafts(outputPath, report.drafts);
|
|
28938
26742
|
wroteFiles.push(outputPath);
|
|
28939
26743
|
}
|
|
@@ -28967,20 +26771,20 @@ async function runLocalSessionSummaryCliCommand(options) {
|
|
|
28967
26771
|
}
|
|
28968
26772
|
|
|
28969
26773
|
// src/transfer/capsule-fork.ts
|
|
28970
|
-
import { lstat as
|
|
28971
|
-
import
|
|
26774
|
+
import { lstat as lstat4, mkdir as mkdir8, readFile as readFile8, realpath as realpath3, writeFile as writeFile8 } from "fs/promises";
|
|
26775
|
+
import path34 from "path";
|
|
28972
26776
|
async function forkCapsule(opts) {
|
|
28973
26777
|
validateForkId(opts.forkId);
|
|
28974
|
-
const rootAbs =
|
|
26778
|
+
const rootAbs = path34.resolve(opts.targetRoot);
|
|
28975
26779
|
await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
|
|
28976
|
-
const forkDirAbs =
|
|
26780
|
+
const forkDirAbs = path34.join(rootAbs, "forks", opts.forkId);
|
|
28977
26781
|
const forkEntryExists = await pathEntryExists(forkDirAbs);
|
|
28978
26782
|
if (forkEntryExists) {
|
|
28979
26783
|
throw new Error(
|
|
28980
26784
|
`forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
|
|
28981
26785
|
);
|
|
28982
26786
|
}
|
|
28983
|
-
const archiveAbs =
|
|
26787
|
+
const archiveAbs = path34.resolve(opts.sourceArchive);
|
|
28984
26788
|
const importResult = await importCapsule({
|
|
28985
26789
|
archivePath: archiveAbs,
|
|
28986
26790
|
root: rootAbs,
|
|
@@ -29002,10 +26806,10 @@ async function forkCapsule(opts) {
|
|
|
29002
26806
|
importedRecords: importResult.imported.length,
|
|
29003
26807
|
skippedRecords: importResult.skipped.length
|
|
29004
26808
|
};
|
|
29005
|
-
const lineagePath =
|
|
26809
|
+
const lineagePath = path34.join(forkDirAbs, "lineage.json");
|
|
29006
26810
|
const rootReal = await realpath3(rootAbs);
|
|
29007
26811
|
await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
|
|
29008
|
-
await
|
|
26812
|
+
await mkdir8(path34.dirname(lineagePath), { recursive: true });
|
|
29009
26813
|
await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
|
|
29010
26814
|
return {
|
|
29011
26815
|
archivePath: archiveAbs,
|
|
@@ -29019,11 +26823,11 @@ async function readForkLineage(targetRoot, forkId) {
|
|
|
29019
26823
|
if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
|
|
29020
26824
|
return null;
|
|
29021
26825
|
}
|
|
29022
|
-
const rootAbs =
|
|
26826
|
+
const rootAbs = path34.resolve(targetRoot);
|
|
29023
26827
|
const rootReal = await realpath3(rootAbs).catch(() => rootAbs);
|
|
29024
|
-
const lineagePath =
|
|
29025
|
-
const rel =
|
|
29026
|
-
if (rel.startsWith("..") ||
|
|
26828
|
+
const lineagePath = path34.join(rootReal, "forks", forkId, "lineage.json");
|
|
26829
|
+
const rel = path34.relative(rootReal, lineagePath);
|
|
26830
|
+
if (rel.startsWith("..") || path34.isAbsolute(rel)) {
|
|
29027
26831
|
return null;
|
|
29028
26832
|
}
|
|
29029
26833
|
if (!await isLineagePathContained(rootReal, lineagePath)) {
|
|
@@ -29058,45 +26862,30 @@ function validateForkId(forkId) {
|
|
|
29058
26862
|
}
|
|
29059
26863
|
}
|
|
29060
26864
|
async function pathEntryExists(absPath) {
|
|
29061
|
-
const st = await
|
|
26865
|
+
const st = await lstat4(absPath).catch(() => null);
|
|
29062
26866
|
return st !== null;
|
|
29063
26867
|
}
|
|
29064
26868
|
async function isLineagePathContained(rootReal, lineagePath) {
|
|
29065
26869
|
let existing = lineagePath;
|
|
29066
26870
|
const suffix = [];
|
|
29067
|
-
while (existing !==
|
|
29068
|
-
const st = await
|
|
26871
|
+
while (existing !== path34.dirname(existing)) {
|
|
26872
|
+
const st = await lstat4(existing).catch(() => null);
|
|
29069
26873
|
if (st !== null) break;
|
|
29070
|
-
suffix.unshift(
|
|
29071
|
-
existing =
|
|
26874
|
+
suffix.unshift(path34.basename(existing));
|
|
26875
|
+
existing = path34.dirname(existing);
|
|
29072
26876
|
}
|
|
29073
26877
|
const existingReal = await realpath3(existing).catch(() => existing);
|
|
29074
|
-
const targetReal = suffix.length > 0 ?
|
|
29075
|
-
const rel =
|
|
26878
|
+
const targetReal = suffix.length > 0 ? path34.join(existingReal, ...suffix) : existingReal;
|
|
26879
|
+
const rel = path34.relative(rootReal, targetReal);
|
|
29076
26880
|
if (rel === "") return true;
|
|
29077
26881
|
if (rel === "..") return false;
|
|
29078
|
-
if (rel.startsWith(`..${
|
|
29079
|
-
if (
|
|
26882
|
+
if (rel.startsWith(`..${path34.sep}`)) return false;
|
|
26883
|
+
if (path34.isAbsolute(rel)) return false;
|
|
29080
26884
|
return true;
|
|
29081
26885
|
}
|
|
29082
26886
|
|
|
29083
26887
|
export {
|
|
29084
26888
|
buildProcedureRecallSection,
|
|
29085
|
-
SupportPassportError,
|
|
29086
|
-
SupportPassportCardService,
|
|
29087
|
-
SupportPassportGrantCardRefSchema,
|
|
29088
|
-
SupportPassportGrantStateSchema,
|
|
29089
|
-
SupportPassportCreateGrantInputSchema,
|
|
29090
|
-
SupportPassportOwnerGrantSchema,
|
|
29091
|
-
SupportPassportCreatedGrantSchema,
|
|
29092
|
-
SupportPassportPublicCardSchema,
|
|
29093
|
-
SupportPassportPublicGuideSchema,
|
|
29094
|
-
SupportPassportRevokeGrantInputSchema,
|
|
29095
|
-
SupportPassportListGrantsInputSchema,
|
|
29096
|
-
notifySupportPassportCommitted,
|
|
29097
|
-
syncDirectoryForDurability,
|
|
29098
|
-
SupportPassportGrantStore,
|
|
29099
|
-
SupportPassportGrantService,
|
|
29100
26889
|
RELAY_DEMO_MISSION_ID,
|
|
29101
26890
|
RELAY_DEMO_NAMESPACE,
|
|
29102
26891
|
createRelayMissionFixture,
|
|
@@ -29210,4 +26999,4 @@ export {
|
|
|
29210
26999
|
blendGraphExpandedRecallScore,
|
|
29211
27000
|
Orchestrator
|
|
29212
27001
|
};
|
|
29213
|
-
//# sourceMappingURL=chunk-
|
|
27002
|
+
//# sourceMappingURL=chunk-W5ZKPI34.js.map
|