@plurnk/plurnk-service 1.3.12 → 1.5.0
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/.env.defaults +95 -91
- package/INSTALL.md +54 -28
- package/README.md +25 -10
- package/SPEC.md +2426 -942
- package/dist/Paths.d.ts +4 -1
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +24 -23
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/edit-receipt.d.ts +13 -28
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +285 -104
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/edited-span.d.ts.map +1 -1
- package/dist/content/edited-span.js +2 -5
- package/dist/content/edited-span.js.map +1 -1
- package/dist/content/index.d.ts +4 -3
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +2 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-marker.d.ts +10 -9
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +8 -11
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +15 -26
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +77 -107
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/mimetype-binary.d.ts +2 -2
- package/dist/content/mimetype-binary.d.ts.map +1 -1
- package/dist/content/mimetype-binary.js +10 -10
- package/dist/content/mimetype-binary.js.map +1 -1
- package/dist/content/path-mimetype.js +3 -3
- package/dist/content/path-mimetype.js.map +1 -1
- package/dist/content/read-projector.d.ts +14 -0
- package/dist/content/read-projector.d.ts.map +1 -0
- package/dist/content/read-projector.js +86 -0
- package/dist/content/read-projector.js.map +1 -0
- package/dist/content/read-resolve.d.ts +6 -7
- package/dist/content/read-resolve.d.ts.map +1 -1
- package/dist/content/read-resolve.js +36 -59
- package/dist/content/read-resolve.js.map +1 -1
- package/dist/core/BranchReceipt.d.ts +6 -0
- package/dist/core/BranchReceipt.d.ts.map +1 -0
- package/dist/core/BranchReceipt.js +24 -0
- package/dist/core/BranchReceipt.js.map +1 -0
- package/dist/core/BudgetOverflow.d.ts +20 -0
- package/dist/core/BudgetOverflow.d.ts.map +1 -0
- package/dist/core/BudgetOverflow.js +49 -0
- package/dist/core/BudgetOverflow.js.map +1 -0
- package/dist/core/BudgetReadout.d.ts +8 -0
- package/dist/core/BudgetReadout.d.ts.map +1 -0
- package/dist/core/BudgetReadout.js +79 -0
- package/dist/core/BudgetReadout.js.map +1 -0
- package/dist/core/ChannelWrite.d.ts +31 -9
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +30 -23
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +14 -12
- package/dist/core/CoreSchemeServices.d.ts +18 -4
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +7 -1
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +26 -21
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +1626 -671
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/DurableStatement.d.ts +6 -0
- package/dist/core/DurableStatement.d.ts.map +1 -0
- package/dist/core/DurableStatement.js +51 -0
- package/dist/core/DurableStatement.js.map +1 -0
- package/dist/core/Engine.d.ts +64 -29
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +1348 -835
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +329 -234
- package/dist/core/EnvFlags.js +1 -1
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/ErrorDetail.d.ts +6 -0
- package/dist/core/ErrorDetail.d.ts.map +1 -0
- package/dist/core/ErrorDetail.js +20 -0
- package/dist/core/ErrorDetail.js.map +1 -0
- package/dist/core/ExecutorRegistry.d.ts +14 -3
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +56 -30
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/GitBranch.d.ts +20 -0
- package/dist/core/GitBranch.d.ts.map +1 -0
- package/dist/core/GitBranch.js +110 -0
- package/dist/core/GitBranch.js.map +1 -0
- package/dist/core/JournalTurn.d.ts +9 -0
- package/dist/core/JournalTurn.d.ts.map +1 -0
- package/dist/core/JournalTurn.js +14 -0
- package/dist/core/JournalTurn.js.map +1 -0
- package/dist/core/JournalTurn.sql +10 -0
- package/dist/core/LogBody.d.ts +18 -0
- package/dist/core/LogBody.d.ts.map +1 -0
- package/dist/core/LogBody.js +180 -0
- package/dist/core/LogBody.js.map +1 -0
- package/dist/core/LoopFlagsReader.d.ts +7 -0
- package/dist/core/LoopFlagsReader.d.ts.map +1 -0
- package/dist/core/LoopFlagsReader.js +33 -0
- package/dist/core/LoopFlagsReader.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +8 -2
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +54 -11
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +10 -7
- package/dist/core/NoticeChannel.d.ts +13 -0
- package/dist/core/NoticeChannel.d.ts.map +1 -0
- package/dist/core/NoticeChannel.js +40 -0
- package/dist/core/NoticeChannel.js.map +1 -0
- package/dist/core/Owner.d.ts +0 -1
- package/dist/core/Owner.d.ts.map +1 -1
- package/dist/core/Owner.js +2 -5
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +27 -25
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +321 -383
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.d.ts +26 -0
- package/dist/core/ProblemLog.d.ts.map +1 -0
- package/dist/core/ProblemLog.js +58 -0
- package/dist/core/ProblemLog.js.map +1 -0
- package/dist/core/ProposalLifecycle.d.ts +15 -21
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +291 -78
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +51 -48
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +14 -8
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +189 -114
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ServiceTeardown.d.ts +11 -0
- package/dist/core/ServiceTeardown.d.ts.map +1 -0
- package/dist/core/ServiceTeardown.js +70 -0
- package/dist/core/ServiceTeardown.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +29 -0
- package/dist/core/StoredPacket.d.ts.map +1 -0
- package/dist/core/StoredPacket.js +147 -0
- package/dist/core/StoredPacket.js.map +1 -0
- package/dist/core/StrikeRail.d.ts +6 -3
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +27 -56
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TerminalResult.d.ts +16 -0
- package/dist/core/TerminalResult.d.ts.map +1 -0
- package/dist/core/TerminalResult.js +49 -0
- package/dist/core/TerminalResult.js.map +1 -0
- package/dist/core/WorkerControlAddress.d.ts +17 -0
- package/dist/core/WorkerControlAddress.d.ts.map +1 -0
- package/dist/core/WorkerControlAddress.js +44 -0
- package/dist/core/WorkerControlAddress.js.map +1 -0
- package/dist/core/WorkerName.d.ts +31 -0
- package/dist/core/WorkerName.d.ts.map +1 -0
- package/dist/core/WorkerName.js +95 -0
- package/dist/core/WorkerName.js.map +1 -0
- package/dist/core/WorkerName.sql +36 -0
- package/dist/core/WorkspaceGate.d.ts +14 -0
- package/dist/core/WorkspaceGate.d.ts.map +1 -0
- package/dist/core/WorkspaceGate.js +155 -0
- package/dist/core/WorkspaceGate.js.map +1 -0
- package/dist/core/caps/CapsResolve.d.ts +5 -1
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js +8 -4
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +5 -11
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +30 -12
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +5 -14
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +27 -8
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +18 -15
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbProjectionCaps.d.ts +5 -5
- package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +21 -4
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +75 -66
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/DbTagCaps.d.ts +5 -12
- package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
- package/dist/core/caps/DbTagCaps.js +20 -11
- package/dist/core/caps/DbTagCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +6 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +6 -6
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/content-hash.js +1 -1
- package/dist/core/content-hash.js.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +55 -30
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +43 -29
- package/dist/core/git-env.d.ts +2 -0
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +13 -18
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-iso.d.ts +3 -2
- package/dist/core/git-iso.d.ts.map +1 -1
- package/dist/core/git-iso.js +36 -27
- package/dist/core/git-iso.js.map +1 -1
- package/dist/core/git-membership.d.ts +2 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +276 -162
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +8 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +44 -26
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/namespace.d.ts +1 -0
- package/dist/core/namespace.d.ts.map +1 -1
- package/dist/core/namespace.js +20 -0
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/optimistic-settlement.d.ts +2 -0
- package/dist/core/optimistic-settlement.d.ts.map +1 -0
- package/dist/core/optimistic-settlement.js +14 -0
- package/dist/core/optimistic-settlement.js.map +1 -0
- package/dist/core/owner.sql +1 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +7 -11
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +3 -21
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +305 -385
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +12 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +49 -29
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/results.d.ts +18 -5
- package/dist/core/results.d.ts.map +1 -1
- package/dist/core/results.js +33 -18
- package/dist/core/results.js.map +1 -1
- package/dist/core/ruler_count.d.ts +4 -0
- package/dist/core/ruler_count.d.ts.map +1 -0
- package/dist/core/ruler_count.js +7 -0
- package/dist/core/ruler_count.js.map +1 -0
- package/dist/core/scheme-types.d.ts +3 -17
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/search-gate.d.ts.map +1 -1
- package/dist/core/search-gate.js +3 -11
- package/dist/core/search-gate.js.map +1 -1
- package/dist/core/teaching-corpus.d.ts +6 -0
- package/dist/core/teaching-corpus.d.ts.map +1 -0
- package/dist/core/teaching-corpus.js +23 -0
- package/dist/core/teaching-corpus.js.map +1 -0
- package/dist/core/teaching.d.ts +0 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +2 -8
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/token-ruler.d.ts.map +1 -1
- package/dist/core/token-ruler.js +3 -16
- package/dist/core/token-ruler.js.map +1 -1
- package/dist/core/turn-scheduler.d.ts +1 -1
- package/dist/core/turn-scheduler.d.ts.map +1 -1
- package/dist/core/turn-scheduler.js +1 -1
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/worker-cap.d.ts +2 -4
- package/dist/core/worker-cap.d.ts.map +1 -1
- package/dist/core/worker-cap.js +13 -4
- package/dist/core/worker-cap.js.map +1 -1
- package/dist/core/{run-ops.sql → worker-ops.sql} +14 -14
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +17 -9
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts +2 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +510 -149
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +23 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/observe/api.d.ts +6 -0
- package/dist/observe/api.d.ts.map +1 -0
- package/dist/observe/api.js +11 -0
- package/dist/observe/api.js.map +1 -0
- package/dist/observe/init.d.ts +7 -0
- package/dist/observe/init.d.ts.map +1 -0
- package/dist/observe/init.js +159 -0
- package/dist/observe/init.js.map +1 -0
- package/dist/observe/metrics.d.ts +6 -0
- package/dist/observe/metrics.d.ts.map +1 -0
- package/dist/observe/metrics.js +15 -0
- package/dist/observe/metrics.js.map +1 -0
- package/dist/observe/spans.d.ts +4 -0
- package/dist/observe/spans.d.ts.map +1 -0
- package/dist/observe/spans.js +51 -0
- package/dist/observe/spans.js.map +1 -0
- package/dist/schemes/EffectPolicy.d.ts +1 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +5 -2
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts +9 -14
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +402 -262
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +9 -9
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +49 -18
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +7 -13
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +280 -151
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +8 -12
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +402 -233
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +71 -32
- package/dist/schemes/Prompt.d.ts +3 -3
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +10 -10
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Skill.d.ts +2 -3
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +2 -6
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts +11 -19
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +210 -89
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-chunk.d.ts.map +1 -1
- package/dist/schemes/_entry-chunk.js +12 -5
- package/dist/schemes/_entry-chunk.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +11 -9
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +72 -13
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +28 -10
- package/dist/schemes/_entry-find.d.ts +49 -18
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +348 -195
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +20 -8
- package/dist/schemes/_entry-graph.d.ts +4 -2
- package/dist/schemes/_entry-graph.d.ts.map +1 -1
- package/dist/schemes/_entry-graph.js +55 -31
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-graph.sql +37 -22
- package/dist/schemes/_entry-manifest.d.ts +10 -15
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +50 -268
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +14 -15
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +121 -110
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +2 -3
- package/dist/schemes/_entry-semantic.d.ts +22 -9
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +127 -67
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +63 -45
- package/dist/schemes/_entry-send.d.ts +3 -4
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +48 -23
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_path-scope.d.ts +23 -0
- package/dist/schemes/_path-scope.d.ts.map +1 -0
- package/dist/schemes/_path-scope.js +61 -0
- package/dist/schemes/_path-scope.js.map +1 -0
- package/dist/schemes/_search-candidate.d.ts +20 -0
- package/dist/schemes/_search-candidate.d.ts.map +1 -0
- package/dist/schemes/_search-candidate.js +19 -0
- package/dist/schemes/_search-candidate.js.map +1 -0
- package/dist/schemes/_search-exclusion.d.ts +7 -0
- package/dist/schemes/_search-exclusion.d.ts.map +1 -0
- package/dist/schemes/_search-exclusion.js +23 -0
- package/dist/schemes/_search-exclusion.js.map +1 -0
- package/dist/schemes/_search-index.d.ts +6 -0
- package/dist/schemes/_search-index.d.ts.map +1 -0
- package/dist/schemes/_search-index.js +328 -0
- package/dist/schemes/_search-index.js.map +1 -0
- package/dist/schemes/cosine.js +1 -1
- package/dist/schemes/cosine.js.map +1 -1
- package/dist/schemes/exec-abort.js +3 -3
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/schemes/exec-env.js +3 -3
- package/dist/schemes/exec-env.js.map +1 -1
- package/dist/server/BranchBatches.d.ts +49 -0
- package/dist/server/BranchBatches.d.ts.map +1 -0
- package/dist/server/BranchBatches.js +592 -0
- package/dist/server/BranchBatches.js.map +1 -0
- package/dist/server/Daemon.d.ts +39 -71
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +1133 -491
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +31 -0
- package/dist/server/DaemonModule.d.ts.map +1 -0
- package/dist/server/DaemonModule.js +2 -0
- package/dist/server/DaemonModule.js.map +1 -0
- package/dist/server/branch-batch.sql +154 -0
- package/dist/server/client-input.d.ts +13 -0
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +268 -57
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +15 -7
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +96 -65
- package/dist/server/envelope.d.ts +4 -7
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +118 -95
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +18 -23
- package/dist/server/exec-poll-backoff.js +1 -1
- package/dist/server/exec-poll-backoff.js.map +1 -1
- package/dist/server/lifecycle-recovery.sql +112 -2
- package/dist/server/logEntry.d.ts +4 -2
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +6 -3
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +1 -1
- package/dist/server/loop-model.d.ts.map +1 -1
- package/dist/server/loop-model.js +22 -9
- package/dist/server/loop-model.js.map +1 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +5 -4
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/seam-entry-read.sql +15 -10
- package/dist/server/seam-log-read.sql +2 -2
- package/dist/server/seam-loop.sql +1 -1
- package/dist/server/seam-proposal-list.sql +17 -7
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +79 -61
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +1010 -0
- package/package.json +65 -32
- package/dist/core/PluginLoader.d.ts +0 -20
- package/dist/core/PluginLoader.d.ts.map +0 -1
- package/dist/core/PluginLoader.js +0 -142
- package/dist/core/PluginLoader.js.map +0 -1
- package/dist/core/TelemetryChannel.d.ts +0 -37
- package/dist/core/TelemetryChannel.d.ts.map +0 -1
- package/dist/core/TelemetryChannel.js +0 -80
- package/dist/core/TelemetryChannel.js.map +0 -1
- package/dist/core/path-decode.d.ts +0 -3
- package/dist/core/path-decode.d.ts.map +0 -1
- package/dist/core/path-decode.js +0 -9
- package/dist/core/path-decode.js.map +0 -1
- package/dist/core/plugin-attribution.d.ts +0 -5
- package/dist/core/plugin-attribution.d.ts.map +0 -1
- package/dist/core/plugin-attribution.js +0 -39
- package/dist/core/plugin-attribution.js.map +0 -1
- package/dist/core/world-state.d.ts +0 -10
- package/dist/core/world-state.d.ts.map +0 -1
- package/dist/core/world-state.js +0 -35
- package/dist/core/world-state.js.map +0 -1
- package/dist/core/world-state.sql +0 -35
- package/dist/core/zero-pin.d.ts +0 -3
- package/dist/core/zero-pin.d.ts.map +0 -1
- package/dist/core/zero-pin.js +0 -16
- package/dist/core/zero-pin.js.map +0 -1
- package/dist/server/auto.d.ts +0 -6
- package/dist/server/auto.d.ts.map +0 -1
- package/dist/server/auto.js +0 -63
- package/dist/server/auto.js.map +0 -1
- package/dist/server/clientTurn.d.ts +0 -6
- package/dist/server/clientTurn.d.ts.map +0 -1
- package/dist/server/clientTurn.js +0 -22
- package/dist/server/clientTurn.js.map +0 -1
- package/dist/server/clientTurn.sql +0 -10
- package/dist/server/noProposals.d.ts +0 -6
- package/dist/server/noProposals.d.ts.map +0 -1
- package/dist/server/noProposals.js +0 -37
- package/dist/server/noProposals.js.map +0 -1
- package/dist/server/version-info.d.ts +0 -14
- package/dist/server/version-info.d.ts.map +0 -1
- package/dist/server/version-info.js +0 -69
- package/dist/server/version-info.js.map +0 -1
- package/migrations/0000-00-00.01_schema.sql +0 -536
- package/migrations/0004_loop-provider.sql +0 -3
- package/migrations/0005_subscription-published-channel.sql +0 -3
- package/migrations/0006_loop-max-turns.sql +0 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// SPEC §membership D4 — git-ls-files workspace membership. §membership-git-membership
|
|
1
|
+
// SPEC {§membership} D4 — git-ls-files workspace membership. {§membership-git-membership}
|
|
2
2
|
//
|
|
3
3
|
// When a workspace's `project_root` is a git working tree, the git-tracked
|
|
4
4
|
// files (`git ls-files`) are workspace MEMBERS without any explicit client
|
|
5
5
|
// `pick`. This module resolves that membership and (when token accounting is
|
|
6
|
-
// available) materializes active members'
|
|
6
|
+
// available) materializes active members' model-readable representation into a body channel,
|
|
7
7
|
// so they appear in the entry catalog (FIND-served) and are READ-able.
|
|
8
8
|
//
|
|
9
9
|
// Decisions realized here:
|
|
@@ -17,25 +17,54 @@
|
|
|
17
17
|
// `(ls-files ∪ pick) − hide`; view is enforced at the File edit gate.
|
|
18
18
|
// D5 — coverage is exhaustive, work is change-gated: every member is stat'd each
|
|
19
19
|
// turn, but only one whose mtime:size signature changed is re-read,
|
|
20
|
-
// re-tokenized, and rewritten
|
|
21
|
-
//
|
|
20
|
+
// re-tokenized, and rewritten. A binary source also compares the installed
|
|
21
|
+
// projection identity without reacquiring bytes. EMI divergence rides the
|
|
22
|
+
// same pass. {§membership-change-gated-sync}
|
|
22
23
|
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
// measures ~8x native (~130ms at 20k files), so a large-repo host can buy the hot path back.
|
|
24
|
+
// Git resolution uses native Git by default (subprocess + hermeticGitEnv,
|
|
25
|
+
// AbortSignal-respecting). PLURNK_SERVICE_GIT_ISO=1 explicitly selects the
|
|
26
|
+
// slower in-process portability backend for a deployment that cannot spawn Git.
|
|
27
27
|
import { execFile } from "node:child_process";
|
|
28
|
-
import { hermeticGitEnv } from "./git-env.js";
|
|
28
|
+
import { gitOutputMaxBytes, hermeticGitEnv, isomorphicGitEnabled } from "./git-env.js";
|
|
29
29
|
import GitIso from "./git-iso.js";
|
|
30
30
|
import { promisify } from "node:util";
|
|
31
31
|
import { readFile, glob, stat } from "node:fs/promises";
|
|
32
|
-
import { resolve,
|
|
32
|
+
import { resolve, join, matchesGlob } from "node:path";
|
|
33
|
+
import { MimetypeInputLimitError, } from "@plurnk/plurnk-mimetypes";
|
|
33
34
|
import { MimetypeBinary } from "../content/index.js";
|
|
34
35
|
import Owner from "./Owner.js";
|
|
35
36
|
import EntryCrud from "../schemes/_entry-crud.js";
|
|
36
37
|
import WorkspaceSettings from "./workspace-settings.js";
|
|
37
|
-
|
|
38
|
-
const
|
|
38
|
+
import Namespace from "./namespace.js";
|
|
39
|
+
const ABSENT_SIG = "absent";
|
|
40
|
+
const sourceProjectionFrom = (encoded) => {
|
|
41
|
+
const attributes = JSON.parse(encoded);
|
|
42
|
+
if (attributes === null || typeof attributes !== "object" || Array.isArray(attributes)) {
|
|
43
|
+
throw new TypeError("GitMembership: entry attributes must be a JSON object");
|
|
44
|
+
}
|
|
45
|
+
const candidate = attributes.sourceProjection;
|
|
46
|
+
if (candidate === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
49
|
+
throw new TypeError("GitMembership: sourceProjection must be a JSON object");
|
|
50
|
+
}
|
|
51
|
+
const projection = candidate;
|
|
52
|
+
if (typeof projection.mimetype !== "string"
|
|
53
|
+
|| projection.mimetype.length === 0
|
|
54
|
+
|| typeof projection.identity !== "string"
|
|
55
|
+
|| projection.identity.length === 0
|
|
56
|
+
|| !["projected", "unavailable", "input-limit"].includes(projection.disposition ?? "")) {
|
|
57
|
+
throw new TypeError("GitMembership: sourceProjection metadata is malformed");
|
|
58
|
+
}
|
|
59
|
+
const hasLimit = Number.isSafeInteger(projection.maximumBytes)
|
|
60
|
+
&& (projection.maximumBytes ?? 0) > 0
|
|
61
|
+
&& Number.isSafeInteger(projection.observedBytes)
|
|
62
|
+
&& (projection.observedBytes ?? 0) > (projection.maximumBytes ?? 0);
|
|
63
|
+
if ((projection.disposition === "input-limit") !== hasLimit) {
|
|
64
|
+
throw new TypeError("GitMembership: sourceProjection input-limit evidence is malformed");
|
|
65
|
+
}
|
|
66
|
+
return projection;
|
|
67
|
+
};
|
|
39
68
|
export default class GitMembership {
|
|
40
69
|
// Workspace creation starts a background warm while the first model turn
|
|
41
70
|
// performs its own eager membership refresh. Both are legitimate callers,
|
|
@@ -46,7 +75,8 @@ export default class GitMembership {
|
|
|
46
75
|
static #execFileP = promisify(execFile);
|
|
47
76
|
// {§fs-write-surface} — the blind-write closure git half: would git ADMIT a create at
|
|
48
77
|
// key (untracked-not-ignored)? check-ignore exit 0 = ignored (refuse), 1 = clean
|
|
49
|
-
// (
|
|
78
|
+
// (automatic membership admission, never `git add`), anything else (128, no
|
|
79
|
+
// repo) = git grants nothing here.
|
|
50
80
|
static async wouldGitAdmit(root, key, signal) {
|
|
51
81
|
try {
|
|
52
82
|
await GitMembership.#execFileP("git", ["check-ignore", "-q", "--", key], { cwd: root, signal, env: hermeticGitEnv() });
|
|
@@ -56,21 +86,33 @@ export default class GitMembership {
|
|
|
56
86
|
return err.code === 1;
|
|
57
87
|
}
|
|
58
88
|
}
|
|
89
|
+
static async stageFile(root, key, signal) {
|
|
90
|
+
try {
|
|
91
|
+
if (isomorphicGitEnabled()) {
|
|
92
|
+
await GitIso.add(root, key);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
await GitMembership.#execFileP("git", ["add", "--", key], { cwd: root, signal, env: hermeticGitEnv() });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Ignore staging errors if root is not a git repo
|
|
100
|
+
}
|
|
101
|
+
}
|
|
59
102
|
// project_root for a workspace. NULL = headless (no membership). Read once per
|
|
60
103
|
// resolution; the File scheme reads the same column for its own root.
|
|
61
104
|
static async #loadWorkspaceRoot(db, workspaceId) {
|
|
62
105
|
const row = await db.envelope_get_workspace.get({ id: workspaceId });
|
|
63
106
|
return row?.project_root ?? null;
|
|
64
107
|
}
|
|
65
|
-
// Tracked files of one repo, workspace-relative
|
|
66
|
-
// entries only) or `git ls-files --stage -z
|
|
67
|
-
// are filtered: a submodule
|
|
68
|
-
// file) is a separate declared repo, never a member of its superproject. Empty → [].
|
|
108
|
+
// Tracked files of one repo, workspace-relative - GitIso.trackedFiles (walk STAGE, blob
|
|
109
|
+
// entries only) or native `git ls-files --stage -z`. Either way gitlinks
|
|
110
|
+
// are filtered: a submodule is a repository boundary, not a file member. Empty → [].
|
|
69
111
|
static async #gitTrackedFiles(root, signal, cache) {
|
|
70
|
-
if (
|
|
112
|
+
if (isomorphicGitEnabled())
|
|
71
113
|
return GitIso.trackedFiles(root, cache);
|
|
72
114
|
// NUL-delimited so paths with spaces/newlines survive.
|
|
73
|
-
const { stdout } = await GitMembership.#execFileP("git", ["ls-files", "--stage", "-z"], { cwd: root, signal, maxBuffer:
|
|
115
|
+
const { stdout } = await GitMembership.#execFileP("git", ["ls-files", "--stage", "-z"], { cwd: root, signal, maxBuffer: gitOutputMaxBytes(), env: hermeticGitEnv() });
|
|
74
116
|
const files = [];
|
|
75
117
|
for (const entry of stdout.split("\0")) {
|
|
76
118
|
if (entry.length === 0)
|
|
@@ -84,22 +126,19 @@ export default class GitMembership {
|
|
|
84
126
|
}
|
|
85
127
|
return files;
|
|
86
128
|
}
|
|
87
|
-
// Untracked-but-not-ignored
|
|
88
|
-
// GitIso.untrackedFiles (the differential-gated pruning ignore-walk) or `git ls-files
|
|
89
|
-
// --others --exclude-standard -z
|
|
129
|
+
// Untracked-but-not-ignored members of one repo ({§membership-auto-add}) —
|
|
130
|
+
// GitIso.untrackedFiles (the differential-gated pruning ignore-walk) or native `git ls-files
|
|
131
|
+
// --others --exclude-standard -z`. A model-created file is a repo
|
|
90
132
|
// member the moment it exists — no git-stage required — while `.gitignore` still filters it.
|
|
91
133
|
static async #gitUntrackedFiles(root, signal, cache) {
|
|
92
|
-
if (
|
|
134
|
+
if (isomorphicGitEnabled())
|
|
93
135
|
return GitIso.untrackedFiles(root, cache);
|
|
94
|
-
const { stdout } = await GitMembership.#execFileP("git", ["ls-files", "--others", "--exclude-standard", "-z"], { cwd: root, signal, maxBuffer:
|
|
136
|
+
const { stdout } = await GitMembership.#execFileP("git", ["ls-files", "--others", "--exclude-standard", "-z"], { cwd: root, signal, maxBuffer: gitOutputMaxBytes(), env: hermeticGitEnv() });
|
|
95
137
|
return stdout.split("\0").filter((e) => e.length > 0);
|
|
96
138
|
}
|
|
97
|
-
// Resolve a
|
|
98
|
-
// null if it isn't inside a git tree. GitIso.repoToplevel (findRoot) or `rev-parse
|
|
99
|
-
// --show-toplevel` under the native flag — both handle plain repos, linked worktrees
|
|
100
|
-
// (`.git` is a gitdir: file), and submodules alike.
|
|
139
|
+
// Resolve a directory to the containing Git repository, or null when absent.
|
|
101
140
|
static async #repoToplevel(dir, signal) {
|
|
102
|
-
if (
|
|
141
|
+
if (isomorphicGitEnabled())
|
|
103
142
|
return GitIso.repoToplevel(dir);
|
|
104
143
|
try {
|
|
105
144
|
const { stdout } = await GitMembership.#execFileP("git", ["rev-parse", "--show-toplevel"], { cwd: dir, signal, env: hermeticGitEnv() });
|
|
@@ -109,84 +148,50 @@ export default class GitMembership {
|
|
|
109
148
|
return null; // not a git tree (or the dir is gone) — contributes nothing
|
|
110
149
|
}
|
|
111
150
|
}
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (repoRoot !== null)
|
|
125
|
-
repoRoots.add(repoRoot);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
151
|
+
// A workspace owns exactly the repository containing project_root. Packages and
|
|
152
|
+
// projects inside that repository share its Git state; unrelated repositories
|
|
153
|
+
// belong to unrelated workspaces.
|
|
154
|
+
static async projectRepository(db, workspaceId, signal) {
|
|
155
|
+
const root = await GitMembership.#loadWorkspaceRoot(db, workspaceId);
|
|
156
|
+
if (root === null || process.env.PLURNK_SERVICE_GIT_ALLOWED !== "1")
|
|
157
|
+
return null;
|
|
158
|
+
if ((await WorkspaceSettings.read(db, workspaceId)).git === false)
|
|
159
|
+
return null;
|
|
160
|
+
return GitMembership.#repoToplevel(root, signal);
|
|
161
|
+
}
|
|
162
|
+
static async #projectMembers(root, repoRoot, signal) {
|
|
128
163
|
const members = new Set();
|
|
129
|
-
// One iso-git cache per PASS: pack/index parses are reused across this resolve's repos
|
|
130
|
-
// and reads, then discarded — never carried across turns, so a rewritten index or
|
|
131
|
-
// repacked store can't serve stale.
|
|
132
164
|
const cache = {};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// an absolute pathname would nest UNDER root and never materialize. {§membership-overlay-repo}
|
|
138
|
-
const prefix = relative(root, repoRoot);
|
|
139
|
-
const tracked = await GitMembership.#gitTrackedFiles(repoRoot, signal, cache);
|
|
140
|
-
const untracked = await GitMembership.#gitUntrackedFiles(repoRoot, signal, cache);
|
|
141
|
-
for (const f of [...tracked, ...untracked]) {
|
|
142
|
-
members.add(join(prefix, f));
|
|
143
|
-
}
|
|
165
|
+
const tracked = await GitMembership.#gitTrackedFiles(repoRoot, signal, cache);
|
|
166
|
+
const untracked = await GitMembership.#gitUntrackedFiles(repoRoot, signal, cache);
|
|
167
|
+
for (const file of [...tracked, ...untracked]) {
|
|
168
|
+
members.add(Namespace.fromRepositoryPath(file, root, repoRoot));
|
|
144
169
|
}
|
|
145
170
|
return [...members];
|
|
146
171
|
}
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// A glob pattern is directory-expanded under the root via node:fs glob — `*` matches each
|
|
151
|
-
// immediate child (one level), `**` recurses — dropping file matches, since only a
|
|
152
|
-
// directory can be a repo; #repoToplevel then filters the non-git matches. {§membership-overlay-repo}
|
|
153
|
-
static async #expandRepoDirs(root, dir, signal) {
|
|
154
|
-
if (!GitMembership.#isGlobPattern(dir))
|
|
155
|
-
return [dir];
|
|
156
|
-
const dirs = [];
|
|
157
|
-
for await (const rel of glob(dir, { cwd: root })) {
|
|
158
|
-
if (signal?.aborted)
|
|
159
|
-
return dirs;
|
|
160
|
-
try {
|
|
161
|
-
if ((await stat(resolve(root, rel))).isDirectory())
|
|
162
|
-
dirs.push(rel);
|
|
163
|
-
}
|
|
164
|
-
catch {
|
|
165
|
-
// raced away between glob and stat — not a candidate
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return dirs;
|
|
169
|
-
}
|
|
170
|
-
// Does this declared repo entry carry glob magic (directory-expand it), or is it a
|
|
171
|
-
// literal path (declared as-is)? The metacharacters node:fs glob honors.
|
|
172
|
-
static #isGlobPattern(s) {
|
|
173
|
-
return /[*?[\]{}]/.test(s);
|
|
174
|
-
}
|
|
175
|
-
// Detect a tracked file's mimetype (mirrors File.detectFileMimetype): route
|
|
176
|
-
// through the Mimetypes service when present, normalizing the auto-text result
|
|
177
|
-
// to the text primitive (plurnk-service never auto-derives text/plain). No
|
|
178
|
-
// service → text primitive.
|
|
172
|
+
// Detect a tracked file's mimetype (mirrors File.detectFileMimetype) through
|
|
173
|
+
// the configured registry, normalizing auto-derived text/plain to the text
|
|
174
|
+
// primitive.
|
|
179
175
|
static async #detectMimetype(canonical, mimetypes) {
|
|
180
|
-
if (mimetypes
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
if (mimetypes === undefined)
|
|
177
|
+
throw new Error("GitMembership: configured mimetype registry is required");
|
|
178
|
+
const detected = await mimetypes.detect({ path: canonical });
|
|
179
|
+
return MimetypeBinary.normalizeAutoTextMimetype(detected);
|
|
180
|
+
}
|
|
181
|
+
static #projectionIdentity(mimetype, mimetypes, identities) {
|
|
182
|
+
if (mimetypes === undefined)
|
|
183
|
+
throw new Error("GitMembership: configured mimetype registry is required");
|
|
184
|
+
let identity = identities.get(mimetype);
|
|
185
|
+
if (identity === undefined) {
|
|
186
|
+
identity = mimetypes.projectionIdentity(mimetype);
|
|
187
|
+
identities.set(mimetype, identity);
|
|
183
188
|
}
|
|
184
|
-
return
|
|
189
|
+
return identity;
|
|
185
190
|
}
|
|
186
191
|
// Shared overlay inputs — the candidate sets (git tracked+untracked union, pick scan) and
|
|
187
192
|
// the overlay globs, before composition. Single-sources the (git ∪ pick) derivation + the
|
|
188
193
|
// glob sets for resolveGitMembership (compose + reconcile) and resolveMembershipEffects
|
|
189
|
-
// (derive per-file effect for clients,
|
|
194
|
+
// (derive per-file effect for clients, {§membership-resolved-effects}). Headless → null.
|
|
190
195
|
static async #resolveOverlayInputs(db, workspaceId, signal) {
|
|
191
196
|
const root = await GitMembership.#loadWorkspaceRoot(db, workspaceId);
|
|
192
197
|
if (root === null)
|
|
@@ -195,38 +200,39 @@ export default class GitMembership {
|
|
|
195
200
|
const hideGlobs = constraints.filter((c) => c.effect === "hide").map((c) => c.glob);
|
|
196
201
|
const pickGlobs = constraints.filter((c) => c.effect === "pick").map((c) => c.glob);
|
|
197
202
|
const viewGlobs = constraints.filter((c) => c.effect === "view").map((c) => c.glob);
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
// `pick` is then the sole source. No early-return on non-git.
|
|
203
|
-
const repoDirs = constraints.filter((c) => c.effect === "repo").map((c) => c.glob); // a declared repo's ls-files join membership, path-prefixed — §membership-overlay-repo
|
|
204
|
-
if (process.env.PLURNK_SERVICE_GIT_AUTO === "1")
|
|
205
|
-
repoDirs.push(root); // ALLOWED ceiling gates the AUTO default — §membership-git-flags
|
|
206
|
-
// #232 — git:false is a workspace-level tighten of the env ALLOWED ceiling (env AND workspace).
|
|
203
|
+
// The repository containing project_root is the sole Git substrate.
|
|
204
|
+
// PLURNK_SERVICE_GIT_ALLOWED=0 is the hard service ceiling and
|
|
205
|
+
// PLURNK_SERVICE_GIT_AUTO=0 disables automatic Git membership.
|
|
206
|
+
// {§operator-config-workspace-git} — git:false tightens the env ALLOWED ceiling.
|
|
207
207
|
const workspaceGit = (await WorkspaceSettings.read(db, workspaceId)).git;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
let gitMembers = [];
|
|
209
|
+
if (process.env.PLURNK_SERVICE_GIT_ALLOWED === "1"
|
|
210
|
+
&& process.env.PLURNK_SERVICE_GIT_AUTO === "1"
|
|
211
|
+
&& workspaceGit !== false) {
|
|
212
|
+
const repository = await GitMembership.#repoToplevel(root, signal);
|
|
213
|
+
if (repository !== null) {
|
|
214
|
+
gitMembers = await GitMembership.#projectMembers(root, repository, signal);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
211
217
|
// `pick` overlay — a targeted, client-dictated scan for untracked matches
|
|
212
218
|
// (node:fs glob over the client's pattern, never a blind walk).
|
|
213
|
-
const picked = pickGlobs.length === 0 ? [] : await GitMembership.#scanPickMembers(root, pickGlobs, signal); // §membership-overlay-pick
|
|
219
|
+
const picked = pickGlobs.length === 0 ? [] : await GitMembership.#scanPickMembers(root, pickGlobs, signal); // {§membership-overlay-pick}
|
|
214
220
|
return { root, gitMembers, picked, hideGlobs, viewGlobs };
|
|
215
221
|
}
|
|
216
222
|
// Resolve a workspace's file membership: the desired set is (git ls-files ∪ pick
|
|
217
|
-
// globs) − hide globs (SPEC §membership overlay), reconciled against the registered
|
|
223
|
+
// globs) − hide globs (SPEC {§membership} overlay), reconciled against the registered
|
|
218
224
|
// overlay-owned members so entries == members. Channel-less rows — disk is the
|
|
219
225
|
// truth (D3); the row is the membership marker File.read gates on. Returns the
|
|
220
226
|
// desired pathnames so the caller can materialize them through writeEntry.
|
|
221
227
|
//
|
|
222
228
|
// signal-respecting: git shell-outs + the pick scan honor `signal`. Headless
|
|
223
229
|
// (no project_root) yields nothing; a non-git root with pick-globs still resolves.
|
|
224
|
-
static async
|
|
230
|
+
static async #reconcileGitMembership(db, workspaceId, signal) {
|
|
225
231
|
const inputs = await GitMembership.#resolveOverlayInputs(db, workspaceId, signal);
|
|
226
232
|
if (inputs === null)
|
|
227
|
-
return []; // headless — no disk surface to resolve
|
|
233
|
+
return { members: [], removed: [] }; // headless — no disk surface to resolve
|
|
228
234
|
const { gitMembers: members, picked, hideGlobs } = inputs;
|
|
229
|
-
// Compose: (git ∪ pick) − hide (§membership-overlay-hide), tracking origin for reconciliation — a path
|
|
235
|
+
// Compose: (git ∪ pick) − hide ({§membership-overlay-hide}), tracking origin for reconciliation — a path
|
|
230
236
|
// in `members` is 'git', a pick-only match is 'constraint'.
|
|
231
237
|
const memberSet = new Set(members);
|
|
232
238
|
const passesHide = (p) => hideGlobs.length === 0 || !hideGlobs.some((g) => matchesGlob(p, g));
|
|
@@ -237,6 +243,7 @@ export default class GitMembership {
|
|
|
237
243
|
// so they match the parser's pathname the shared read helper queries by.
|
|
238
244
|
const desired = [...desiredGit, ...desiredPick]; // bare canon keys ({§fs-canonical-name}) — ls-files output IS the canon
|
|
239
245
|
const desiredSet = new Set(desired);
|
|
246
|
+
const candidateSet = new Set([...members, ...picked]);
|
|
240
247
|
// Reconcile so entries == members (the constitutive invariant): register the
|
|
241
248
|
// desired with their origin, then un-register any overlay-owned member ('git'
|
|
242
249
|
// or 'constraint') no longer desired — untracked, unmatched, or newly hidden.
|
|
@@ -249,18 +256,43 @@ export default class GitMembership {
|
|
|
249
256
|
await db.crud_register_workspace_member.get({ workspace_id: workspaceId, owner_id: commonsId, scheme: "file", pathname, membership_origin: "constraint" });
|
|
250
257
|
}
|
|
251
258
|
const registered = await db.crud_list_reconcilable_members.all({ workspace_id: workspaceId });
|
|
259
|
+
const removed = [];
|
|
252
260
|
for (const m of registered) {
|
|
253
261
|
if (!desiredSet.has(m.pathname)) {
|
|
262
|
+
// A path that left Git/pick membership also left disk truth (for
|
|
263
|
+
// example an untracked deletion or staged rename). A hide overlay
|
|
264
|
+
// is policy, not a filesystem occurrence, and is therefore silent.
|
|
265
|
+
if (!candidateSet.has(m.pathname)) {
|
|
266
|
+
const prior = await db.ops_read_channel.get({
|
|
267
|
+
workspace_id: workspaceId,
|
|
268
|
+
owner_id: commonsId,
|
|
269
|
+
scheme: "file",
|
|
270
|
+
pathname: m.pathname,
|
|
271
|
+
channel: "body",
|
|
272
|
+
});
|
|
273
|
+
if (prior !== undefined) {
|
|
274
|
+
removed.push({
|
|
275
|
+
pathname: m.pathname,
|
|
276
|
+
entryId: m.id,
|
|
277
|
+
channel: "body",
|
|
278
|
+
before: prior.content,
|
|
279
|
+
after: "",
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
254
283
|
await db.crud_delete_entry.run({ entry_id: m.id });
|
|
255
284
|
}
|
|
256
285
|
}
|
|
257
|
-
return desired;
|
|
286
|
+
return { members: desired, removed };
|
|
258
287
|
}
|
|
259
|
-
|
|
260
|
-
|
|
288
|
+
static async resolveGitMembership(db, workspaceId, signal) {
|
|
289
|
+
return (await GitMembership.#reconcileGitMembership(db, workspaceId, signal)).members;
|
|
290
|
+
}
|
|
291
|
+
// Resolve each candidate's membership effect without mutating — a read for clients
|
|
292
|
+
// ({§membership-resolved-effects}): the same (git ∪ pick) / hide / view resolution resolveGitMembership
|
|
261
293
|
// composes, surfaced per-file so a client signs member/view/hidden with ZERO glob-matching of
|
|
262
294
|
// its own. `members` are (git ∪ pick) − hide, each tagged `view` (read-only, refused at the
|
|
263
|
-
// File edit gate §membership-overlay-view) or plain `member`; `hidden` are candidates a `hide`
|
|
295
|
+
// File edit gate {§membership-overlay-view}) or plain `member`; `hidden` are candidates a `hide`
|
|
264
296
|
// glob excludes (project files absent from the manifest). Paths namespace-absolute, matching
|
|
265
297
|
// the manifest + storage. Headless → empty. {§membership-resolved-effects}
|
|
266
298
|
static async resolveMembershipEffects(db, workspaceId, signal) {
|
|
@@ -285,7 +317,7 @@ export default class GitMembership {
|
|
|
285
317
|
hidden.sort();
|
|
286
318
|
return { members, hidden };
|
|
287
319
|
}
|
|
288
|
-
// Targeted client-dictated scan (SPEC §membership `pick`) — enumerate disk files
|
|
320
|
+
// Targeted client-dictated scan (SPEC {§membership} `pick`) — enumerate disk files
|
|
289
321
|
// matching the client's pick-globs via node:fs glob (the pattern bounds the
|
|
290
322
|
// traversal; never a blind fs-walk). Files only — directories aren't members.
|
|
291
323
|
// Workspace-relative paths, the same shape as git ls-files.
|
|
@@ -306,18 +338,22 @@ export default class GitMembership {
|
|
|
306
338
|
}
|
|
307
339
|
return [...matches];
|
|
308
340
|
}
|
|
309
|
-
// Materialize a member's
|
|
341
|
+
// Materialize a member's model-readable snapshot into a body channel via writeEntry (the
|
|
310
342
|
// entry-write paradigm) — so it appears in the manifest catalog and is READ-able
|
|
311
|
-
// (D4/D5). Change-gated:
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
static async #materializeMember(pathname, root, ctx) {
|
|
343
|
+
// (D4/D5). Change-gated: text changes with mtime:size; binary projections also
|
|
344
|
+
// change when their opaque reader identity changes. A binary source persists
|
|
345
|
+
// only derived Unicode when its installed handler provides it, otherwise an
|
|
346
|
+
// empty typed marker ({§membership-source-projection}).
|
|
347
|
+
// A tracked path missing on disk retains membership but loses its stale
|
|
348
|
+
// readable channels; its explicit absent signature makes a later
|
|
349
|
+
// reappearance another observable divergence.
|
|
350
|
+
static async #materializeMember(pathname, root, ctx, identities) {
|
|
319
351
|
const canonical = join(root, pathname); // pathname is namespace-absolute (`/src/foo.ts`); join roots it at the workspace
|
|
320
|
-
|
|
352
|
+
const commonsId = await Owner.commonsId(ctx.db, ctx.workspaceId);
|
|
353
|
+
const known = await ctx.db.crud_get_member_sig.get({
|
|
354
|
+
workspace_id: ctx.workspaceId, owner_id: commonsId, scheme: "file", pathname,
|
|
355
|
+
});
|
|
356
|
+
// SPEC {§membership-change-gated-sync} — the cheap detect is a stat (mtime:size),
|
|
321
357
|
// never a content read: a member whose signature matches its last sync is a
|
|
322
358
|
// no-op (not re-read, re-tokenized, or rewritten). Coverage stays exhaustive
|
|
323
359
|
// (every member is stat'd); work is proportional to change.
|
|
@@ -332,24 +368,39 @@ export default class GitMembership {
|
|
|
332
368
|
sig = `${st.mtimeMs}:${st.size}`;
|
|
333
369
|
}
|
|
334
370
|
catch (err) {
|
|
335
|
-
if (err.code === "ENOENT")
|
|
336
|
-
|
|
371
|
+
if (err.code === "ENOENT") {
|
|
372
|
+
if (known === undefined || known.synced_sig === ABSENT_SIG)
|
|
373
|
+
return null;
|
|
374
|
+
const prior = await ctx.db.ops_read_channel.get({
|
|
375
|
+
workspace_id: ctx.workspaceId,
|
|
376
|
+
owner_id: commonsId,
|
|
377
|
+
scheme: "file",
|
|
378
|
+
pathname,
|
|
379
|
+
channel: "body",
|
|
380
|
+
});
|
|
381
|
+
await ctx.db.crud_delete_channels.run({ entry_id: known.id });
|
|
382
|
+
await ctx.db.crud_mark_member_absent.run({ entry_id: known.id });
|
|
383
|
+
return prior === undefined ? null : {
|
|
384
|
+
pathname,
|
|
385
|
+
entryId: known.id,
|
|
386
|
+
channel: "body",
|
|
387
|
+
before: prior.content,
|
|
388
|
+
after: "",
|
|
389
|
+
};
|
|
390
|
+
}
|
|
337
391
|
throw err;
|
|
338
392
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
393
|
+
if (known !== undefined && known.synced_sig === sig) {
|
|
394
|
+
const sourceProjection = sourceProjectionFrom(known.attributes);
|
|
395
|
+
if (sourceProjection === null)
|
|
396
|
+
return null;
|
|
397
|
+
const currentIdentity = await GitMembership.#projectionIdentity(sourceProjection.mimetype, ctx.mimetypes, identities);
|
|
398
|
+
if (currentIdentity === sourceProjection.identity)
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
344
401
|
const mimetype = await GitMembership.#detectMimetype(canonical, ctx.mimetypes);
|
|
345
|
-
if (MimetypeBinary.isBinaryMimetype(mimetype)) {
|
|
346
|
-
|
|
347
|
-
// class entry that READ-415s through readWorkspaceEntry's isBinaryMimetype
|
|
348
|
-
// gate (#186), not a channel-less row that would read as 404.
|
|
349
|
-
const r = await EntryCrud.writeEntry(pathname, { channels: { body: { content: "", mimetype } }, tags: [] }, ctx, "file");
|
|
350
|
-
if (r.entryId !== null)
|
|
351
|
-
await ctx.db.crud_set_synced_sig.run({ entry_id: r.entryId, synced_sig: sig });
|
|
352
|
-
return null; // binary bodies are empty markers — no text divergence to narrate
|
|
402
|
+
if (await MimetypeBinary.isBinaryMimetype(mimetype, ctx.mimetypes)) {
|
|
403
|
+
return GitMembership.#materializeBinary(pathname, { path: canonical }, mimetype, sig, known?.synced_sig !== sig, known?.synced_sig === ABSENT_SIG, ctx, identities);
|
|
353
404
|
}
|
|
354
405
|
let buf;
|
|
355
406
|
try {
|
|
@@ -360,34 +411,96 @@ export default class GitMembership {
|
|
|
360
411
|
return null;
|
|
361
412
|
throw err;
|
|
362
413
|
}
|
|
363
|
-
// §membership-binary-sniff
|
|
414
|
+
// {§membership-binary-sniff} — the extension map can lie (.wasm fell through to
|
|
364
415
|
// the markdown DEFAULT and a 3.3MB blob entered the corpus as prose, three copies,
|
|
365
416
|
// ~10M tokens). NUL bytes in the head are binary truth regardless of the label:
|
|
366
|
-
// re-stamp octet-stream and take the
|
|
367
|
-
// FTS'd/embedded/tokenized as text).
|
|
417
|
+
// re-stamp octet-stream and take the same bounded projection-or-marker arm.
|
|
368
418
|
if (buf.subarray(0, 8192).includes(0)) {
|
|
369
|
-
|
|
370
|
-
if (r.entryId !== null)
|
|
371
|
-
await ctx.db.crud_set_synced_sig.run({ entry_id: r.entryId, synced_sig: sig });
|
|
372
|
-
return null;
|
|
419
|
+
return GitMembership.#materializeBinary(pathname, { content: buf, hint: "application/octet-stream" }, "application/octet-stream", sig, known?.synced_sig !== sig, known?.synced_sig === ABSENT_SIG, ctx, identities);
|
|
373
420
|
}
|
|
374
421
|
const content = buf.toString("utf8");
|
|
375
|
-
// §env-delta — capture
|
|
376
|
-
//
|
|
377
|
-
// ambient divergence (D5). writeEntry then refreshes the entry to disk truth.
|
|
422
|
+
// {§env-delta-filesystem-narration} — capture the prior snapshot before
|
|
423
|
+
// materialization replaces it, then journal the resulting net span.
|
|
378
424
|
const prior = await ctx.db.ops_read_channel.get({
|
|
379
|
-
workspace_id: ctx.workspaceId, owner_id:
|
|
425
|
+
workspace_id: ctx.workspaceId, owner_id: commonsId, scheme: "file", pathname, channel: "body",
|
|
380
426
|
});
|
|
381
|
-
const result = await EntryCrud.writeEntry(pathname, { channels: { body: { content, mimetype } }, tags: [] }, ctx, "file");
|
|
427
|
+
const result = await EntryCrud.writeEntry(pathname, { channels: { body: { content, mimetype } }, tags: [], attributes: {} }, ctx, "file");
|
|
382
428
|
if (result.entryId !== null)
|
|
383
429
|
await ctx.db.crud_set_synced_sig.run({ entry_id: result.entryId, synced_sig: sig });
|
|
384
|
-
|
|
385
|
-
|
|
430
|
+
const changed = prior !== undefined && prior.content !== content;
|
|
431
|
+
if ((changed || known?.synced_sig === ABSENT_SIG) && result.entryId !== null) {
|
|
432
|
+
return { pathname, entryId: result.entryId, channel: "body", before: prior?.content ?? "", after: content };
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
static async #materializeBinary(pathname, input, mimetype, sig, diskChanged, previouslyAbsent, ctx, identities) {
|
|
437
|
+
const mimetypes = ctx.mimetypes;
|
|
438
|
+
if (mimetypes === undefined)
|
|
439
|
+
throw new Error("GitMembership: configured mimetype registry is required");
|
|
440
|
+
let content = "";
|
|
441
|
+
let outputMimetype = mimetype;
|
|
442
|
+
let metadata;
|
|
443
|
+
try {
|
|
444
|
+
const projected = await mimetypes.projectReadable(input);
|
|
445
|
+
if (projected === null) {
|
|
446
|
+
metadata = {
|
|
447
|
+
mimetype,
|
|
448
|
+
identity: await GitMembership.#projectionIdentity(mimetype, mimetypes, identities),
|
|
449
|
+
disposition: "unavailable",
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
content = projected.content;
|
|
454
|
+
outputMimetype = "text/markdown";
|
|
455
|
+
metadata = {
|
|
456
|
+
mimetype: projected.sourceMimetype,
|
|
457
|
+
identity: projected.projectionIdentity,
|
|
458
|
+
disposition: "projected",
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch (cause) {
|
|
463
|
+
if (!(cause instanceof MimetypeInputLimitError))
|
|
464
|
+
throw cause;
|
|
465
|
+
metadata = {
|
|
466
|
+
mimetype,
|
|
467
|
+
identity: await GitMembership.#projectionIdentity(mimetype, mimetypes, identities),
|
|
468
|
+
disposition: "input-limit",
|
|
469
|
+
maximumBytes: cause.maximumBytes,
|
|
470
|
+
observedBytes: cause.observedBytes,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
const prior = diskChanged && metadata.disposition === "projected"
|
|
474
|
+
? await ctx.db.ops_read_channel.get({
|
|
475
|
+
workspace_id: ctx.workspaceId,
|
|
476
|
+
owner_id: await Owner.commonsId(ctx.db, ctx.workspaceId),
|
|
477
|
+
scheme: "file",
|
|
478
|
+
pathname,
|
|
479
|
+
channel: "body",
|
|
480
|
+
})
|
|
481
|
+
: undefined;
|
|
482
|
+
const result = await EntryCrud.writeEntry(pathname, {
|
|
483
|
+
channels: { body: { content, mimetype: outputMimetype } },
|
|
484
|
+
tags: [],
|
|
485
|
+
attributes: { sourceProjection: metadata },
|
|
486
|
+
}, ctx, "file");
|
|
487
|
+
if (result.entryId !== null) {
|
|
488
|
+
await ctx.db.crud_set_synced_sig.run({ entry_id: result.entryId, synced_sig: sig });
|
|
489
|
+
}
|
|
490
|
+
const changed = prior !== undefined && prior.content !== content;
|
|
491
|
+
if ((changed || previouslyAbsent) && result.entryId !== null) {
|
|
492
|
+
return {
|
|
493
|
+
pathname,
|
|
494
|
+
entryId: result.entryId,
|
|
495
|
+
channel: "body",
|
|
496
|
+
before: prior?.content ?? "",
|
|
497
|
+
after: content,
|
|
498
|
+
};
|
|
386
499
|
}
|
|
387
500
|
return null;
|
|
388
501
|
}
|
|
389
502
|
// Full membership + materialization pass for a worker. Registers git members,
|
|
390
|
-
// then materializes each active
|
|
503
|
+
// then materializes each active on-disk member as an entry
|
|
391
504
|
// through writeEntry. Called at packet-composition time (Engine.runTurn) per
|
|
392
505
|
// D5. No-ops on headless / non-git workspaces.
|
|
393
506
|
static async indexGitMembership(ctx) {
|
|
@@ -411,10 +524,11 @@ export default class GitMembership {
|
|
|
411
524
|
const root = await GitMembership.#loadWorkspaceRoot(ctx.db, ctx.workspaceId);
|
|
412
525
|
if (root === null)
|
|
413
526
|
return [];
|
|
414
|
-
const
|
|
415
|
-
const divergences = [];
|
|
416
|
-
|
|
417
|
-
|
|
527
|
+
const resolution = await GitMembership.#reconcileGitMembership(ctx.db, ctx.workspaceId, ctx.signal);
|
|
528
|
+
const divergences = [...resolution.removed];
|
|
529
|
+
const identities = new Map();
|
|
530
|
+
for (const pathname of resolution.members) {
|
|
531
|
+
const divergence = await GitMembership.#materializeMember(pathname, root, ctx, identities);
|
|
418
532
|
if (divergence !== null)
|
|
419
533
|
divergences.push(divergence);
|
|
420
534
|
}
|