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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict UTF-8 plus the `text` and `string` policies.
|
|
3
|
+
*
|
|
4
|
+
* `TextEncoder` replaces an unpaired surrogate with U+FFFD, so `"\uD800"` and
|
|
5
|
+
* `"\uFFFD"` would hash identically 鈥?the exact collision this module exists to
|
|
6
|
+
* prevent (the design audit measured it). `encodeUtf8Strict` therefore validates
|
|
7
|
+
* surrogate pairing before it writes a byte and is the only string-to-bytes
|
|
8
|
+
* path in the module; `json.ts`, `file.ts` and `tree.ts` all use it for that
|
|
9
|
+
* reason.
|
|
10
|
+
*
|
|
11
|
+
* The two policies answer two different questions and both are needed:
|
|
12
|
+
*
|
|
13
|
+
* - `text/utf8+nfc+lf` removes presentation differences that carry no content
|
|
14
|
+
* (one leading BOM, CRLF versus LF) and applies NFC, so `"茅"` and `"e\u0301"`
|
|
15
|
+
* are one value. NFC and not NFKC: compatibility decomposition is lossy
|
|
16
|
+
* (`铿乣 becomes `fi`), which would make distinct texts collide on purpose.
|
|
17
|
+
* - `string/utf16-strict` preserves the code units exactly. Sometimes the byte
|
|
18
|
+
* identity is what the caller wants to pin, and a generic `fingerprintOf`
|
|
19
|
+
* dispatcher must not silently normalise what it was given.
|
|
20
|
+
*/
|
|
21
|
+
import { NormalizationRejected } from "./error.js";
|
|
22
|
+
import { Policy } from "./policy.js";
|
|
23
|
+
import { fingerprintPayload } from "./preimage.js";
|
|
24
|
+
const HexRadix = 16;
|
|
25
|
+
const SurrogateHighStart = 0xd800;
|
|
26
|
+
const SurrogateHighEnd = 0xdbff;
|
|
27
|
+
const SurrogateLowStart = 0xdc00;
|
|
28
|
+
const SurrogateLowEnd = 0xdfff;
|
|
29
|
+
const SurrogateBase = 0x10000;
|
|
30
|
+
const hex4 = (value) => value.toString(HexRadix).toUpperCase().padStart(4, "0");
|
|
31
|
+
/**
|
|
32
|
+
* Compute the UTF-8 length of `text` while rejecting any unpaired surrogate.
|
|
33
|
+
*
|
|
34
|
+
* The validation and the measurement happen in one pass because both walk the
|
|
35
|
+
* same code units: a separate validator would double the scans and could drift
|
|
36
|
+
* out of sync with the encoder. The returned length lets the encoder allocate
|
|
37
|
+
* once, so no intermediate array of code points is materialised.
|
|
38
|
+
*/
|
|
39
|
+
const utf8ByteLength = (text) => {
|
|
40
|
+
let length = 0;
|
|
41
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
42
|
+
const unit = text.charCodeAt(index);
|
|
43
|
+
if (unit < 0x80) {
|
|
44
|
+
length += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (unit < 0x800) {
|
|
48
|
+
length += 2;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (unit >= SurrogateHighStart && unit <= SurrogateHighEnd) {
|
|
52
|
+
const next = index + 1 < text.length ? text.charCodeAt(index + 1) : -1;
|
|
53
|
+
if (next < SurrogateLowStart || next > SurrogateLowEnd) {
|
|
54
|
+
throw new NormalizationRejected([`text contains a lone high surrogate U+${hex4(unit)} at index ${index}`]);
|
|
55
|
+
}
|
|
56
|
+
length += 4;
|
|
57
|
+
index += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (unit >= SurrogateLowStart && unit <= SurrogateLowEnd) {
|
|
61
|
+
throw new NormalizationRejected([`text contains a lone low surrogate U+${hex4(unit)} at index ${index}`]);
|
|
62
|
+
}
|
|
63
|
+
length += 3;
|
|
64
|
+
}
|
|
65
|
+
return length;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Encode a JavaScript string as UTF-8 without ever substituting U+FFFD.
|
|
69
|
+
*
|
|
70
|
+
* Two passes: the first measures and validates, the second writes. A paired
|
|
71
|
+
* surrogate is written as one four-byte sequence and the loop skips its low
|
|
72
|
+
* half, so the output is standard UTF-8 (the CESU-8 spelling of a pair would be
|
|
73
|
+
* six bytes and would collide with different text).
|
|
74
|
+
*/
|
|
75
|
+
export const encodeUtf8Strict = (text) => {
|
|
76
|
+
if (typeof (text) !== "string") {
|
|
77
|
+
throw new TypeError(`encodeUtf8Strict expects a string, received ${typeof (text)}`);
|
|
78
|
+
}
|
|
79
|
+
const bytes = new Uint8Array(utf8ByteLength(text));
|
|
80
|
+
let offset = 0;
|
|
81
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
82
|
+
const unit = text.charCodeAt(index);
|
|
83
|
+
if (unit < 0x80) {
|
|
84
|
+
bytes[offset] = unit;
|
|
85
|
+
offset += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (unit < 0x800) {
|
|
89
|
+
bytes[offset] = 0xc0 | (unit >> 6);
|
|
90
|
+
bytes[offset + 1] = 0x80 | (unit & 0x3f);
|
|
91
|
+
offset += 2;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (unit >= SurrogateHighStart && unit <= SurrogateHighEnd) {
|
|
95
|
+
const next = text.charCodeAt(index + 1);
|
|
96
|
+
const codePoint = SurrogateBase + ((unit - SurrogateHighStart) << 10) + (next - SurrogateLowStart);
|
|
97
|
+
bytes[offset] = 0xf0 | (codePoint >> 18);
|
|
98
|
+
bytes[offset + 1] = 0x80 | ((codePoint >> 12) & 0x3f);
|
|
99
|
+
bytes[offset + 2] = 0x80 | ((codePoint >> 6) & 0x3f);
|
|
100
|
+
bytes[offset + 3] = 0x80 | (codePoint & 0x3f);
|
|
101
|
+
offset += 4;
|
|
102
|
+
index += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
bytes[offset] = 0xe0 | (unit >> 12);
|
|
106
|
+
bytes[offset + 1] = 0x80 | ((unit >> 6) & 0x3f);
|
|
107
|
+
bytes[offset + 2] = 0x80 | (unit & 0x3f);
|
|
108
|
+
offset += 3;
|
|
109
|
+
}
|
|
110
|
+
return bytes;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Apply the `text/utf8+nfc+lf` normalisation, in the order the policy name
|
|
114
|
+
* implies: exactly one leading BOM is dropped (interior BOMs are content), CRLF
|
|
115
|
+
* and lone CR become LF, then NFC is applied.
|
|
116
|
+
*
|
|
117
|
+
* NUL is rejected rather than hashed: a NUL inside text truncates every C
|
|
118
|
+
* consumer of the string, so two texts that are equal only up to a NUL would be
|
|
119
|
+
* treated as identical downstream while this module would say they differ.
|
|
120
|
+
* Rejecting keeps the two views aligned.
|
|
121
|
+
*/
|
|
122
|
+
export const normalizeTextNfc = (text) => {
|
|
123
|
+
const withoutBom = text.startsWith("\uFEFF") ? text.slice(1) : text;
|
|
124
|
+
const lfOnly = withoutBom.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
125
|
+
const normalized = lfOnly.normalize("NFC");
|
|
126
|
+
const nulIndex = normalized.indexOf("\u0000");
|
|
127
|
+
if (nulIndex !== -1) {
|
|
128
|
+
throw new NormalizationRejected([`text contains U+0000 at index ${nulIndex}; the text policy forbids NUL`]);
|
|
129
|
+
}
|
|
130
|
+
return normalized;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Fingerprint text under the NFC policy (default) or the raw policy.
|
|
134
|
+
*
|
|
135
|
+
* `raw` still uses the strict encoder: "no normalisation" means no BOM, newline
|
|
136
|
+
* or Unicode folding, not "let the platform substitute replacement characters".
|
|
137
|
+
*/
|
|
138
|
+
export const fingerprintText = (text, options) => {
|
|
139
|
+
const policy = options?.policy ?? "nfc";
|
|
140
|
+
if (policy === "nfc") {
|
|
141
|
+
const payload = encodeUtf8Strict(normalizeTextNfc(text));
|
|
142
|
+
return fingerprintPayload("sha256", "text", Policy.textNfc, payload);
|
|
143
|
+
}
|
|
144
|
+
if (policy === "raw") {
|
|
145
|
+
return fingerprintPayload("sha256", "text", Policy.textRaw, encodeUtf8Strict(text));
|
|
146
|
+
}
|
|
147
|
+
throw new NormalizationRejected([`unknown text policy "${policy}"; expected "nfc" or "raw"`]);
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Fingerprint the exact code units of a string: no BOM stripping, no newline
|
|
151
|
+
* folding, no NFC. `"茅"` (U+00E9) and `"e\u0301"` (e + U+0301) are different
|
|
152
|
+
* strings and therefore different fingerprints, which is the point of having a
|
|
153
|
+
* `string` kind next to `text`.
|
|
154
|
+
*/
|
|
155
|
+
export const fingerprintString = (text) => fingerprintPayload("sha256", "string", Policy.stringStrict, encodeUtf8Strict(text));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AlgorithmId } from "./algorithm.js";
|
|
2
|
+
import type { Fingerprint } from "./preimage.js";
|
|
3
|
+
/**
|
|
4
|
+
* One entry of the tree.
|
|
5
|
+
*
|
|
6
|
+
* `digest` is the *child* digest that goes into the leaf record: the file
|
|
7
|
+
* content digest for a regular file, `sha256(utf8(target))` for a symlink, and
|
|
8
|
+
* `sha256(empty)` for a directory. Keeping the child digest (rather than the
|
|
9
|
+
* leaf digest) means a consumer can compare a file against a CAS object while
|
|
10
|
+
* still being able to rebuild the leaf —and therefore the root —from the
|
|
11
|
+
* returned entries.
|
|
12
|
+
*/
|
|
13
|
+
export interface TreeEntry {
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly digest: string;
|
|
16
|
+
readonly size: number;
|
|
17
|
+
readonly mode: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A tree fingerprint plus its root and per-entry detail.
|
|
21
|
+
*
|
|
22
|
+
* `root` is the canonical tree root in bare lowercase hex; `ref.digest` is the
|
|
23
|
+
* same hex and `digest` is its CAS-compatible `<algorithm>:<hex>` spelling.
|
|
24
|
+
* `bytes` in the reference is the total length of the canonical leaf records
|
|
25
|
+
* that were folded, not the sum of the file sizes: it measures the serialised
|
|
26
|
+
* payload the Merkle tree was built from.
|
|
27
|
+
*/
|
|
28
|
+
export interface TreeFingerprint extends Fingerprint {
|
|
29
|
+
readonly root: string;
|
|
30
|
+
readonly entries: readonly TreeEntry[];
|
|
31
|
+
readonly excluded: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Option shape for `fingerprintTree`.
|
|
35
|
+
*
|
|
36
|
+
* `exclude` replaces the default exclusion set rather than extending it; there
|
|
37
|
+
* would otherwise be no way to fingerprint a directory that contains a
|
|
38
|
+
* `node_modules` folder on purpose. The applied set is echoed in `excluded` so
|
|
39
|
+
* a verifier can see what was in scope.
|
|
40
|
+
*/
|
|
41
|
+
export interface TreeFingerprintOptions {
|
|
42
|
+
readonly exclude?: readonly string[];
|
|
43
|
+
readonly algorithm?: AlgorithmId;
|
|
44
|
+
readonly chunkBytes?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Fingerprint a directory tree.
|
|
48
|
+
*
|
|
49
|
+
* The returned entries are sorted by UTF-8 path bytes and carry the child digest
|
|
50
|
+
* each leaf was built from, so a caller can re-derive the root after changing
|
|
51
|
+
* one file without re-reading the whole tree. The algorithm is fixed to SHA-256
|
|
52
|
+
* in this build: the root composition in `amp.fp/1` is defined in terms of
|
|
53
|
+
* SHA-256, so naming another algorithm here would produce a reference whose
|
|
54
|
+
* verifier cannot exist.
|
|
55
|
+
*/
|
|
56
|
+
export declare const fingerprintTree: (root: string, options?: TreeFingerprintOptions) => Promise<TreeFingerprint>;
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical directory-tree fingerprints: a Merkle tree over a sorted flat leaf
|
|
3
|
+
* list.
|
|
4
|
+
*
|
|
5
|
+
* Hashing a directory is meaningless until its serialisation is defined —tar
|
|
6
|
+
* and zip are not canonical, which is why Nix hashes NAR rather than raw bytes.
|
|
7
|
+
* The serialisation used here is:
|
|
8
|
+
*
|
|
9
|
+
* leaf(pathBytes, mode, size, childDigest)
|
|
10
|
+
* = sha256( 0x00 || u32be(pathBytes.length) || pathBytes
|
|
11
|
+
* || u32be(mode) || u64be(size) || childDigest )
|
|
12
|
+
* node(left, right)
|
|
13
|
+
* = sha256( 0x01 || left || right )
|
|
14
|
+
* root
|
|
15
|
+
* = sha256( 0x02 || u64be(entryCount) || merkleRoot || sha256(utf8(treePolicy)) )
|
|
16
|
+
*
|
|
17
|
+
* The `0x00`/`0x01`/`0x02` prefixes are domain separation in the sense of RFC
|
|
18
|
+
* 6962 §2.1: without them a leaf digest could be replayed as an interior node,
|
|
19
|
+
* which breaks second-preimage resistance. `entryCount` in the root makes `{}`
|
|
20
|
+
* differ from a tree whose only entry is an empty directory even before the
|
|
21
|
+
* leaves are considered, and folding the policy hash into the root binds the
|
|
22
|
+
* exclusion/digest rules to the value.
|
|
23
|
+
*
|
|
24
|
+
* Paths are `/`-separated, relative to the root, and sorted by UTF-8 byte order
|
|
25
|
+
* (`Buffer.compare`), never by locale. `mode` binds the file type and the
|
|
26
|
+
* executable bit; `size` is in the leaf so a verifier compares length before
|
|
27
|
+
* digest, as OCI does. Directories get `sha256(empty)` as their child digest:
|
|
28
|
+
* their content is represented by the leaves of their children, and the leaf's
|
|
29
|
+
* mode field is what keeps the entry from colliding with an empty file at the
|
|
30
|
+
* same path.
|
|
31
|
+
*
|
|
32
|
+
* Symlinks are **never followed**. A symlink is recorded as mode 4 with its
|
|
33
|
+
* target string hashed as the child digest, so a link loop cannot hang the walk
|
|
34
|
+
* and the same tree produces the same root on machines where the link would
|
|
35
|
+
* resolve differently.
|
|
36
|
+
*/
|
|
37
|
+
import { lstatSync, readdirSync, readlinkSync } from "node:fs";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
import { bytesToHex, createSha256, hexToBytes } from "./algorithm.js";
|
|
40
|
+
import { FingerprintIOError, UnsupportedAlgorithm, describeError } from "./error.js";
|
|
41
|
+
import { fileContentDigest, resolveChunkBytes } from "./file.js";
|
|
42
|
+
import { Policy } from "./policy.js";
|
|
43
|
+
import { SchemeName, shortForm } from "./preimage.js";
|
|
44
|
+
import { encodeUtf8Strict } from "./text.js";
|
|
45
|
+
const ModeFile = 1;
|
|
46
|
+
const ModeExecutableFile = 2;
|
|
47
|
+
const ModeDirectory = 3;
|
|
48
|
+
const ModeSymlink = 4;
|
|
49
|
+
const LeafPrefix = 0x00;
|
|
50
|
+
const NodePrefix = 0x01;
|
|
51
|
+
const RootPrefix = 0x02;
|
|
52
|
+
const DigestBytes = 32;
|
|
53
|
+
const LeafFixedBytes = 1 + 4 + 4 + 8 + DigestBytes;
|
|
54
|
+
const NodeBytes = 1 + DigestBytes + DigestBytes;
|
|
55
|
+
const RootFixedBytes = 1 + 8 + DigestBytes + DigestBytes;
|
|
56
|
+
const PathLengthOffset = 1;
|
|
57
|
+
const ModeOffsetBase = 5;
|
|
58
|
+
const SizeOffsetBase = 9;
|
|
59
|
+
const DigestOffsetBase = 17;
|
|
60
|
+
const NodeLeftOffset = 1;
|
|
61
|
+
const NodeRightOffset = 1 + DigestBytes;
|
|
62
|
+
const RootCountOffset = 1;
|
|
63
|
+
const RootMerkleOffset = 9;
|
|
64
|
+
const RootPolicyOffset = 41;
|
|
65
|
+
const Uint32Range = 0x100000000;
|
|
66
|
+
/**
|
|
67
|
+
* Default exclusions. Version-control metadata, dependency trees, caches and
|
|
68
|
+
* build output are not content: including them would make the same source tree
|
|
69
|
+
* produce different roots on two machines. The set is echoed in `excluded`
|
|
70
|
+
* because "what was ignored" changes the digest and has to be auditable.
|
|
71
|
+
*/
|
|
72
|
+
const DefaultExclusions = ["node_modules", ".git", ".cache", "dist", "lib"];
|
|
73
|
+
/**
|
|
74
|
+
* Child digest used for directories, and the Merkle root of an empty tree.
|
|
75
|
+
* Both are `sha256(empty)`, which is unambiguous because the leaf records carry
|
|
76
|
+
* path, mode and size, so a directory entry can never be confused with an empty
|
|
77
|
+
* file entry at a different position.
|
|
78
|
+
*/
|
|
79
|
+
const EmptyDigestHex = bytesToHex(createSha256().digest());
|
|
80
|
+
/**
|
|
81
|
+
* Compare two relative paths by their UTF-8 bytes.
|
|
82
|
+
*
|
|
83
|
+
* `Array.prototype.sort()` compares UTF-16 code units, which orders astral
|
|
84
|
+
* characters before U+E000–U+FFFF; RFC 8785 and every content-addressed format
|
|
85
|
+
* expect byte order. Decoding through `Buffer` is the cheapest way to get it,
|
|
86
|
+
* and `Buffer.compare` returns the sign `sort` needs.
|
|
87
|
+
*/
|
|
88
|
+
const comparePaths = (left, right) => Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"));
|
|
89
|
+
/**
|
|
90
|
+
* Validate the exclusion set once.
|
|
91
|
+
*
|
|
92
|
+
* A pattern is a plain entry name, not a glob and not a path: a value containing
|
|
93
|
+
* a separator would silently exclude nothing, and a silent no-op in an exclusion
|
|
94
|
+
* rule is exactly the kind of mistake that later looks like a digest mismatch.
|
|
95
|
+
*/
|
|
96
|
+
const resolveExclusions = (exclude) => {
|
|
97
|
+
const names = exclude ?? DefaultExclusions;
|
|
98
|
+
const unique = new Set();
|
|
99
|
+
for (let index = 0; index < names.length; index += 1) {
|
|
100
|
+
const name = names[index];
|
|
101
|
+
if (name.length === 0 || name.includes("/") || name.includes("\\")) {
|
|
102
|
+
throw new TypeError(`exclusion "${name}" must be a single path segment without separators`);
|
|
103
|
+
}
|
|
104
|
+
unique.add(name);
|
|
105
|
+
}
|
|
106
|
+
return [...unique];
|
|
107
|
+
};
|
|
108
|
+
const lstatOrThrow = (path) => {
|
|
109
|
+
try {
|
|
110
|
+
return lstatSync(path);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw new FingerprintIOError([`cannot stat ${path}: ${describeError(error)}`]);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const readDirectoryOrThrow = (path) => {
|
|
117
|
+
try {
|
|
118
|
+
return readdirSync(path);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw new FingerprintIOError([`cannot read directory ${path}: ${describeError(error)}`]);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const readLinkOrThrow = (path) => {
|
|
125
|
+
try {
|
|
126
|
+
return readlinkSync(path);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw new FingerprintIOError([`cannot read symlink ${path}: ${describeError(error)}`]);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Depth-first walk that records one entry per filesystem object and never
|
|
134
|
+
* descends through a symlink.
|
|
135
|
+
*
|
|
136
|
+
* Recursion is safe because the walk cannot loop: a symlink is recorded and
|
|
137
|
+
* skipped, so a cycle in the directory graph (which POSIX forbids anyway) is not
|
|
138
|
+
* reachable. Ordering is imposed later by a global sort, so the traversal order
|
|
139
|
+
* here only has to be deterministic, which sorting the child names provides.
|
|
140
|
+
*/
|
|
141
|
+
const collectEntries = (directory, prefix, state) => {
|
|
142
|
+
const names = readDirectoryOrThrow(directory);
|
|
143
|
+
names.sort(comparePaths);
|
|
144
|
+
for (let index = 0; index < names.length; index += 1) {
|
|
145
|
+
const name = names[index];
|
|
146
|
+
if (state.excluded.has(name)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const fullPath = join(directory, name);
|
|
150
|
+
const relativePath = prefix.length === 0 ? name : `${prefix}/${name}`;
|
|
151
|
+
const stats = lstatOrThrow(fullPath);
|
|
152
|
+
if (stats.isSymbolicLink()) {
|
|
153
|
+
const target = readLinkOrThrow(fullPath);
|
|
154
|
+
const targetBytes = encodeUtf8Strict(target);
|
|
155
|
+
state.entries.push({
|
|
156
|
+
path: relativePath,
|
|
157
|
+
digest: bytesToHex(createSha256().update(targetBytes).digest()),
|
|
158
|
+
size: targetBytes.length,
|
|
159
|
+
mode: ModeSymlink,
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (stats.isDirectory()) {
|
|
164
|
+
state.entries.push({ path: relativePath, digest: EmptyDigestHex, size: 0, mode: ModeDirectory });
|
|
165
|
+
collectEntries(fullPath, relativePath, state);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (!stats.isFile()) {
|
|
169
|
+
throw new FingerprintIOError([`${fullPath} is not a regular file, directory or symlink`]);
|
|
170
|
+
}
|
|
171
|
+
const mode = (stats.mode & 0o111) !== 0 ? ModeExecutableFile : ModeFile;
|
|
172
|
+
const digest = fileContentDigest(fullPath, stats.size, state.chunkBytes);
|
|
173
|
+
state.entries.push({ path: relativePath, digest, size: stats.size, mode });
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Serialise one entry into its leaf record.
|
|
178
|
+
*
|
|
179
|
+
* `size` is written as a big-endian u64 from its high and low 32-bit halves,
|
|
180
|
+
* which avoids BigInt conversion on the hot path and is exact for every
|
|
181
|
+
* JavaScript number that can be a file size (`Number.isSafeInteger`).
|
|
182
|
+
*/
|
|
183
|
+
const buildLeafRecord = (entry) => {
|
|
184
|
+
const pathBytes = encodeUtf8Strict(entry.path);
|
|
185
|
+
const record = new Uint8Array(LeafFixedBytes + pathBytes.length);
|
|
186
|
+
record[0] = LeafPrefix;
|
|
187
|
+
const view = new DataView(record.buffer);
|
|
188
|
+
view.setUint32(PathLengthOffset, pathBytes.length);
|
|
189
|
+
record.set(pathBytes, PathLengthOffset + 4);
|
|
190
|
+
const modeOffset = ModeOffsetBase + pathBytes.length;
|
|
191
|
+
const sizeOffset = SizeOffsetBase + pathBytes.length;
|
|
192
|
+
const digestOffset = DigestOffsetBase + pathBytes.length;
|
|
193
|
+
view.setUint32(modeOffset, entry.mode);
|
|
194
|
+
view.setUint32(sizeOffset, Math.floor(entry.size / Uint32Range));
|
|
195
|
+
view.setUint32(sizeOffset + 4, entry.size % Uint32Range);
|
|
196
|
+
record.set(hexToBytes(entry.digest), digestOffset);
|
|
197
|
+
return record;
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Fold sorted leaf digests into a Merkle root.
|
|
201
|
+
*
|
|
202
|
+
* Adjacent pairs are combined bottom-up; an odd node is promoted unchanged to
|
|
203
|
+
* the next level, which is the Bitcoin/RFC 6962 style tree and keeps the fold
|
|
204
|
+
* well-defined for any entry count. The empty tree is `sha256(empty)` rather
|
|
205
|
+
* than a special constant, so the one-entry and zero-entry cases differ by an
|
|
206
|
+
* actual hash rather than by convention.
|
|
207
|
+
*/
|
|
208
|
+
const merkleFold = (leaves) => {
|
|
209
|
+
if (leaves.length === 0) {
|
|
210
|
+
return createSha256().digest();
|
|
211
|
+
}
|
|
212
|
+
let level = [];
|
|
213
|
+
for (let index = 0; index < leaves.length; index += 1) {
|
|
214
|
+
level.push(leaves[index]);
|
|
215
|
+
}
|
|
216
|
+
while (level.length > 1) {
|
|
217
|
+
const next = [];
|
|
218
|
+
for (let index = 0; index < level.length; index += 2) {
|
|
219
|
+
if (index + 1 === level.length) {
|
|
220
|
+
next.push(level[index]);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const pair = new Uint8Array(NodeBytes);
|
|
224
|
+
pair[0] = NodePrefix;
|
|
225
|
+
pair.set(level[index], NodeLeftOffset);
|
|
226
|
+
pair.set(level[index + 1], NodeRightOffset);
|
|
227
|
+
next.push(createSha256().update(pair).digest());
|
|
228
|
+
}
|
|
229
|
+
level = next;
|
|
230
|
+
}
|
|
231
|
+
return level[0];
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Fingerprint a directory tree.
|
|
235
|
+
*
|
|
236
|
+
* The returned entries are sorted by UTF-8 path bytes and carry the child digest
|
|
237
|
+
* each leaf was built from, so a caller can re-derive the root after changing
|
|
238
|
+
* one file without re-reading the whole tree. The algorithm is fixed to SHA-256
|
|
239
|
+
* in this build: the root composition in `amp.fp/1` is defined in terms of
|
|
240
|
+
* SHA-256, so naming another algorithm here would produce a reference whose
|
|
241
|
+
* verifier cannot exist.
|
|
242
|
+
*/
|
|
243
|
+
export const fingerprintTree = async (root, options) => {
|
|
244
|
+
const algorithm = options?.algorithm ?? "sha256";
|
|
245
|
+
if (algorithm !== "sha256") {
|
|
246
|
+
throw new UnsupportedAlgorithm([`tree fingerprints compose with sha256; algorithm "${algorithm}" has no tree backend`]);
|
|
247
|
+
}
|
|
248
|
+
const chunkBytes = resolveChunkBytes(options?.chunkBytes);
|
|
249
|
+
const rootStats = lstatOrThrow(root);
|
|
250
|
+
if (rootStats.isSymbolicLink()) {
|
|
251
|
+
throw new FingerprintIOError([`${root} is a symbolic link; tree fingerprints never follow links`]);
|
|
252
|
+
}
|
|
253
|
+
if (!rootStats.isDirectory()) {
|
|
254
|
+
throw new FingerprintIOError([`${root} is not a directory`]);
|
|
255
|
+
}
|
|
256
|
+
const exclusions = resolveExclusions(options?.exclude);
|
|
257
|
+
const state = { excluded: new Set(exclusions), chunkBytes, entries: [] };
|
|
258
|
+
collectEntries(root, "", state);
|
|
259
|
+
const sorted = state.entries.slice();
|
|
260
|
+
sorted.sort((left, right) => comparePaths(left.path, right.path));
|
|
261
|
+
const leaves = [];
|
|
262
|
+
let totalBytes = 0;
|
|
263
|
+
for (let index = 0; index < sorted.length; index += 1) {
|
|
264
|
+
const record = buildLeafRecord(sorted[index]);
|
|
265
|
+
leaves.push(createSha256().update(record).digest());
|
|
266
|
+
totalBytes += record.byteLength;
|
|
267
|
+
}
|
|
268
|
+
const merkleRoot = merkleFold(leaves);
|
|
269
|
+
const policyDigest = createSha256().update(encodeUtf8Strict(Policy.treeV1)).digest();
|
|
270
|
+
const rootInput = new Uint8Array(RootFixedBytes);
|
|
271
|
+
rootInput[0] = RootPrefix;
|
|
272
|
+
const rootView = new DataView(rootInput.buffer);
|
|
273
|
+
rootView.setUint32(RootCountOffset, Math.floor(sorted.length / Uint32Range));
|
|
274
|
+
rootView.setUint32(RootCountOffset + 4, sorted.length % Uint32Range);
|
|
275
|
+
rootInput.set(merkleRoot, RootMerkleOffset);
|
|
276
|
+
rootInput.set(policyDigest, RootPolicyOffset);
|
|
277
|
+
const rootHex = bytesToHex(createSha256().update(rootInput).digest());
|
|
278
|
+
const excluded = [...exclusions].sort(comparePaths);
|
|
279
|
+
const ref = {
|
|
280
|
+
scheme: SchemeName,
|
|
281
|
+
algorithm,
|
|
282
|
+
kind: "tree",
|
|
283
|
+
policy: Policy.treeV1,
|
|
284
|
+
bytes: totalBytes,
|
|
285
|
+
digest: rootHex,
|
|
286
|
+
};
|
|
287
|
+
return { ref, digest: shortForm(algorithm, rootHex), root: rootHex, entries: sorted, excluded };
|
|
288
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FingerprintRef } from "./preimage.js";
|
|
2
|
+
/**
|
|
3
|
+
* True when both references name the same value under the same rules.
|
|
4
|
+
*
|
|
5
|
+
* Kind and policy are compared as strings because they are frozen vocabulary;
|
|
6
|
+
* digest comparison is constant-time-ish. `bytes` is deliberately not part of
|
|
7
|
+
* the identity here (RFC 6920 identity is algorithm + value), but `verify`
|
|
8
|
+
* compares it as well.
|
|
9
|
+
*/
|
|
10
|
+
export declare const matches: (expected: FingerprintRef, actual: FingerprintRef) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Assert that `actual` is the value `expected` names; throw `FingerprintMismatch`
|
|
13
|
+
* otherwise.
|
|
14
|
+
*
|
|
15
|
+
* The message contains both references (algorithm, kind, policy, bytes and hex)
|
|
16
|
+
* plus one line per differing field. A log line that only says "mismatch" cannot
|
|
17
|
+
* be acted on: the reader needs to know whether the policy changed or the bytes
|
|
18
|
+
* did.
|
|
19
|
+
*/
|
|
20
|
+
export declare const verify: (expected: FingerprintRef, actual: FingerprintRef) => void;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference comparison and verification.
|
|
3
|
+
*
|
|
4
|
+
* Comparing digests alone is the bug this module exists to avoid: the same
|
|
5
|
+
* payload bytes hashed under two policies produce two different digests, so a
|
|
6
|
+
* verifier that only sees hex cannot know which rules to apply. `matches`
|
|
7
|
+
* therefore compares the identity quadruple — algorithm, kind, policy and
|
|
8
|
+
* digest — following RFC 6920 §2 (identity is algorithm + value; presentation
|
|
9
|
+
* fields are ignored) extended with the two fields that decide how the value was
|
|
10
|
+
* computed.
|
|
11
|
+
*
|
|
12
|
+
* `verify` is one step stricter and also compares the declared payload length,
|
|
13
|
+
* mirroring OCI's "compare size before digest" rule: a reference that claims a
|
|
14
|
+
* different length is a different descriptor even when the hash agrees. The
|
|
15
|
+
* length is cheap to compare and shrinks the space an attacker has to search.
|
|
16
|
+
*
|
|
17
|
+
* The hex comparison is length-checked first and then scans the whole string
|
|
18
|
+
* without an early exit, so a mismatch does not reveal the position of the first
|
|
19
|
+
* differing digit through timing. This is not a substitute for a MAC, but it
|
|
20
|
+
* costs nothing and avoids being the weakest link in an otherwise
|
|
21
|
+
* constant-time comparison chain.
|
|
22
|
+
*/
|
|
23
|
+
import { FingerprintMismatch } from "./error.js";
|
|
24
|
+
/**
|
|
25
|
+
* Compare two equal-length strings without returning early.
|
|
26
|
+
*
|
|
27
|
+
* Different lengths fail immediately: the length is public (it is the algorithm
|
|
28
|
+
* identity), so no secret leaks, and scanning would need padding to be
|
|
29
|
+
* meaningful anyway.
|
|
30
|
+
*/
|
|
31
|
+
const constantTimeEquals = (left, right) => {
|
|
32
|
+
if (left.length !== right.length) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
let difference = 0;
|
|
36
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
37
|
+
difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
38
|
+
}
|
|
39
|
+
return difference === 0;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Describe a reference for a human reader without re-validating it.
|
|
43
|
+
*
|
|
44
|
+
* `formatRef` cannot be used in the mismatch message: it validates the fields
|
|
45
|
+
* and throws, which would replace the `FingerprintMismatch` the caller is
|
|
46
|
+
* supposed to catch with an unrelated `invalid_ref`.
|
|
47
|
+
*/
|
|
48
|
+
const describe = (ref) => `${ref.algorithm}:${ref.kind}:${ref.policy}:${ref.bytes}:${ref.digest}`;
|
|
49
|
+
/**
|
|
50
|
+
* True when both references name the same value under the same rules.
|
|
51
|
+
*
|
|
52
|
+
* Kind and policy are compared as strings because they are frozen vocabulary;
|
|
53
|
+
* digest comparison is constant-time-ish. `bytes` is deliberately not part of
|
|
54
|
+
* the identity here (RFC 6920 identity is algorithm + value), but `verify`
|
|
55
|
+
* compares it as well.
|
|
56
|
+
*/
|
|
57
|
+
export const matches = (expected, actual) => {
|
|
58
|
+
if (expected.algorithm !== actual.algorithm) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (expected.kind !== actual.kind) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (expected.policy !== actual.policy) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return constantTimeEquals(expected.digest, actual.digest);
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Assert that `actual` is the value `expected` names; throw `FingerprintMismatch`
|
|
71
|
+
* otherwise.
|
|
72
|
+
*
|
|
73
|
+
* The message contains both references (algorithm, kind, policy, bytes and hex)
|
|
74
|
+
* plus one line per differing field. A log line that only says "mismatch" cannot
|
|
75
|
+
* be acted on: the reader needs to know whether the policy changed or the bytes
|
|
76
|
+
* did.
|
|
77
|
+
*/
|
|
78
|
+
export const verify = (expected, actual) => {
|
|
79
|
+
const problems = [];
|
|
80
|
+
if (expected.algorithm !== actual.algorithm) {
|
|
81
|
+
problems.push(`algorithm differs: expected ${expected.algorithm}, received ${actual.algorithm}`);
|
|
82
|
+
}
|
|
83
|
+
if (expected.kind !== actual.kind) {
|
|
84
|
+
problems.push(`kind differs: expected ${expected.kind}, received ${actual.kind}`);
|
|
85
|
+
}
|
|
86
|
+
if (expected.policy !== actual.policy) {
|
|
87
|
+
problems.push(`policy differs: expected ${expected.policy}, received ${actual.policy}`);
|
|
88
|
+
}
|
|
89
|
+
if (!constantTimeEquals(expected.digest, actual.digest)) {
|
|
90
|
+
problems.push("digest differs");
|
|
91
|
+
}
|
|
92
|
+
if (expected.bytes !== actual.bytes) {
|
|
93
|
+
problems.push(`bytes differs: expected ${expected.bytes}, received ${actual.bytes}`);
|
|
94
|
+
}
|
|
95
|
+
if (problems.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
throw new FingerprintMismatch([`expected ${describe(expected)} but received ${describe(actual)}`, ...problems]);
|
|
99
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global filesystem adapter.
|
|
3
|
+
*
|
|
4
|
+
* The adapter renames the local `amp_tool_filesystem_*` surface to
|
|
5
|
+
* `amp_tool_globalfs_*` and rewrites the response protocol. It owns no tree,
|
|
6
|
+
* cache or write journal of its own: every call goes through the bound
|
|
7
|
+
* `FilesystemSession`, so the session token, roots, quotas and isolation stay
|
|
8
|
+
* exactly as strong as the local surface. A future multi-root router can sit
|
|
9
|
+
* behind the same interface without changing the wire names.
|
|
10
|
+
*/
|
|
11
|
+
import type { FilesystemSession } from "../file/service.js";
|
|
12
|
+
import type { FilesystemService } from "../file/service.js";
|
|
13
|
+
import type { FilesystemToolDefinition } from "../protocol/filesystem.js";
|
|
14
|
+
import type { GlobalFilesystemResponse } from "../protocol/globalFilesystem.js";
|
|
15
|
+
export declare class GlobalFilesystemService {
|
|
16
|
+
private readonly base;
|
|
17
|
+
constructor(base: FilesystemService);
|
|
18
|
+
/**
|
|
19
|
+
* Bind one authenticated session to the global namespace.
|
|
20
|
+
*/
|
|
21
|
+
bind(sessionId: string, token: string): GlobalFilesystemSession;
|
|
22
|
+
dispose(sessionId: string): void;
|
|
23
|
+
}
|
|
24
|
+
export declare class GlobalFilesystemSession {
|
|
25
|
+
private readonly base;
|
|
26
|
+
constructor(base: FilesystemSession);
|
|
27
|
+
get sessionId(): string;
|
|
28
|
+
get descriptor(): FilesystemSession["descriptor"];
|
|
29
|
+
tools(): FilesystemToolDefinition[];
|
|
30
|
+
/**
|
|
31
|
+
* Typed delegates keep hook and direct-embedder code identical for the
|
|
32
|
+
* local and global surfaces.
|
|
33
|
+
*/
|
|
34
|
+
read: FilesystemSession["read"];
|
|
35
|
+
write: FilesystemSession["write"];
|
|
36
|
+
outline: FilesystemSession["outline"];
|
|
37
|
+
imports: FilesystemSession["imports"];
|
|
38
|
+
exports: FilesystemSession["exports"];
|
|
39
|
+
dependency: FilesystemSession["dependency"];
|
|
40
|
+
ast: FilesystemSession["ast"];
|
|
41
|
+
revision: FilesystemSession["revision"];
|
|
42
|
+
call(name: string, raw: unknown): Promise<GlobalFilesystemResponse>;
|
|
43
|
+
}
|