attention-manifest-protocol 0.4.2 → 0.4.4
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/CHANGELOG.md +341 -293
- package/CHANGELOG.zh-CN.md +41 -8
- package/README.md +250 -171
- package/README.zh-CN.md +251 -171
- package/lib/assignment/assign.d.ts +102 -0
- package/lib/assignment/assign.js +556 -0
- package/lib/assignment/binding.d.ts +103 -0
- package/lib/assignment/binding.js +575 -0
- package/lib/assignment/errors.d.ts +14 -0
- package/lib/assignment/errors.js +16 -0
- package/lib/assignment/guards.d.ts +18 -0
- package/lib/assignment/guards.js +28 -0
- package/lib/assignment/index.d.ts +10 -0
- package/lib/assignment/index.js +10 -0
- package/lib/assignment/types.d.ts +169 -0
- package/lib/assignment/types.js +1 -0
- package/lib/attention/budget.d.ts +1 -1
- package/lib/attention/budget.js +31 -9
- package/lib/bayes/engine.js +2 -1
- package/lib/bayes/reliability.js +25 -10
- package/lib/boundary/frame.d.ts +10 -4
- package/lib/boundary/frame.js +346 -109
- package/lib/boundary/kinds.d.ts +11 -0
- package/lib/boundary/kinds.js +33 -0
- package/lib/boundary/refTable.d.ts +19 -9
- package/lib/boundary/refTable.js +128 -30
- package/lib/boundary/toolCall.d.ts +22 -10
- package/lib/boundary/toolCall.js +798 -97
- package/lib/concept/conceptBudget.js +10 -1
- package/lib/concurrency/idempotency.d.ts +4 -3
- package/lib/concurrency/idempotency.js +57 -13
- package/lib/concurrency/retry.js +18 -3
- package/lib/context/agentContext.d.ts +13 -0
- package/lib/context/agentContext.js +14 -1
- package/lib/context/ast.d.ts +4 -1
- package/lib/context/ast.js +13 -3
- package/lib/context/contentStore.js +22 -9
- package/lib/context/contextBuilder.d.ts +457 -0
- package/lib/context/contextBuilder.js +1395 -0
- package/lib/context/contextPackage.d.ts +214 -0
- package/lib/context/contextPackage.js +191 -0
- package/lib/context/index.d.ts +14 -3
- package/lib/context/index.js +9 -1
- package/lib/context/relevance.d.ts +171 -0
- package/lib/context/relevance.js +250 -0
- package/lib/context/workspaceDiff.d.ts +105 -0
- package/lib/context/workspaceDiff.js +238 -0
- package/lib/context/workspaceService.d.ts +236 -1
- package/lib/context/workspaceService.js +1501 -73
- package/lib/cooperation/collaboration.d.ts +9 -0
- package/lib/cooperation/session.d.ts +4 -4
- package/lib/cooperation/session.js +3 -3
- package/lib/database/adapter/filesystemStore.d.ts +145 -0
- package/lib/database/adapter/filesystemStore.js +321 -0
- package/lib/database/adapter/index.d.ts +2 -0
- package/lib/database/adapter/index.js +2 -0
- package/lib/database/adapter/workspaceSessionStore.d.ts +118 -0
- package/lib/database/adapter/workspaceSessionStore.js +120 -0
- package/lib/database/entity/fileGraph.d.ts +53 -0
- package/lib/database/entity/fileGraph.js +15 -0
- package/lib/database/entity/fileTree.d.ts +76 -0
- package/lib/database/entity/fileTree.js +39 -0
- package/lib/database/entity/hook.d.ts +29 -0
- package/lib/database/entity/hook.js +18 -0
- package/lib/database/entity/index.d.ts +4 -0
- package/lib/database/entity/index.js +4 -0
- package/lib/database/entity/workspaceSession.d.ts +53 -0
- package/lib/database/entity/workspaceSession.js +28 -0
- package/lib/database/repository/fileAnnotationRepository.d.ts +75 -0
- package/lib/database/repository/fileAnnotationRepository.js +109 -0
- package/lib/database/repository/fileGraphRepository.d.ts +188 -0
- package/lib/database/repository/fileGraphRepository.js +648 -0
- package/lib/database/repository/fileNodeRepository.d.ts +116 -0
- package/lib/database/repository/fileNodeRepository.js +263 -0
- package/lib/database/repository/fileOutlineRepository.d.ts +40 -0
- package/lib/database/repository/fileOutlineRepository.js +104 -0
- package/lib/database/repository/fileWriteRepository.d.ts +41 -0
- package/lib/database/repository/fileWriteRepository.js +93 -0
- package/lib/database/repository/hookRepository.d.ts +67 -0
- package/lib/database/repository/hookRepository.js +150 -0
- package/lib/database/repository/index.d.ts +7 -0
- package/lib/database/repository/index.js +7 -0
- package/lib/database/repository/workspaceSessionRepository.d.ts +134 -0
- package/lib/database/repository/workspaceSessionRepository.js +327 -0
- package/lib/database/service/database.d.ts +14 -0
- package/lib/database/service/database.js +21 -0
- package/lib/database/sql/schema.js +187 -0
- package/lib/database/store/database.js +6 -1
- package/lib/delegate/team.d.ts +5 -0
- package/lib/delegate/team.js +83 -20
- package/lib/discover/classify.d.ts +20 -0
- package/lib/discover/classify.js +85 -0
- package/lib/discover/host.d.ts +20 -0
- package/lib/discover/host.js +89 -0
- package/lib/discover/index.d.ts +11 -0
- package/lib/discover/index.js +11 -0
- package/lib/discover/kinds.d.ts +14 -0
- package/lib/discover/kinds.js +23 -0
- package/lib/discover/tree.d.ts +7 -0
- package/lib/discover/tree.js +432 -0
- package/lib/discover/types.d.ts +115 -0
- package/lib/discover/types.js +1 -0
- package/lib/error/boundaryRejection.d.ts +1 -1
- package/lib/evaluation/agreement.js +2 -2
- package/lib/execution/handles.js +6 -0
- package/lib/execution/pin.js +2 -2
- package/lib/file/cfb.d.ts +56 -0
- package/lib/file/cfb.js +396 -0
- package/lib/file/dependency.d.ts +151 -0
- package/lib/file/dependency.js +568 -0
- package/lib/file/directory.d.ts +34 -0
- package/lib/file/directory.js +141 -0
- package/lib/file/errors.d.ts +20 -0
- package/lib/file/errors.js +18 -0
- package/lib/file/exportGraph.d.ts +31 -0
- package/lib/file/exportGraph.js +554 -0
- package/lib/file/file.d.ts +40 -0
- package/lib/file/file.js +339 -0
- package/lib/file/importGraph.d.ts +121 -0
- package/lib/file/importGraph.js +1022 -0
- package/lib/file/index.d.ts +45 -0
- package/lib/file/index.js +30 -0
- package/lib/file/metadata.d.ts +66 -0
- package/lib/file/metadata.js +470 -0
- package/lib/file/path.d.ts +60 -0
- package/lib/file/path.js +259 -0
- package/lib/file/read.d.ts +168 -0
- package/lib/file/read.js +541 -0
- package/lib/file/runtime.d.ts +95 -0
- package/lib/file/runtime.js +150 -0
- package/lib/file/service.d.ts +227 -0
- package/lib/file/service.js +663 -0
- package/lib/file/syntaxTree.d.ts +7 -0
- package/lib/file/syntaxTree.js +38 -0
- package/lib/file/time.d.ts +38 -0
- package/lib/file/time.js +44 -0
- package/lib/file/tree.d.ts +53 -0
- package/lib/file/tree.js +417 -0
- package/lib/file/types.d.ts +371 -0
- package/lib/file/types.js +1 -0
- package/lib/file/write.d.ts +159 -0
- package/lib/file/write.js +1028 -0
- package/lib/file/zip.d.ts +35 -0
- package/lib/file/zip.js +349 -0
- package/lib/fingerprint/algorithm.d.ts +97 -0
- package/lib/fingerprint/algorithm.js +271 -0
- package/lib/fingerprint/bytes.d.ts +18 -0
- package/lib/fingerprint/bytes.js +31 -0
- package/lib/fingerprint/error.d.ts +73 -0
- package/lib/fingerprint/error.js +86 -0
- package/lib/fingerprint/file.d.ts +71 -0
- package/lib/fingerprint/file.js +254 -0
- package/lib/fingerprint/index.d.ts +37 -0
- package/lib/fingerprint/index.js +12 -0
- package/lib/fingerprint/json.d.ts +41 -0
- package/lib/fingerprint/json.js +94 -0
- package/lib/fingerprint/number.d.ts +32 -0
- package/lib/fingerprint/number.js +95 -0
- package/lib/fingerprint/policy.d.ts +54 -0
- package/lib/fingerprint/policy.js +50 -0
- package/lib/fingerprint/preimage.d.ts +84 -0
- package/lib/fingerprint/preimage.js +133 -0
- package/lib/fingerprint/raw.d.ts +26 -0
- package/lib/fingerprint/raw.js +45 -0
- package/lib/fingerprint/ref.d.ts +39 -0
- package/lib/fingerprint/ref.js +178 -0
- package/lib/fingerprint/text.d.ts +42 -0
- package/lib/fingerprint/text.js +155 -0
- package/lib/fingerprint/tree.d.ts +56 -0
- package/lib/fingerprint/tree.js +288 -0
- package/lib/fingerprint/verify.d.ts +20 -0
- package/lib/fingerprint/verify.js +99 -0
- package/lib/global/filesystem.d.ts +43 -0
- package/lib/global/filesystem.js +75 -0
- package/lib/global/index.d.ts +8 -0
- package/lib/global/index.js +8 -0
- package/lib/global/service.d.ts +51 -0
- package/lib/global/service.js +98 -0
- package/lib/governance/transport.js +18 -6
- package/lib/hook/ast.d.ts +29 -0
- package/lib/hook/ast.js +22 -0
- package/lib/hook/code.d.ts +55 -0
- package/lib/hook/code.js +47 -0
- package/lib/hook/dependency.d.ts +45 -0
- package/lib/hook/dependency.js +28 -0
- package/lib/hook/diff.d.ts +114 -0
- package/lib/hook/diff.js +327 -0
- package/lib/hook/exportation.d.ts +31 -0
- package/lib/hook/exportation.js +24 -0
- package/lib/hook/file.d.ts +44 -0
- package/lib/hook/file.js +154 -0
- package/lib/hook/importation.d.ts +33 -0
- package/lib/hook/importation.js +22 -0
- package/lib/hook/index.d.ts +30 -0
- package/lib/hook/index.js +23 -0
- package/lib/hook/outline.d.ts +35 -0
- package/lib/hook/outline.js +27 -0
- package/lib/hook/project.d.ts +65 -0
- package/lib/hook/project.js +217 -0
- package/lib/hook/types.d.ts +114 -0
- package/lib/hook/types.js +407 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js +9 -0
- package/lib/lock/lease.js +28 -3
- package/lib/manifest/cardSign.d.ts +1 -1
- package/lib/manifest/cardSign.js +37 -7
- package/lib/manifest/federation.js +13 -6
- package/lib/manifest/trust.d.ts +2 -0
- package/lib/manifest/trust.js +27 -6
- package/lib/module/index.d.ts +4 -0
- package/lib/module/index.js +4 -0
- package/lib/module/mcp/client.js +21 -2
- package/lib/module/mcp/filesystemServer.d.ts +24 -0
- package/lib/module/mcp/filesystemServer.js +102 -0
- package/lib/module/mcp/http.js +32 -19
- package/lib/module/mcp/workspaceServer.js +20 -3
- package/lib/module/tool/filesystemExecutor.d.ts +18 -0
- package/lib/module/tool/filesystemExecutor.js +49 -0
- package/lib/module/tool/globalExecutor.d.ts +17 -0
- package/lib/module/tool/globalExecutor.js +39 -0
- package/lib/module/tool/globalFilesystemExecutor.d.ts +18 -0
- package/lib/module/tool/globalFilesystemExecutor.js +49 -0
- package/lib/module/tool/workspaceExecutor.d.ts +9 -0
- package/lib/module/tool/workspaceExecutor.js +16 -3
- package/lib/naming/aliases.d.ts +48 -0
- package/lib/naming/aliases.js +79 -0
- package/lib/naming/catalog.d.ts +117 -0
- package/lib/naming/catalog.js +108 -0
- package/lib/naming/grammar.d.ts +67 -0
- package/lib/naming/grammar.js +212 -0
- package/lib/naming/ids.d.ts +157 -0
- package/lib/naming/ids.js +119 -0
- package/lib/naming/index.d.ts +13 -0
- package/lib/naming/index.js +13 -0
- package/lib/outline/index.d.ts +9 -0
- package/lib/outline/index.js +8 -0
- package/lib/outline/office.d.ts +160 -0
- package/lib/outline/office.js +2375 -0
- package/lib/outline/officeBridge.d.ts +32 -0
- package/lib/outline/officeBridge.js +27 -0
- package/lib/outline/outline.d.ts +159 -0
- package/lib/outline/outline.js +837 -0
- package/lib/outline/outlineIndex.d.ts +97 -0
- package/lib/outline/outlineIndex.js +325 -0
- package/lib/outline/outlineKeywords.d.ts +59 -0
- package/lib/outline/outlineKeywords.js +143 -0
- package/lib/outline/outlineStrategies.d.ts +414 -0
- package/lib/outline/outlineStrategies.js +8324 -0
- package/lib/outline/reactOutline.d.ts +37 -0
- package/lib/outline/reactOutline.js +1070 -0
- package/lib/outline/shellOutline.d.ts +65 -0
- package/lib/outline/shellOutline.js +873 -0
- package/lib/outline/sqlOutline.d.ts +170 -0
- package/lib/outline/sqlOutline.js +1536 -0
- package/lib/outline/strategy.d.ts +46 -0
- package/lib/outline/strategy.js +1 -0
- package/lib/outline/types.d.ts +95 -0
- package/lib/outline/types.js +1 -0
- package/lib/outline/visualBasicOutline.d.ts +27 -0
- package/lib/outline/visualBasicOutline.js +750 -0
- package/lib/protocol/filesystem.d.ts +55 -0
- package/lib/protocol/filesystem.js +105 -0
- package/lib/protocol/global.d.ts +42 -0
- package/lib/protocol/global.js +63 -0
- package/lib/protocol/globalFilesystem.d.ts +40 -0
- package/lib/protocol/globalFilesystem.js +59 -0
- package/lib/protocol/index.d.ts +4 -0
- package/lib/protocol/index.js +4 -0
- package/lib/protocol/protocol.d.ts +4 -0
- package/lib/protocol/wire.js +5 -2
- package/lib/protocol/workspace.d.ts +305 -0
- package/lib/protocol/workspace.js +258 -0
- package/lib/receipt/receipt.d.ts +8 -0
- package/lib/registry/content.js +9 -3
- package/lib/runtime/kernelRuntime.js +9 -1
- package/lib/scenario/scenario.js +5 -4
- package/lib/semantic/canonical.d.ts +61 -0
- package/lib/semantic/canonical.js +135 -8
- package/lib/semantic/jsonValue.d.ts +31 -0
- package/lib/semantic/jsonValue.js +122 -0
- package/lib/semantic/sha256.js +3 -0
- package/lib/semantic/time.d.ts +14 -0
- package/lib/semantic/time.js +56 -0
- package/lib/session/context.d.ts +76 -0
- package/lib/session/context.js +419 -0
- package/lib/session/errors.d.ts +24 -0
- package/lib/session/errors.js +22 -0
- package/lib/session/identity.d.ts +24 -0
- package/lib/session/identity.js +56 -0
- package/lib/session/index.d.ts +14 -0
- package/lib/session/index.js +12 -0
- package/lib/session/registry.d.ts +130 -0
- package/lib/session/registry.js +908 -0
- package/lib/session/types.d.ts +227 -0
- package/lib/session/types.js +14 -0
- package/lib/structure/index.d.ts +1 -0
- package/lib/structure/index.js +1 -0
- package/lib/structure/trie.d.ts +88 -0
- package/lib/structure/trie.js +183 -0
- package/lib/syntax/byteIndex.d.ts +44 -0
- package/lib/syntax/byteIndex.js +148 -0
- package/lib/syntax/charset.d.ts +88 -0
- package/lib/syntax/charset.js +276 -0
- package/lib/syntax/index.d.ts +6 -0
- package/lib/syntax/index.js +5 -0
- package/lib/syntax/syntaxRegistry.d.ts +150 -0
- package/lib/syntax/syntaxRegistry.js +314 -0
- package/lib/syntax/syntaxTree.d.ts +106 -0
- package/lib/syntax/syntaxTree.js +668 -0
- package/lib/syntax/types.d.ts +15 -0
- package/lib/syntax/types.js +1 -0
- package/lib/types/common.d.ts +1 -1
- package/package.json +72 -193
- package/.editorconfig +0 -12
- package/.prettierignore +0 -17
- package/MCP-Token/347/250/216/344/270/216/344/270/213/344/270/200/344/273/243/345/267/245/345/205/267/345/215/217/350/256/256.html +0 -1763
- package/docs/annotation-campaign-A.csv +0 -54
- package/docs/annotation-campaign-B.csv +0 -54
- package/docs/annotation-campaign.csv +0 -54
- package/docs/eval/annotations-A.jsonl +0 -16
- package/docs/eval/annotations.json +0 -122
- package/docs/eval/recorded-labels.json +0 -12
- package/docs/eval/replay-cases.json +0 -14
- package/docs/eval/replay-labels-b.json +0 -14
- package/docs/examples/attention-request.json +0 -16
- package/docs/examples/checkpoint.json +0 -15
- package/docs/examples/claim.json +0 -66
- package/docs/examples/collaboration.json +0 -66
- package/docs/examples/concept-checkpoint.json +0 -15
- package/docs/examples/concept-prune-plan.json +0 -45
- package/docs/examples/federation.json +0 -126
- package/docs/examples/frame-chain.json +0 -77
- package/docs/examples/ledger-snapshot.json +0 -108
- package/docs/examples/manifest.json +0 -77
- package/docs/examples/message.json +0 -19
- package/docs/examples/other-model.json +0 -45
- package/docs/examples/plan.json +0 -50
- package/docs/examples/prune-plan.json +0 -48
- package/docs/examples/receipt.json +0 -22
- package/docs/examples/runtime-run.json +0 -573
- package/docs/examples/team.json +0 -66
- package/docs/examples/verb-note.json +0 -11
- package/docs/probes/bayes-scores.json +0 -1452
- package/docs/probes/calibration-imported.json +0 -141
- package/docs/probes/context-ast-deepseek.json +0 -1577
- package/docs/probes/deepseek-probe.json +0 -917
- package/docs/probes/eval-recorded-replay.json +0 -597
- package/docs/probes/eval-replay.json +0 -124
- package/docs/probes/eval-summary.json +0 -42
- package/docs/probes/runtime-eval.json +0 -4230
- package/eslint.config.mts +0 -96
- package/index.html +0 -13
- package/prettier.config.mts +0 -37
- package/public/favicon.svg +0 -1
- package/public/icons.svg +0 -24
- package/src/attention/attention.ts +0 -347
- package/src/attention/budget.ts +0 -72
- package/src/attention/cognition.ts +0 -519
- package/src/attention/index.ts +0 -8
- package/src/attention/interrupts.ts +0 -228
- package/src/attention/resource.ts +0 -316
- package/src/attention/social.ts +0 -217
- package/src/attention/socialTypes.ts +0 -115
- package/src/authz/authz.ts +0 -305
- package/src/authz/index.ts +0 -1
- package/src/bayes/calibration.ts +0 -204
- package/src/bayes/calibrationRegistry.ts +0 -111
- package/src/bayes/calibrationSelection.ts +0 -154
- package/src/bayes/engine.ts +0 -532
- package/src/bayes/index.ts +0 -6
- package/src/bayes/reliability.ts +0 -62
- package/src/bayes/scopedPriors.ts +0 -88
- package/src/boundary/frame.ts +0 -322
- package/src/boundary/ids.ts +0 -14
- package/src/boundary/index.ts +0 -12
- package/src/boundary/refTable.ts +0 -125
- package/src/boundary/toolCall.ts +0 -212
- package/src/concept/concept.ts +0 -75
- package/src/concept/conceptBudget.ts +0 -346
- package/src/concept/conceptBudgetTypes.ts +0 -79
- package/src/concept/index.ts +0 -3
- package/src/concurrency/idempotency.ts +0 -41
- package/src/concurrency/index.ts +0 -5
- package/src/concurrency/mutex.ts +0 -26
- package/src/concurrency/namedLocks.ts +0 -35
- package/src/concurrency/retry.ts +0 -50
- package/src/concurrency/worker.ts +0 -128
- package/src/context/agentContext.ts +0 -308
- package/src/context/ast.ts +0 -499
- package/src/context/contentStore.ts +0 -75
- package/src/context/context.ts +0 -65
- package/src/context/contextIndex.ts +0 -85
- package/src/context/document.ts +0 -137
- package/src/context/fileStorePath.ts +0 -14
- package/src/context/index.ts +0 -43
- package/src/context/lifecycle.ts +0 -221
- package/src/context/projections.ts +0 -151
- package/src/context/workspace.ts +0 -422
- package/src/context/workspaceProtocol.ts +0 -112
- package/src/context/workspaceService.ts +0 -423
- package/src/cooperation/board.ts +0 -104
- package/src/cooperation/collaboration.ts +0 -60
- package/src/cooperation/index.ts +0 -6
- package/src/cooperation/merge.ts +0 -190
- package/src/cooperation/metrics.ts +0 -57
- package/src/cooperation/session.ts +0 -131
- package/src/cooperation/unified.ts +0 -56
- package/src/counter.ts +0 -9
- package/src/database/adapter/adapters.ts +0 -35
- package/src/database/adapter/index.ts +0 -4
- package/src/database/adapter/runtimeSink.ts +0 -74
- package/src/database/adapter/sessionStore.ts +0 -32
- package/src/database/adapter/turnStore.ts +0 -23
- package/src/database/entity/agent.ts +0 -199
- package/src/database/entity/entity.ts +0 -1046
- package/src/database/entity/handle.ts +0 -79
- package/src/database/entity/index.ts +0 -32
- package/src/database/entity/message.ts +0 -74
- package/src/database/entity/meta.ts +0 -11
- package/src/database/entity/object.ts +0 -42
- package/src/database/entity/outbox.ts +0 -15
- package/src/database/entity/process.ts +0 -65
- package/src/database/entity/registry.ts +0 -155
- package/src/database/entity/runtimeApproval.ts +0 -30
- package/src/database/entity/runtimeSession.ts +0 -13
- package/src/database/entity/runtimeTurn.ts +0 -15
- package/src/database/entity/thread.ts +0 -85
- package/src/database/entity/window.ts +0 -85
- package/src/database/entity/worker.ts +0 -90
- package/src/database/index.ts +0 -6
- package/src/database/repository/addressSpaceRepository.ts +0 -72
- package/src/database/repository/agentRepository.ts +0 -460
- package/src/database/repository/base.ts +0 -41
- package/src/database/repository/executionRepository.ts +0 -477
- package/src/database/repository/handleRepository.ts +0 -64
- package/src/database/repository/index.ts +0 -20
- package/src/database/repository/messageRepository.ts +0 -52
- package/src/database/repository/objectRepository.ts +0 -69
- package/src/database/repository/outboxRepository.ts +0 -63
- package/src/database/repository/processRepository.ts +0 -58
- package/src/database/repository/registryRepository.ts +0 -119
- package/src/database/repository/repository.ts +0 -491
- package/src/database/repository/runtimeApprovalRepository.ts +0 -44
- package/src/database/repository/runtimeSessionRepository.ts +0 -27
- package/src/database/repository/runtimeTurnRepository.ts +0 -39
- package/src/database/repository/socialRepository.ts +0 -185
- package/src/database/repository/threadRepository.ts +0 -57
- package/src/database/repository/windowRepository.ts +0 -88
- package/src/database/repository/workerRepository.ts +0 -69
- package/src/database/service/database.ts +0 -90
- package/src/database/service/handleService.ts +0 -48
- package/src/database/service/index.ts +0 -16
- package/src/database/service/messageService.ts +0 -61
- package/src/database/service/objectService.ts +0 -59
- package/src/database/service/processService.ts +0 -61
- package/src/database/service/registryServices.ts +0 -88
- package/src/database/service/service.ts +0 -183
- package/src/database/service/stepService.ts +0 -53
- package/src/database/service/threadService.ts +0 -65
- package/src/database/service/windowService.ts +0 -30
- package/src/database/service/workerService.ts +0 -57
- package/src/database/sql/index.ts +0 -3
- package/src/database/sql/schema.ts +0 -418
- package/src/database/sql/sql.ts +0 -543
- package/src/database/store/database.ts +0 -210
- package/src/database/store/index.ts +0 -3
- package/src/database/store/store.ts +0 -266
- package/src/delegate/index.ts +0 -2
- package/src/delegate/team.ts +0 -268
- package/src/delegate/teamTypes.ts +0 -47
- package/src/diagnosis/checklist.ts +0 -74
- package/src/diagnosis/context.ts +0 -93
- package/src/diagnosis/frame.ts +0 -256
- package/src/diagnosis/index.ts +0 -5
- package/src/diagnosis/router.ts +0 -72
- package/src/diagnosis/types.ts +0 -89
- package/src/error/agentError.ts +0 -16
- package/src/error/ampError.ts +0 -20
- package/src/error/authzError.ts +0 -14
- package/src/error/boundaryRejection.ts +0 -20
- package/src/error/index.ts +0 -7
- package/src/error/kernelError.ts +0 -27
- package/src/error/mailboxError.ts +0 -9
- package/src/error/windowError.ts +0 -12
- package/src/evaluation/agreement.ts +0 -96
- package/src/evaluation/index.ts +0 -2
- package/src/evaluation/labels.ts +0 -241
- package/src/evidence/evidenceGraph.ts +0 -205
- package/src/evidence/index.ts +0 -4
- package/src/evidence/revalidation.ts +0 -191
- package/src/execution/exec.ts +0 -408
- package/src/execution/handles.ts +0 -65
- package/src/execution/index.ts +0 -3
- package/src/execution/pin.ts +0 -154
- package/src/frame/frame.ts +0 -70
- package/src/frame/index.ts +0 -1
- package/src/goal/goal.ts +0 -43
- package/src/goal/index.ts +0 -2
- package/src/goal/plan.ts +0 -196
- package/src/governance/attentionManifest.ts +0 -802
- package/src/governance/audit.ts +0 -362
- package/src/governance/budget.ts +0 -628
- package/src/governance/context.ts +0 -356
- package/src/governance/control.ts +0 -159
- package/src/governance/cooperation.ts +0 -479
- package/src/governance/credential.ts +0 -359
- package/src/governance/httpServer.ts +0 -99
- package/src/governance/index.ts +0 -32
- package/src/governance/legal.ts +0 -574
- package/src/governance/matrix.ts +0 -460
- package/src/governance/perspectives.ts +0 -406
- package/src/governance/signing.ts +0 -407
- package/src/governance/store.ts +0 -125
- package/src/governance/switching.ts +0 -459
- package/src/governance/toolPolicy.ts +0 -80
- package/src/governance/transport.ts +0 -204
- package/src/governance/types.ts +0 -380
- package/src/governance/workflow.ts +0 -743
- package/src/index.ts +0 -11
- package/src/interaction/index.ts +0 -1
- package/src/interaction/interaction.ts +0 -391
- package/src/ipc/index.ts +0 -4
- package/src/ipc/mailbox.ts +0 -132
- package/src/ipc/memorySocialStore.ts +0 -93
- package/src/ipc/social.ts +0 -93
- package/src/kernel/index.ts +0 -14
- package/src/kernel/scheduler.ts +0 -498
- package/src/ledger/checkpoint.ts +0 -304
- package/src/ledger/index.ts +0 -4
- package/src/ledger/ledger.ts +0 -31
- package/src/ledger/persistence.ts +0 -159
- package/src/ledger/share.ts +0 -80
- package/src/lock/index.ts +0 -2
- package/src/lock/lease.ts +0 -74
- package/src/main.ts +0 -199
- package/src/manifest/agentCard.ts +0 -72
- package/src/manifest/cardSign.ts +0 -87
- package/src/manifest/federation.ts +0 -237
- package/src/manifest/federationTypes.ts +0 -55
- package/src/manifest/index.ts +0 -8
- package/src/manifest/keys.ts +0 -643
- package/src/manifest/manifest.ts +0 -114
- package/src/manifest/sign.ts +0 -134
- package/src/manifest/trust.ts +0 -146
- package/src/mission/index.ts +0 -2
- package/src/mission/missionQueue.ts +0 -75
- package/src/module/index.ts +0 -9
- package/src/module/llm/deepseek.ts +0 -214
- package/src/module/llm/llm.ts +0 -84
- package/src/module/mcp/client.ts +0 -110
- package/src/module/mcp/http.ts +0 -102
- package/src/module/mcp/protocol.ts +0 -77
- package/src/module/mcp/server.ts +0 -148
- package/src/module/mcp/transport.ts +0 -30
- package/src/module/mcp/workspaceServer.ts +0 -111
- package/src/module/sandbox/sandbox.ts +0 -29
- package/src/module/tool/mcpExecutor.ts +0 -54
- package/src/module/tool/policy.ts +0 -52
- package/src/module/tool/redact.ts +0 -29
- package/src/module/tool/tool.ts +0 -53
- package/src/module/tool/workspaceExecutor.ts +0 -35
- package/src/policy/guard.ts +0 -240
- package/src/policy/index.ts +0 -2
- package/src/policy/policy.ts +0 -561
- package/src/process/agent.ts +0 -341
- package/src/process/agentService.ts +0 -236
- package/src/process/agentStore.ts +0 -378
- package/src/process/executionStore.ts +0 -151
- package/src/process/index.ts +0 -5
- package/src/process/process.ts +0 -240
- package/src/process/transitions.ts +0 -19
- package/src/progress/index.ts +0 -2
- package/src/progress/progress.ts +0 -85
- package/src/protocol/a2a.ts +0 -120
- package/src/protocol/channel.ts +0 -44
- package/src/protocol/envelope.ts +0 -655
- package/src/protocol/httpChannel.ts +0 -87
- package/src/protocol/index.ts +0 -6
- package/src/protocol/protocol.ts +0 -138
- package/src/protocol/wire.ts +0 -60
- package/src/receipt/index.ts +0 -1
- package/src/receipt/receipt.ts +0 -47
- package/src/registry/content.ts +0 -69
- package/src/registry/index.ts +0 -23
- package/src/registry/registry.ts +0 -599
- package/src/runtime/action.ts +0 -87
- package/src/runtime/behavior.ts +0 -330
- package/src/runtime/behaviorTuning.ts +0 -163
- package/src/runtime/cognitiveRuntime.ts +0 -703
- package/src/runtime/escalation.ts +0 -35
- package/src/runtime/governedTask.ts +0 -233
- package/src/runtime/index.ts +0 -15
- package/src/runtime/kernelRuntime.ts +0 -144
- package/src/runtime/operation.ts +0 -35
- package/src/runtime/replay.ts +0 -71
- package/src/runtime/routing.ts +0 -58
- package/src/runtime/safety.ts +0 -48
- package/src/runtime/session.ts +0 -341
- package/src/runtime/sessionStore.ts +0 -43
- package/src/runtime/telemetry.ts +0 -55
- package/src/runtime/turnStore.ts +0 -30
- package/src/scenario/index.ts +0 -1
- package/src/scenario/scenario.ts +0 -299
- package/src/semantic/canonical.ts +0 -24
- package/src/semantic/index.ts +0 -2
- package/src/semantic/sha256.ts +0 -82
- package/src/storage/appendLog.ts +0 -372
- package/src/storage/fileAppendSink.ts +0 -40
- package/src/storage/index.ts +0 -2
- package/src/store/bindCache.ts +0 -22
- package/src/store/cache.ts +0 -191
- package/src/store/context.ts +0 -31
- package/src/store/handleStore.ts +0 -31
- package/src/store/index.ts +0 -9
- package/src/store/messageStore.ts +0 -31
- package/src/store/objectStore.ts +0 -31
- package/src/store/processStore.ts +0 -31
- package/src/store/threadStore.ts +0 -31
- package/src/store/windowStore.ts +0 -31
- package/src/structure/abstractSyntaxTree.ts +0 -493
- package/src/structure/avlTree.ts +0 -408
- package/src/structure/binarySearchTree.ts +0 -352
- package/src/structure/binaryTree.ts +0 -525
- package/src/structure/bloomFilter.ts +0 -231
- package/src/structure/compare.ts +0 -110
- package/src/structure/cuckooFilter.ts +0 -337
- package/src/structure/deque.ts +0 -223
- package/src/structure/filterKey.ts +0 -36
- package/src/structure/hash.ts +0 -279
- package/src/structure/heap.ts +0 -268
- package/src/structure/index.ts +0 -20
- package/src/structure/iterator.ts +0 -22
- package/src/structure/lru.ts +0 -619
- package/src/structure/ordered.ts +0 -399
- package/src/structure/priority.ts +0 -915
- package/src/structure/queue.ts +0 -168
- package/src/structure/redBlackTree.ts +0 -680
- package/src/structure/segmentTree.ts +0 -248
- package/src/structure/stack.ts +0 -118
- package/src/structure/unordered.ts +0 -407
- package/src/style.css +0 -278
- package/src/thread/index.ts +0 -2
- package/src/thread/thread.ts +0 -176
- package/src/thread/transitions.ts +0 -17
- package/src/types/common.ts +0 -119
- package/src/types/index.ts +0 -23
- package/src/warrant/epistemic.ts +0 -154
- package/src/warrant/index.ts +0 -3
- package/src/warrant/inquiry.ts +0 -166
- package/src/warrant/warrant.ts +0 -179
- package/src/window/compaction.ts +0 -403
- package/src/window/compactionTypes.ts +0 -119
- package/src/window/index.ts +0 -7
- package/src/window/page.ts +0 -18
- package/src/window/window.ts +0 -244
- package/tools/_helpers.ts +0 -34
- package/tools/a2a-check.ts +0 -110
- package/tools/a2a-flow-check.ts +0 -78
- package/tools/agent-card-check.ts +0 -76
- package/tools/agent-check.ts +0 -236
- package/tools/agent-store-check.ts +0 -153
- package/tools/agreement-check.ts +0 -27
- package/tools/annotation-server-check.ts +0 -48
- package/tools/annotation-server.ts +0 -230
- package/tools/annotation-status.ts +0 -65
- package/tools/approval-access-check.ts +0 -66
- package/tools/arch-check.ts +0 -72
- package/tools/attention-core-check.ts +0 -48
- package/tools/attention-resource-check.ts +0 -169
- package/tools/audit-check.ts +0 -207
- package/tools/authority-check.ts +0 -124
- package/tools/authz-check.ts +0 -138
- package/tools/bayes-check.ts +0 -162
- package/tools/bayes-probe.ts +0 -154
- package/tools/behavior-tuning-check.ts +0 -53
- package/tools/board-check.ts +0 -87
- package/tools/boundary-check.ts +0 -199
- package/tools/bundle-trust-check.ts +0 -96
- package/tools/calibrate-imported.ts +0 -108
- package/tools/calibration-check.ts +0 -44
- package/tools/calibration-registry-check.ts +0 -40
- package/tools/calibration-sim.ts +0 -40
- package/tools/card-sign-check.ts +0 -71
- package/tools/card-trust-check.ts +0 -78
- package/tools/channel-check.ts +0 -86
- package/tools/checkpoint-check.ts +0 -620
- package/tools/cleanup-style-configs.ts +0 -29
- package/tools/cognition-check.ts +0 -648
- package/tools/cognitive-runtime-check.ts +0 -609
- package/tools/collaboration-demo.ts +0 -78
- package/tools/compaction-check.ts +0 -266
- package/tools/concept-check.ts +0 -260
- package/tools/concurrency-check.ts +0 -242
- package/tools/conformance-runtime.ts +0 -389
- package/tools/conformance.ts +0 -651
- package/tools/context-ast-check.ts +0 -90
- package/tools/context-ast-deepseek.ts +0 -242
- package/tools/context-graph-bench.ts +0 -50
- package/tools/context-graph-check.ts +0 -229
- package/tools/context-index-check.ts +0 -48
- package/tools/context-lifecycle-check.ts +0 -69
- package/tools/context-projection-check.ts +0 -73
- package/tools/context-scope-check.ts +0 -134
- package/tools/context-storage-check.ts +0 -113
- package/tools/cooperation-check.ts +0 -517
- package/tools/cooperation-http-check.ts +0 -125
- package/tools/deepseek-llm-check.ts +0 -147
- package/tools/deepseek-probe.ts +0 -494
- package/tools/diagnosis-check.ts +0 -109
- package/tools/diagnosis-router-check.ts +0 -50
- package/tools/document-context-check.ts +0 -237
- package/tools/envelope-check.ts +0 -659
- package/tools/eslint-rules/index.ts +0 -26
- package/tools/eslint-rules/rules/jsdoc-comment-format.ts +0 -105
- package/tools/eslint-rules/rules/no-function-keyword.ts +0 -60
- package/tools/eslint-rules/rules/no-multiline-parameters.ts +0 -71
- package/tools/eslint-rules/rules/no-multiline-type-parameters.ts +0 -57
- package/tools/eslint-rules/rules/no-undefined-comparison.ts +0 -115
- package/tools/eslint-rules/rules/prefer-template-for-string-conversion.ts +0 -97
- package/tools/eslint-rules/rules/require-typeof-parentheses.ts +0 -49
- package/tools/eslint-rules/rules/require-variable-type.ts +0 -36
- package/tools/eslint-rules/rules/variable-naming.ts +0 -175
- package/tools/eval-recorded-replay.ts +0 -215
- package/tools/eval-replay.ts +0 -139
- package/tools/eval-summary.ts +0 -136
- package/tools/evidence-revalidation-check.ts +0 -235
- package/tools/exec-check.ts +0 -217
- package/tools/federation-check.ts +0 -166
- package/tools/federation-demo.ts +0 -45
- package/tools/filter-check.ts +0 -243
- package/tools/governance-check.ts +0 -680
- package/tools/governance-store-check.ts +0 -131
- package/tools/governed-task-check.ts +0 -227
- package/tools/guard-check.ts +0 -122
- package/tools/http-channel-check.ts +0 -125
- package/tools/import-campaign.ts +0 -28
- package/tools/inquiry-check.ts +0 -126
- package/tools/interaction-check.ts +0 -171
- package/tools/interrupts-check.ts +0 -173
- package/tools/ipc-check.ts +0 -170
- package/tools/kernel-async-check.ts +0 -136
- package/tools/kernel-check.ts +0 -369
- package/tools/kernel-runtime-check.ts +0 -276
- package/tools/keys-check.ts +0 -559
- package/tools/label-audit.ts +0 -70
- package/tools/labels-workflow-check.ts +0 -49
- package/tools/linear-structure-check.ts +0 -524
- package/tools/live-exec.ts +0 -62
- package/tools/live-governance-eval.ts +0 -813
- package/tools/live-legacy.ts +0 -50
- package/tools/lru-check.ts +0 -182
- package/tools/make-annotation-campaign.ts +0 -57
- package/tools/mcp-executor-check.ts +0 -33
- package/tools/merge-annotations.ts +0 -32
- package/tools/merge-check.ts +0 -98
- package/tools/metrics-check.ts +0 -84
- package/tools/net-probe.ts +0 -107
- package/tools/oauth-probe.ts +0 -117
- package/tools/outbox-check.ts +0 -50
- package/tools/persistence-check.ts +0 -144
- package/tools/pin-check.ts +0 -116
- package/tools/platform-check.ts +0 -281
- package/tools/policy-check.ts +0 -514
- package/tools/prettier-plugin/index.mts +0 -84
- package/tools/priority-check.ts +0 -627
- package/tools/probe-context7.ts +0 -63
- package/tools/registry-check.ts +0 -252
- package/tools/reliability-check.ts +0 -25
- package/tools/retry-check.ts +0 -85
- package/tools/rewrite-declaration-extensions.ts +0 -98
- package/tools/runtime-check.ts +0 -165
- package/tools/runtime-deepseek-check.ts +0 -85
- package/tools/runtime-eval.ts +0 -358
- package/tools/scenario-check.ts +0 -161
- package/tools/scenario-incident.ts +0 -162
- package/tools/scoped-priors-check.ts +0 -35
- package/tools/scoped-priors-pooling.ts +0 -34
- package/tools/segment-ast-check.ts +0 -649
- package/tools/session-check.ts +0 -196
- package/tools/session-store-check.ts +0 -73
- package/tools/share-check.ts +0 -88
- package/tools/sign-check.ts +0 -95
- package/tools/signing-check.ts +0 -275
- package/tools/snapshot-demo.ts +0 -65
- package/tools/social-check.ts +0 -146
- package/tools/structure-compare-check.ts +0 -95
- package/tools/support/documentScanner.ts +0 -577
- package/tools/support/texScanner.ts +0 -631
- package/tools/support/workspaceScanner.ts +0 -476
- package/tools/team-check.ts +0 -163
- package/tools/team-demo.ts +0 -36
- package/tools/telemetry-check.ts +0 -44
- package/tools/tex-context-check.ts +0 -263
- package/tools/tool-gate-check.ts +0 -98
- package/tools/tree-structure-check.ts +0 -786
- package/tools/trust-flow-check.ts +0 -158
- package/tools/turn-store-check.ts +0 -57
- package/tools/unified-check.ts +0 -83
- package/tools/validate.ts +0 -309
- package/tools/wire-check.ts +0 -96
- package/tools/workspace-agent-check.ts +0 -486
- package/tools/workspace-agent-demo.ts +0 -62
- package/tools/workspace-agent-server.ts +0 -101
- package/tools/workspace-context-check.ts +0 -331
- package/tools/workspace-context.ts +0 -131
- package/tsconfig.build.json +0 -14
- package/tsconfig.json +0 -24
- package/tsconfig.tools.json +0 -31
- package/viz/context-ast.json +0 -1577
|
@@ -0,0 +1,908 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session registry: identity, lifecycle, capacity and isolated context.
|
|
3
|
+
*
|
|
4
|
+
* A session binds a host-approved agent identity to real root directories, a
|
|
5
|
+
* permission set, a TTL and a private context. The registry is the authority
|
|
6
|
+
* boundary for that record: it mints the one-time credential, verifies it in
|
|
7
|
+
* constant time, serialises every lifecycle transition and persists only the
|
|
8
|
+
* token hash. It never shares mutable state with `runtime/session.ts`, which is
|
|
9
|
+
* the cognitive memory of a turn loop rather than a data-isolation record.
|
|
10
|
+
*
|
|
11
|
+
* All methods are synchronous. That is deliberate: the registry is single
|
|
12
|
+
* threaded, and an async API would invite an `await` between the status check
|
|
13
|
+
* and the state update that lets two callers observe different lifetimes.
|
|
14
|
+
*/
|
|
15
|
+
import { realpathSync, statSync } from "node:fs";
|
|
16
|
+
import { isAbsolute } from "node:path";
|
|
17
|
+
import { SessionContexts } from "./context.js";
|
|
18
|
+
import { fail } from "./errors.js";
|
|
19
|
+
import { createSessionId, createSessionToken, hashSessionToken, verifySessionToken } from "./identity.js";
|
|
20
|
+
const DefaultLimits = {
|
|
21
|
+
maxSessions: 256,
|
|
22
|
+
maxRootsPerSession: 16,
|
|
23
|
+
maxContextEntries: 256,
|
|
24
|
+
maxContextBytes: 1024 * 1024,
|
|
25
|
+
maxTokenRotations: 8,
|
|
26
|
+
};
|
|
27
|
+
const DefaultDefaults = {
|
|
28
|
+
ttlMs: 8 * 60 * 60 * 1000,
|
|
29
|
+
idleTtlMs: 30 * 60 * 1000,
|
|
30
|
+
label: "session",
|
|
31
|
+
};
|
|
32
|
+
const DefaultPermissions = {
|
|
33
|
+
read: true,
|
|
34
|
+
write: false,
|
|
35
|
+
create: false,
|
|
36
|
+
remove: false,
|
|
37
|
+
maxReadBytes: 8 * 1024 * 1024,
|
|
38
|
+
maxWriteBytes: 4 * 1024 * 1024,
|
|
39
|
+
maxTreeNodes: 20000,
|
|
40
|
+
maxContextEntries: 256,
|
|
41
|
+
maxContextBytes: 1024 * 1024,
|
|
42
|
+
};
|
|
43
|
+
const ControlCharacters = /[\u0000-\u001f\u007f-\u009f]/;
|
|
44
|
+
const SystemClock = { now: () => new Date() };
|
|
45
|
+
const clone = (value) => structuredClone(value);
|
|
46
|
+
/**
|
|
47
|
+
* Reject lone surrogates before a value reaches a store that binds UTF-8:
|
|
48
|
+
* `JSON.stringify` can escape them, but a SQLite/JSON column cannot preserve
|
|
49
|
+
* them, so a restored record would no longer name the same agent or root.
|
|
50
|
+
*/
|
|
51
|
+
const isWellFormed = (value) => {
|
|
52
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
53
|
+
const unit = value.charCodeAt(index);
|
|
54
|
+
if (unit >= 0xd800 && unit <= 0xdbff) {
|
|
55
|
+
const next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0;
|
|
56
|
+
if (next < 0xdc00 || next > 0xdfff) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
index += 1;
|
|
60
|
+
}
|
|
61
|
+
else if (unit >= 0xdc00 && unit <= 0xdfff) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Identifiers, labels and metadata are host text: non-blank, no control
|
|
69
|
+
* characters and well-formed Unicode. There is deliberately no length ceiling
|
|
70
|
+
* here; the explicit 128-code-unit ceiling belongs to context namespaces/keys.
|
|
71
|
+
*/
|
|
72
|
+
const textIsValid = (value) => typeof (value) === "string" && value.trim().length > 0 && !ControlCharacters.test(value) && isWellFormed(value);
|
|
73
|
+
const requireText = (value) => (textIsValid(value) ? value : fail("invalid_arguments"));
|
|
74
|
+
/**
|
|
75
|
+
* A blank label is a host convenience, not an invalid session: it falls back to
|
|
76
|
+
* the configured default. Other bad types still fail loudly.
|
|
77
|
+
*/
|
|
78
|
+
const resolveLabel = (value, fallback) => {
|
|
79
|
+
if (value === (void 0)) {
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
if (typeof (value) === "string" && value.trim().length === 0) {
|
|
83
|
+
return fallback;
|
|
84
|
+
}
|
|
85
|
+
return requireText(value);
|
|
86
|
+
};
|
|
87
|
+
const loadRotationCount = (store, sessionId) => {
|
|
88
|
+
const candidate = store;
|
|
89
|
+
if (typeof (candidate.loadRotations) !== "function") {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
let rotations;
|
|
93
|
+
try {
|
|
94
|
+
rotations = candidate.loadRotations(sessionId);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return fail("store_failure");
|
|
98
|
+
}
|
|
99
|
+
if (rotations === (void 0)) {
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
if (!Number.isSafeInteger(rotations) || rotations < 0) {
|
|
103
|
+
return fail("store_failure");
|
|
104
|
+
}
|
|
105
|
+
return rotations;
|
|
106
|
+
};
|
|
107
|
+
const persistRotationCount = (request) => {
|
|
108
|
+
const candidate = request.store;
|
|
109
|
+
if (typeof (candidate.saveRotations) !== "function") {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
candidate.saveRotations(request.sessionId, request.rotations);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
fail("store_failure");
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Best-effort rollback for a rotation whose descriptor save failed. The
|
|
121
|
+
* original failure is more useful than a rollback failure, so this never
|
|
122
|
+
* throws.
|
|
123
|
+
*/
|
|
124
|
+
const restoreRotationCount = (request) => {
|
|
125
|
+
try {
|
|
126
|
+
persistRotationCount(request);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const requirePositive = (value, fallback) => {
|
|
133
|
+
if (value === (void 0)) {
|
|
134
|
+
return fallback;
|
|
135
|
+
}
|
|
136
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
137
|
+
return fail("invalid_arguments");
|
|
138
|
+
}
|
|
139
|
+
return value;
|
|
140
|
+
};
|
|
141
|
+
const requireNonNegative = (value, fallback) => {
|
|
142
|
+
if (value === (void 0)) {
|
|
143
|
+
return fallback;
|
|
144
|
+
}
|
|
145
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
146
|
+
return fail("invalid_arguments");
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
};
|
|
150
|
+
const requireFlag = (value, fallback) => {
|
|
151
|
+
if (value === (void 0)) {
|
|
152
|
+
return fallback;
|
|
153
|
+
}
|
|
154
|
+
if (typeof (value) !== "boolean") {
|
|
155
|
+
return fail("invalid_arguments");
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
};
|
|
159
|
+
const parseTime = (value) => {
|
|
160
|
+
const parsed = Date.parse(value);
|
|
161
|
+
return Number.isFinite(parsed) ? parsed : (void 0);
|
|
162
|
+
};
|
|
163
|
+
const MaxDateMs = 8_640_000_000_000_000;
|
|
164
|
+
/**
|
|
165
|
+
* Convert epoch milliseconds to an ISO timestamp. A duration large enough to
|
|
166
|
+
* leave the `Date` range is an argument error, not a `RangeError` that escapes
|
|
167
|
+
* the closed error taxonomy.
|
|
168
|
+
*/
|
|
169
|
+
const isoAt = (milliseconds) => {
|
|
170
|
+
if (!Number.isFinite(milliseconds) || milliseconds < -MaxDateMs || milliseconds > MaxDateMs) {
|
|
171
|
+
return fail("invalid_arguments");
|
|
172
|
+
}
|
|
173
|
+
return new Date(milliseconds).toISOString();
|
|
174
|
+
};
|
|
175
|
+
const isDue = (descriptor, nowMs) => {
|
|
176
|
+
const expires = parseTime(descriptor.expiresAt);
|
|
177
|
+
if (expires === (void 0) || nowMs >= expires) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
const idle = parseTime(descriptor.idleExpiresAt);
|
|
181
|
+
return idle === (void 0) || nowMs >= idle;
|
|
182
|
+
};
|
|
183
|
+
const normalizeExclude = (input) => {
|
|
184
|
+
if (input === (void 0)) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
if (!Array.isArray(input)) {
|
|
188
|
+
return fail("invalid_arguments");
|
|
189
|
+
}
|
|
190
|
+
const seen = new Set();
|
|
191
|
+
const excludes = [];
|
|
192
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
193
|
+
const entry = input[index];
|
|
194
|
+
if (typeof (entry) !== "string" || ControlCharacters.test(entry) || !isWellFormed(entry)) {
|
|
195
|
+
return fail("invalid_arguments");
|
|
196
|
+
}
|
|
197
|
+
const normalized = entry
|
|
198
|
+
.trim()
|
|
199
|
+
.replace(/\\/g, "/")
|
|
200
|
+
.replace(/^\.?\//, "")
|
|
201
|
+
.replace(/^\/+/, "")
|
|
202
|
+
.replace(/\/+$/, "");
|
|
203
|
+
if (normalized.length === 0 || seen.has(normalized)) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
seen.add(normalized);
|
|
207
|
+
excludes.push(normalized);
|
|
208
|
+
}
|
|
209
|
+
return excludes;
|
|
210
|
+
};
|
|
211
|
+
const pathIdentity = (value) => (process.platform === "win32" ? value.toLowerCase() : value);
|
|
212
|
+
const normalizeMetadata = (input) => {
|
|
213
|
+
if (input === (void 0)) {
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
if (input === null || typeof (input) !== "object" || Array.isArray(input)) {
|
|
217
|
+
return fail("invalid_arguments");
|
|
218
|
+
}
|
|
219
|
+
const source = input;
|
|
220
|
+
const keys = Object.keys(source);
|
|
221
|
+
const metadata = {};
|
|
222
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
223
|
+
const key = keys[index];
|
|
224
|
+
const value = source[key];
|
|
225
|
+
if (key.length === 0 || ControlCharacters.test(key) || !isWellFormed(key) || typeof (value) !== "string" || !isWellFormed(value)) {
|
|
226
|
+
return fail("invalid_arguments");
|
|
227
|
+
}
|
|
228
|
+
metadata[key] = value;
|
|
229
|
+
}
|
|
230
|
+
return metadata;
|
|
231
|
+
};
|
|
232
|
+
const resolvePermissions = (options) => {
|
|
233
|
+
const source = options.input ?? {};
|
|
234
|
+
return {
|
|
235
|
+
read: requireFlag(source.read, DefaultPermissions.read),
|
|
236
|
+
write: requireFlag(source.write, DefaultPermissions.write),
|
|
237
|
+
create: requireFlag(source.create, DefaultPermissions.create),
|
|
238
|
+
remove: requireFlag(source.remove, DefaultPermissions.remove),
|
|
239
|
+
maxReadBytes: requirePositive(source.maxReadBytes, DefaultPermissions.maxReadBytes),
|
|
240
|
+
maxWriteBytes: requirePositive(source.maxWriteBytes, DefaultPermissions.maxWriteBytes),
|
|
241
|
+
maxTreeNodes: requirePositive(source.maxTreeNodes, DefaultPermissions.maxTreeNodes),
|
|
242
|
+
maxContextEntries: Math.min(requirePositive(source.maxContextEntries, DefaultPermissions.maxContextEntries), options.limits.maxContextEntries),
|
|
243
|
+
maxContextBytes: Math.min(requirePositive(source.maxContextBytes, DefaultPermissions.maxContextBytes), options.limits.maxContextBytes),
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
export class SessionRegistry {
|
|
247
|
+
context;
|
|
248
|
+
limits;
|
|
249
|
+
defaults;
|
|
250
|
+
store;
|
|
251
|
+
clock;
|
|
252
|
+
records = new Map();
|
|
253
|
+
constructor(options = {}) {
|
|
254
|
+
this.limits = {
|
|
255
|
+
maxSessions: requirePositive(options.limits?.maxSessions, DefaultLimits.maxSessions),
|
|
256
|
+
maxRootsPerSession: requirePositive(options.limits?.maxRootsPerSession, DefaultLimits.maxRootsPerSession),
|
|
257
|
+
maxContextEntries: requirePositive(options.limits?.maxContextEntries, DefaultLimits.maxContextEntries),
|
|
258
|
+
maxContextBytes: requirePositive(options.limits?.maxContextBytes, DefaultLimits.maxContextBytes),
|
|
259
|
+
maxTokenRotations: requireNonNegative(options.limits?.maxTokenRotations, DefaultLimits.maxTokenRotations),
|
|
260
|
+
};
|
|
261
|
+
this.defaults = {
|
|
262
|
+
ttlMs: requirePositive(options.defaults?.ttlMs, DefaultDefaults.ttlMs),
|
|
263
|
+
idleTtlMs: requirePositive(options.defaults?.idleTtlMs, DefaultDefaults.idleTtlMs),
|
|
264
|
+
label: options.defaults?.label === (void 0) ? DefaultDefaults.label : requireText(options.defaults.label),
|
|
265
|
+
};
|
|
266
|
+
this.store = options.store;
|
|
267
|
+
this.clock = options.clock ?? SystemClock;
|
|
268
|
+
this.context = new SessionContexts({
|
|
269
|
+
persistence: options.contextStore,
|
|
270
|
+
clock: this.clock,
|
|
271
|
+
limits: { maxContextEntries: this.limits.maxContextEntries, maxContextBytes: this.limits.maxContextBytes },
|
|
272
|
+
});
|
|
273
|
+
this.restore();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Open a new session. Roots are resolved through `realpathSync` once, at
|
|
277
|
+
* this boundary, so replacing a parent directory later cannot move an
|
|
278
|
+
* already-authorized root. The raw token is returned exactly once.
|
|
279
|
+
*/
|
|
280
|
+
open(input) {
|
|
281
|
+
if (input === null || typeof (input) !== "object") {
|
|
282
|
+
return fail("invalid_arguments");
|
|
283
|
+
}
|
|
284
|
+
const agentId = requireText(input.agentId);
|
|
285
|
+
const roots = this.normalizeRoots(input.roots);
|
|
286
|
+
const permissions = resolvePermissions({ input: input.permissions, limits: this.limits });
|
|
287
|
+
const label = resolveLabel(input.label, this.defaults.label);
|
|
288
|
+
const ttlMs = requirePositive(input.ttlMs, this.defaults.ttlMs);
|
|
289
|
+
const idleTtlMs = requirePositive(input.idleTtlMs, this.defaults.idleTtlMs);
|
|
290
|
+
const metadata = normalizeMetadata(input.metadata);
|
|
291
|
+
const parentId = input.parentId === (void 0) ? (void 0) : requireText(input.parentId);
|
|
292
|
+
this.assertCapacity();
|
|
293
|
+
const now = this.clock.now();
|
|
294
|
+
const nowMs = now.getTime();
|
|
295
|
+
const expiresAt = isoAt(nowMs + ttlMs);
|
|
296
|
+
const idleExpiresAt = isoAt(Math.min(nowMs + idleTtlMs, nowMs + ttlMs));
|
|
297
|
+
const sessionId = createSessionId();
|
|
298
|
+
const token = createSessionToken();
|
|
299
|
+
const tokenHash = hashSessionToken(token);
|
|
300
|
+
const descriptor = {
|
|
301
|
+
id: sessionId,
|
|
302
|
+
agentId,
|
|
303
|
+
label,
|
|
304
|
+
status: "active",
|
|
305
|
+
roots,
|
|
306
|
+
permissions,
|
|
307
|
+
createdAt: now.toISOString(),
|
|
308
|
+
expiresAt,
|
|
309
|
+
idleExpiresAt,
|
|
310
|
+
revision: 0,
|
|
311
|
+
...(parentId === (void 0) ? {} : { parentId }),
|
|
312
|
+
metadata,
|
|
313
|
+
};
|
|
314
|
+
this.persist(descriptor, tokenHash);
|
|
315
|
+
this.records.set(sessionId, { descriptor: clone(descriptor), tokenHash, rotations: 0, idleTtlMs });
|
|
316
|
+
return { descriptor: clone(descriptor), credential: { sessionId, token } };
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Verify a bearer token and refresh the idle deadline. The absolute deadline
|
|
320
|
+
* is never extended; a successful call advances `revision` and is persisted.
|
|
321
|
+
*/
|
|
322
|
+
authenticate(sessionId, token) {
|
|
323
|
+
const record = this.require(sessionId);
|
|
324
|
+
const now = this.clock.now();
|
|
325
|
+
const nowMs = now.getTime();
|
|
326
|
+
if (record.descriptor.status === "revoked") {
|
|
327
|
+
return fail("session_revoked");
|
|
328
|
+
}
|
|
329
|
+
if (record.descriptor.status === "expired") {
|
|
330
|
+
return fail("session_expired");
|
|
331
|
+
}
|
|
332
|
+
if (isDue(record.descriptor, nowMs)) {
|
|
333
|
+
this.markExpired(record);
|
|
334
|
+
return fail("session_expired");
|
|
335
|
+
}
|
|
336
|
+
if (record.descriptor.status === "suspended") {
|
|
337
|
+
return fail("session_suspended");
|
|
338
|
+
}
|
|
339
|
+
const storedHash = record.tokenHash;
|
|
340
|
+
if (storedHash === (void 0) || !verifySessionToken(token, storedHash)) {
|
|
341
|
+
return fail("invalid_identity");
|
|
342
|
+
}
|
|
343
|
+
const expiresMs = parseTime(record.descriptor.expiresAt);
|
|
344
|
+
const idleMs = expiresMs === (void 0) ? nowMs : Math.min(nowMs + record.idleTtlMs, expiresMs);
|
|
345
|
+
record.descriptor = {
|
|
346
|
+
...record.descriptor,
|
|
347
|
+
idleExpiresAt: isoAt(idleMs),
|
|
348
|
+
revision: record.descriptor.revision + 1,
|
|
349
|
+
};
|
|
350
|
+
this.saveRecord(record);
|
|
351
|
+
return { descriptor: clone(record.descriptor), tokenHash: storedHash };
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Host-side descriptor lookup. It is safe to call for an expired or revoked
|
|
355
|
+
* session: the terminal status is returned for audit rather than revived.
|
|
356
|
+
* `authenticate` is the operation that refuses terminal sessions.
|
|
357
|
+
*/
|
|
358
|
+
get(sessionId) {
|
|
359
|
+
const record = this.require(sessionId);
|
|
360
|
+
this.expireIfDue(record, this.clock.now().getTime());
|
|
361
|
+
return clone(record.descriptor);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* List descriptors, optionally filtered to one agent. Terminal records are
|
|
365
|
+
* included; a host that needs only live sessions filters on `status`.
|
|
366
|
+
*/
|
|
367
|
+
list(agentId) {
|
|
368
|
+
const records = [...this.records.values()];
|
|
369
|
+
const descriptors = [];
|
|
370
|
+
for (let index = 0; index < records.length; index += 1) {
|
|
371
|
+
const descriptor = records[index].descriptor;
|
|
372
|
+
if (agentId !== (void 0) && descriptor.agentId !== agentId) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
descriptors.push(clone(descriptor));
|
|
376
|
+
}
|
|
377
|
+
descriptors.sort((left, right) => {
|
|
378
|
+
if (left.createdAt === right.createdAt) {
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
381
|
+
return left.createdAt < right.createdAt ? -1 : 1;
|
|
382
|
+
});
|
|
383
|
+
return descriptors;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Diagnostics summary for one session. Terminal sessions stay inspectable.
|
|
387
|
+
*/
|
|
388
|
+
summary(sessionId) {
|
|
389
|
+
const record = this.require(sessionId);
|
|
390
|
+
const now = this.clock.now();
|
|
391
|
+
this.expireIfDue(record, now.getTime());
|
|
392
|
+
const descriptor = record.descriptor;
|
|
393
|
+
const expiresMs = parseTime(descriptor.expiresAt);
|
|
394
|
+
const live = descriptor.status === "active" || descriptor.status === "suspended";
|
|
395
|
+
const remainingMs = live && expiresMs !== (void 0) ? Math.max(0, expiresMs - now.getTime()) : 0;
|
|
396
|
+
const roots = descriptor.roots.map((root) => ({
|
|
397
|
+
id: root.id,
|
|
398
|
+
writable: root.writable,
|
|
399
|
+
}));
|
|
400
|
+
return {
|
|
401
|
+
id: descriptor.id,
|
|
402
|
+
agentId: descriptor.agentId,
|
|
403
|
+
label: descriptor.label,
|
|
404
|
+
status: descriptor.status,
|
|
405
|
+
roots,
|
|
406
|
+
createdAt: descriptor.createdAt,
|
|
407
|
+
expiresAt: descriptor.expiresAt,
|
|
408
|
+
remainingMs,
|
|
409
|
+
revision: descriptor.revision,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Refresh the idle deadline for an active session without checking a token.
|
|
414
|
+
* Host-only keepalive; a caller that needs the token path uses
|
|
415
|
+
* `authenticate`.
|
|
416
|
+
*/
|
|
417
|
+
touch(sessionId) {
|
|
418
|
+
const record = this.require(sessionId);
|
|
419
|
+
const now = this.clock.now();
|
|
420
|
+
this.expireIfDue(record, now.getTime());
|
|
421
|
+
if (record.descriptor.status === "revoked") {
|
|
422
|
+
return fail("session_revoked");
|
|
423
|
+
}
|
|
424
|
+
if (record.descriptor.status === "expired") {
|
|
425
|
+
return fail("session_expired");
|
|
426
|
+
}
|
|
427
|
+
if (record.descriptor.status === "suspended") {
|
|
428
|
+
return fail("session_suspended");
|
|
429
|
+
}
|
|
430
|
+
const expiresMs = parseTime(record.descriptor.expiresAt);
|
|
431
|
+
if (expiresMs === (void 0)) {
|
|
432
|
+
this.markExpired(record);
|
|
433
|
+
return fail("session_expired");
|
|
434
|
+
}
|
|
435
|
+
record.descriptor = {
|
|
436
|
+
...record.descriptor,
|
|
437
|
+
idleExpiresAt: isoAt(Math.min(now.getTime() + record.idleTtlMs, expiresMs)),
|
|
438
|
+
revision: record.descriptor.revision + 1,
|
|
439
|
+
};
|
|
440
|
+
this.saveRecord(record);
|
|
441
|
+
return clone(record.descriptor);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Suspend an active session. Suspending an already suspended session is
|
|
445
|
+
* idempotent; terminal sessions are never revived.
|
|
446
|
+
*/
|
|
447
|
+
suspend(sessionId) {
|
|
448
|
+
const record = this.require(sessionId);
|
|
449
|
+
this.expireIfDue(record, this.clock.now().getTime());
|
|
450
|
+
if (record.descriptor.status === "revoked") {
|
|
451
|
+
return fail("session_revoked");
|
|
452
|
+
}
|
|
453
|
+
if (record.descriptor.status === "expired") {
|
|
454
|
+
return fail("session_expired");
|
|
455
|
+
}
|
|
456
|
+
if (record.descriptor.status === "suspended") {
|
|
457
|
+
return clone(record.descriptor);
|
|
458
|
+
}
|
|
459
|
+
record.descriptor = { ...record.descriptor, status: "suspended", revision: record.descriptor.revision + 1 };
|
|
460
|
+
this.saveRecord(record);
|
|
461
|
+
return clone(record.descriptor);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Resume a suspended session. Only the absolute deadline blocks a resume;
|
|
465
|
+
* the idle deadline is refreshed by this call, so a host that explicitly
|
|
466
|
+
* reactivates a session does not have to race the idle timer.
|
|
467
|
+
*/
|
|
468
|
+
resume(sessionId) {
|
|
469
|
+
const record = this.require(sessionId);
|
|
470
|
+
const now = this.clock.now();
|
|
471
|
+
if (record.descriptor.status === "revoked") {
|
|
472
|
+
return fail("session_revoked");
|
|
473
|
+
}
|
|
474
|
+
if (record.descriptor.status === "expired") {
|
|
475
|
+
return fail("session_expired");
|
|
476
|
+
}
|
|
477
|
+
if (record.descriptor.status !== "suspended") {
|
|
478
|
+
return fail("session_forbidden");
|
|
479
|
+
}
|
|
480
|
+
const expiresMs = parseTime(record.descriptor.expiresAt);
|
|
481
|
+
if (expiresMs === (void 0) || now.getTime() >= expiresMs) {
|
|
482
|
+
this.markExpired(record);
|
|
483
|
+
return fail("session_expired");
|
|
484
|
+
}
|
|
485
|
+
record.descriptor = {
|
|
486
|
+
...record.descriptor,
|
|
487
|
+
status: "active",
|
|
488
|
+
idleExpiresAt: isoAt(Math.min(now.getTime() + record.idleTtlMs, expiresMs)),
|
|
489
|
+
revision: record.descriptor.revision + 1,
|
|
490
|
+
};
|
|
491
|
+
this.saveRecord(record);
|
|
492
|
+
return clone(record.descriptor);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Revoke a session permanently. The descriptor and context are retained for
|
|
496
|
+
* audit, but the stored secret is replaced with an empty hash, so a restored
|
|
497
|
+
* registry cannot authenticate the old token either. `authenticate` checks
|
|
498
|
+
* `revoked` before the token, which makes the failure unambiguous. A session
|
|
499
|
+
* whose deadline has already passed is reported as `session_expired`; the
|
|
500
|
+
* host uses `close` to remove it.
|
|
501
|
+
*/
|
|
502
|
+
revoke(sessionId) {
|
|
503
|
+
const record = this.require(sessionId);
|
|
504
|
+
this.expireIfDue(record, this.clock.now().getTime());
|
|
505
|
+
if (record.descriptor.status === "revoked") {
|
|
506
|
+
return clone(record.descriptor);
|
|
507
|
+
}
|
|
508
|
+
if (record.descriptor.status === "expired") {
|
|
509
|
+
return fail("session_expired");
|
|
510
|
+
}
|
|
511
|
+
record.descriptor = { ...record.descriptor, status: "revoked", revision: record.descriptor.revision + 1 };
|
|
512
|
+
record.tokenHash = (void 0);
|
|
513
|
+
this.saveRecord(record);
|
|
514
|
+
return clone(record.descriptor);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Replace the bearer token, invalidating the previous one immediately.
|
|
518
|
+
* Active and suspended sessions may rotate, up to `maxTokenRotations`. When
|
|
519
|
+
* the store implements {@link SessionRotationStore}, the counter is persisted
|
|
520
|
+
* before the descriptor so a restart keeps the same budget.
|
|
521
|
+
*/
|
|
522
|
+
rotate(sessionId) {
|
|
523
|
+
const record = this.require(sessionId);
|
|
524
|
+
this.expireIfDue(record, this.clock.now().getTime());
|
|
525
|
+
if (record.descriptor.status === "revoked") {
|
|
526
|
+
return fail("session_revoked");
|
|
527
|
+
}
|
|
528
|
+
if (record.descriptor.status === "expired") {
|
|
529
|
+
return fail("session_expired");
|
|
530
|
+
}
|
|
531
|
+
if (record.rotations >= this.limits.maxTokenRotations) {
|
|
532
|
+
return fail("session_forbidden");
|
|
533
|
+
}
|
|
534
|
+
const previousHash = record.tokenHash;
|
|
535
|
+
const previousRevision = record.descriptor.revision;
|
|
536
|
+
const previousRotations = record.rotations;
|
|
537
|
+
const token = createSessionToken();
|
|
538
|
+
const tokenHash = hashSessionToken(token);
|
|
539
|
+
record.tokenHash = tokenHash;
|
|
540
|
+
record.rotations = previousRotations + 1;
|
|
541
|
+
record.descriptor = { ...record.descriptor, revision: record.descriptor.revision + 1 };
|
|
542
|
+
const store = this.store;
|
|
543
|
+
try {
|
|
544
|
+
if (store !== (void 0)) {
|
|
545
|
+
persistRotationCount({ store, sessionId: record.descriptor.id, rotations: record.rotations });
|
|
546
|
+
}
|
|
547
|
+
this.saveRecord(record);
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
if (store !== (void 0)) {
|
|
551
|
+
restoreRotationCount({ store, sessionId: record.descriptor.id, rotations: previousRotations });
|
|
552
|
+
}
|
|
553
|
+
record.tokenHash = previousHash;
|
|
554
|
+
record.rotations = previousRotations;
|
|
555
|
+
record.descriptor = { ...record.descriptor, revision: previousRevision };
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
return { sessionId: record.descriptor.id, token };
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Fork an active session. The child copies roots, permissions and context
|
|
562
|
+
* by value, gets a fresh id and token, and cannot outlive the absolute
|
|
563
|
+
* deadline of its parent.
|
|
564
|
+
*/
|
|
565
|
+
fork(parentId, input = {}) {
|
|
566
|
+
const parent = this.require(parentId);
|
|
567
|
+
const now = this.clock.now();
|
|
568
|
+
this.expireIfDue(parent, now.getTime());
|
|
569
|
+
if (parent.descriptor.status === "revoked") {
|
|
570
|
+
return fail("session_revoked");
|
|
571
|
+
}
|
|
572
|
+
if (parent.descriptor.status === "expired") {
|
|
573
|
+
return fail("session_expired");
|
|
574
|
+
}
|
|
575
|
+
if (parent.descriptor.status !== "active") {
|
|
576
|
+
return fail("session_suspended");
|
|
577
|
+
}
|
|
578
|
+
if (input === null || typeof (input) !== "object") {
|
|
579
|
+
return fail("invalid_arguments");
|
|
580
|
+
}
|
|
581
|
+
const ttlMs = requirePositive(input.ttlMs, this.defaults.ttlMs);
|
|
582
|
+
const label = resolveLabel(input.label, this.defaults.label);
|
|
583
|
+
const metadata = input.metadata === (void 0) ? clone(parent.descriptor.metadata) : normalizeMetadata(input.metadata);
|
|
584
|
+
this.assertCapacity();
|
|
585
|
+
const nowMs = now.getTime();
|
|
586
|
+
const parentExpiresMs = parseTime(parent.descriptor.expiresAt);
|
|
587
|
+
const expiresMs = parentExpiresMs === (void 0) ? nowMs + ttlMs : Math.min(nowMs + ttlMs, parentExpiresMs);
|
|
588
|
+
if (expiresMs <= nowMs) {
|
|
589
|
+
this.markExpired(parent);
|
|
590
|
+
return fail("session_expired");
|
|
591
|
+
}
|
|
592
|
+
const idleTtlMs = parent.idleTtlMs;
|
|
593
|
+
const sessionId = createSessionId();
|
|
594
|
+
const token = createSessionToken();
|
|
595
|
+
const tokenHash = hashSessionToken(token);
|
|
596
|
+
const descriptor = {
|
|
597
|
+
id: sessionId,
|
|
598
|
+
agentId: parent.descriptor.agentId,
|
|
599
|
+
label,
|
|
600
|
+
status: "active",
|
|
601
|
+
roots: clone(parent.descriptor.roots),
|
|
602
|
+
permissions: clone(parent.descriptor.permissions),
|
|
603
|
+
createdAt: now.toISOString(),
|
|
604
|
+
expiresAt: isoAt(expiresMs),
|
|
605
|
+
idleExpiresAt: isoAt(Math.min(nowMs + idleTtlMs, expiresMs)),
|
|
606
|
+
revision: 0,
|
|
607
|
+
parentId: parent.descriptor.id,
|
|
608
|
+
metadata,
|
|
609
|
+
};
|
|
610
|
+
this.context.fork(parent.descriptor.id, sessionId);
|
|
611
|
+
try {
|
|
612
|
+
this.persist(descriptor, tokenHash);
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
this.discardContext(sessionId);
|
|
616
|
+
throw error;
|
|
617
|
+
}
|
|
618
|
+
this.records.set(sessionId, { descriptor: clone(descriptor), tokenHash, rotations: 0, idleTtlMs });
|
|
619
|
+
return { descriptor: clone(descriptor), credential: { sessionId, token } };
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Lazily expire every active or suspended session whose absolute or idle
|
|
623
|
+
* deadline has passed. Returns the number of transitions performed.
|
|
624
|
+
*/
|
|
625
|
+
sweep(now = this.clock.now()) {
|
|
626
|
+
const nowMs = now.getTime();
|
|
627
|
+
const records = [...this.records.values()];
|
|
628
|
+
let expired = 0;
|
|
629
|
+
for (let index = 0; index < records.length; index += 1) {
|
|
630
|
+
const record = records[index];
|
|
631
|
+
if (record.descriptor.status !== "active" && record.descriptor.status !== "suspended") {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (!isDue(record.descriptor, nowMs)) {
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
this.markExpired(record);
|
|
638
|
+
expired += 1;
|
|
639
|
+
}
|
|
640
|
+
return expired;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Revoke and forget a session: descriptor index, context and persisted row
|
|
644
|
+
* are removed. `revoke` is the audit-friendly variant that keeps the
|
|
645
|
+
* descriptor; `close` is the end-of-life cleanup.
|
|
646
|
+
*/
|
|
647
|
+
close(sessionId) {
|
|
648
|
+
const record = this.require(sessionId);
|
|
649
|
+
if (record.descriptor.status !== "revoked") {
|
|
650
|
+
record.descriptor = { ...record.descriptor, status: "revoked", revision: record.descriptor.revision + 1 };
|
|
651
|
+
record.tokenHash = (void 0);
|
|
652
|
+
this.saveRecord(record);
|
|
653
|
+
}
|
|
654
|
+
this.context.remove(record.descriptor.id);
|
|
655
|
+
this.deletePersisted(record.descriptor.id);
|
|
656
|
+
this.records.delete(record.descriptor.id);
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Load persisted descriptors and token hashes at construction. Terminal
|
|
660
|
+
* statuses are preserved exactly. The descriptor carries only the idle
|
|
661
|
+
* deadline, not the configured idle window, so the window is recovered from
|
|
662
|
+
* `idleExpiresAt - createdAt` and capped by the current registry default; a
|
|
663
|
+
* persisted store that exceeds `maxSessions` is rejected rather than
|
|
664
|
+
* silently breaking the capacity invariant.
|
|
665
|
+
*/
|
|
666
|
+
restore() {
|
|
667
|
+
const store = this.store;
|
|
668
|
+
if (store === (void 0) || typeof (store.list) !== "function") {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
let listed;
|
|
672
|
+
try {
|
|
673
|
+
listed = store.list();
|
|
674
|
+
}
|
|
675
|
+
catch {
|
|
676
|
+
return fail("store_failure");
|
|
677
|
+
}
|
|
678
|
+
if (!Array.isArray(listed)) {
|
|
679
|
+
return fail("store_failure");
|
|
680
|
+
}
|
|
681
|
+
for (let index = 0; index < listed.length; index += 1) {
|
|
682
|
+
const descriptor = listed[index];
|
|
683
|
+
if (!this.storedDescriptorIsValid(descriptor)) {
|
|
684
|
+
return fail("store_failure");
|
|
685
|
+
}
|
|
686
|
+
let secret;
|
|
687
|
+
try {
|
|
688
|
+
secret = typeof (store.loadSecret) === "function" ? store.loadSecret(descriptor.id) : (void 0);
|
|
689
|
+
}
|
|
690
|
+
catch {
|
|
691
|
+
return fail("store_failure");
|
|
692
|
+
}
|
|
693
|
+
const createdMs = parseTime(descriptor.createdAt);
|
|
694
|
+
const idleExpiresMs = parseTime(descriptor.idleExpiresAt);
|
|
695
|
+
const idleWindow = createdMs === (void 0) || idleExpiresMs === (void 0) ? 0 : idleExpiresMs - createdMs;
|
|
696
|
+
this.records.set(descriptor.id, {
|
|
697
|
+
descriptor: clone(descriptor),
|
|
698
|
+
tokenHash: typeof (secret) === "string" && secret.length > 0 ? secret : (void 0),
|
|
699
|
+
rotations: loadRotationCount(store, descriptor.id),
|
|
700
|
+
idleTtlMs: idleWindow > 0 ? Math.min(this.defaults.idleTtlMs, idleWindow) : this.defaults.idleTtlMs,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
if (this.records.size > this.limits.maxSessions) {
|
|
704
|
+
return fail("session_capacity");
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
storedDescriptorIsValid(descriptor) {
|
|
708
|
+
try {
|
|
709
|
+
if (descriptor === null || typeof (descriptor) !== "object" || Array.isArray(descriptor)) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
const status = descriptor.status;
|
|
713
|
+
if (!textIsValid(descriptor.id) ||
|
|
714
|
+
!textIsValid(descriptor.agentId) ||
|
|
715
|
+
!textIsValid(descriptor.label) ||
|
|
716
|
+
(status !== "active" && status !== "suspended" && status !== "revoked" && status !== "expired") ||
|
|
717
|
+
!Number.isSafeInteger(descriptor.revision) ||
|
|
718
|
+
descriptor.revision < 0) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
const created = parseTime(descriptor.createdAt);
|
|
722
|
+
const expires = parseTime(descriptor.expiresAt);
|
|
723
|
+
const idleExpires = parseTime(descriptor.idleExpiresAt);
|
|
724
|
+
if (created === (void 0) || expires === (void 0) || idleExpires === (void 0) || expires < created || idleExpires > expires) {
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
if (descriptor.parentId !== (void 0) && !textIsValid(descriptor.parentId)) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
if (!Array.isArray(descriptor.roots) || descriptor.roots.length === 0 || descriptor.roots.length > this.limits.maxRootsPerSession) {
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
const rootIds = new Set();
|
|
734
|
+
const rootPaths = new Set();
|
|
735
|
+
for (let index = 0; index < descriptor.roots.length; index += 1) {
|
|
736
|
+
const root = descriptor.roots[index];
|
|
737
|
+
if (root === null ||
|
|
738
|
+
typeof (root) !== "object" ||
|
|
739
|
+
!textIsValid(root.id) ||
|
|
740
|
+
rootIds.has(root.id) ||
|
|
741
|
+
typeof (root.path) !== "string" ||
|
|
742
|
+
!isAbsolute(root.path) ||
|
|
743
|
+
typeof (root.writable) !== "boolean" ||
|
|
744
|
+
!Array.isArray(root.exclude) ||
|
|
745
|
+
root.exclude.some((entry) => typeof (entry) !== "string" || ControlCharacters.test(entry) || !isWellFormed(entry))) {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
let resolved;
|
|
749
|
+
if (!statSync(root.path).isDirectory()) {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
resolved = realpathSync(root.path);
|
|
753
|
+
if (pathIdentity(resolved) !== pathIdentity(root.path) || rootPaths.has(pathIdentity(resolved))) {
|
|
754
|
+
return false;
|
|
755
|
+
}
|
|
756
|
+
rootIds.add(root.id);
|
|
757
|
+
rootPaths.add(pathIdentity(resolved));
|
|
758
|
+
}
|
|
759
|
+
const permissions = descriptor.permissions;
|
|
760
|
+
if (permissions === null || typeof (permissions) !== "object" || Array.isArray(permissions)) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
const flags = [permissions.read, permissions.write, permissions.create, permissions.remove];
|
|
764
|
+
if (flags.some((flag) => typeof (flag) !== "boolean")) {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
const permissionLimits = [
|
|
768
|
+
permissions.maxReadBytes,
|
|
769
|
+
permissions.maxWriteBytes,
|
|
770
|
+
permissions.maxTreeNodes,
|
|
771
|
+
permissions.maxContextEntries,
|
|
772
|
+
permissions.maxContextBytes,
|
|
773
|
+
];
|
|
774
|
+
if (permissionLimits.some((limit) => !Number.isSafeInteger(limit) || limit < 1)) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
if (permissions.maxContextEntries > this.limits.maxContextEntries || permissions.maxContextBytes > this.limits.maxContextBytes) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
const metadata = descriptor.metadata;
|
|
781
|
+
if (metadata === null || typeof (metadata) !== "object" || Array.isArray(metadata)) {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
return Object.entries(metadata).every(([key, value]) => key.length > 0 && !ControlCharacters.test(key) && isWellFormed(key) && typeof (value) === "string" && isWellFormed(value));
|
|
785
|
+
}
|
|
786
|
+
catch {
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
normalizeRoots(input) {
|
|
791
|
+
if (!Array.isArray(input) || input.length === 0 || input.length > this.limits.maxRootsPerSession) {
|
|
792
|
+
return fail("invalid_arguments");
|
|
793
|
+
}
|
|
794
|
+
const seen = new Set();
|
|
795
|
+
const seenPaths = new Set();
|
|
796
|
+
const roots = [];
|
|
797
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
798
|
+
const root = input[index];
|
|
799
|
+
if (root === null || typeof (root) !== "object") {
|
|
800
|
+
return fail("invalid_arguments");
|
|
801
|
+
}
|
|
802
|
+
const id = requireText(root.id);
|
|
803
|
+
if (seen.has(id)) {
|
|
804
|
+
return fail("invalid_arguments");
|
|
805
|
+
}
|
|
806
|
+
seen.add(id);
|
|
807
|
+
const path = root.path;
|
|
808
|
+
if (typeof (path) !== "string" || path.length === 0 || !isAbsolute(path)) {
|
|
809
|
+
return fail("invalid_arguments");
|
|
810
|
+
}
|
|
811
|
+
let directory;
|
|
812
|
+
try {
|
|
813
|
+
directory = statSync(path).isDirectory();
|
|
814
|
+
}
|
|
815
|
+
catch {
|
|
816
|
+
return fail("invalid_arguments");
|
|
817
|
+
}
|
|
818
|
+
if (!directory) {
|
|
819
|
+
return fail("invalid_arguments");
|
|
820
|
+
}
|
|
821
|
+
let resolved;
|
|
822
|
+
try {
|
|
823
|
+
resolved = realpathSync(path);
|
|
824
|
+
}
|
|
825
|
+
catch {
|
|
826
|
+
return fail("invalid_arguments");
|
|
827
|
+
}
|
|
828
|
+
const identity = pathIdentity(resolved);
|
|
829
|
+
if (seenPaths.has(identity)) {
|
|
830
|
+
return fail("invalid_arguments");
|
|
831
|
+
}
|
|
832
|
+
seenPaths.add(identity);
|
|
833
|
+
roots.push({ id, path: resolved, writable: root.writable === true, exclude: normalizeExclude(root.exclude) });
|
|
834
|
+
}
|
|
835
|
+
return roots;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Capacity counts retained descriptors, including terminal records kept
|
|
839
|
+
* for audit. `close` is the operation that frees a slot.
|
|
840
|
+
*/
|
|
841
|
+
assertCapacity() {
|
|
842
|
+
if (this.records.size >= this.limits.maxSessions) {
|
|
843
|
+
fail("session_capacity");
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
require(sessionId) {
|
|
847
|
+
if (typeof (sessionId) !== "string" || sessionId.length === 0) {
|
|
848
|
+
return fail("session_not_found");
|
|
849
|
+
}
|
|
850
|
+
const record = this.records.get(sessionId);
|
|
851
|
+
return record === (void 0) ? fail("session_not_found") : record;
|
|
852
|
+
}
|
|
853
|
+
expireIfDue(record, nowMs) {
|
|
854
|
+
if (record.descriptor.status !== "active" && record.descriptor.status !== "suspended") {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (isDue(record.descriptor, nowMs)) {
|
|
858
|
+
this.markExpired(record);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
markExpired(record) {
|
|
862
|
+
if (record.descriptor.status === "expired") {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
record.descriptor = { ...record.descriptor, status: "expired", revision: record.descriptor.revision + 1 };
|
|
866
|
+
this.saveRecord(record);
|
|
867
|
+
}
|
|
868
|
+
saveRecord(record) {
|
|
869
|
+
this.persist(record.descriptor, record.tokenHash ?? "");
|
|
870
|
+
}
|
|
871
|
+
persist(descriptor, tokenHash) {
|
|
872
|
+
const store = this.store;
|
|
873
|
+
if (store === (void 0)) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
store.save(clone(descriptor), tokenHash);
|
|
878
|
+
}
|
|
879
|
+
catch {
|
|
880
|
+
fail("store_failure");
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
deletePersisted(sessionId) {
|
|
884
|
+
const store = this.store;
|
|
885
|
+
if (store === (void 0)) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
try {
|
|
889
|
+
store.delete(sessionId);
|
|
890
|
+
}
|
|
891
|
+
catch {
|
|
892
|
+
fail("store_failure");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Best-effort rollback for a fork whose descriptor could not be persisted.
|
|
897
|
+
* The original store error is more useful than a cleanup error, so this
|
|
898
|
+
* never throws.
|
|
899
|
+
*/
|
|
900
|
+
discardContext(sessionId) {
|
|
901
|
+
try {
|
|
902
|
+
this.context.remove(sessionId);
|
|
903
|
+
}
|
|
904
|
+
catch {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|