@amalgm/shell 0.1.164-main.40070365614 → 0.1.164-main.40795482467
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accepted-fold.d.ts +24 -46
- package/dist/accepted-fold.js +62 -140
- package/dist/accepted-fold.js.map +1 -1
- package/dist/accepted-tail.d.ts +3 -3
- package/dist/accepted-tail.js +6 -6
- package/dist/accepted-tail.js.map +1 -1
- package/dist/apply-control.d.ts +9 -4
- package/dist/apply-control.js +18 -5
- package/dist/apply-control.js.map +1 -1
- package/dist/apply-enter-build.d.ts +6 -7
- package/dist/apply-enter-build.js +4 -10
- package/dist/apply-enter-build.js.map +1 -1
- package/dist/apply-enter-plan.d.ts +9 -7
- package/dist/apply-enter-plan.js +40 -27
- package/dist/apply-enter-plan.js.map +1 -1
- package/dist/apply-local-work.d.ts +8 -20
- package/dist/apply-local-work.js +18 -95
- package/dist/apply-local-work.js.map +1 -1
- package/dist/apply-showing.d.ts +15 -1
- package/dist/apply-showing.js +26 -4
- package/dist/apply-showing.js.map +1 -1
- package/dist/apply-window-ground.d.ts +7 -9
- package/dist/apply-window-ground.js +16 -11
- package/dist/apply-window-ground.js.map +1 -1
- package/dist/apply-window-host.d.ts +29 -4
- package/dist/apply-window-host.js +212 -280
- package/dist/apply-window-host.js.map +1 -1
- package/dist/apply-window-line.d.ts +2 -1
- package/dist/apply-window-line.js +5 -4
- package/dist/apply-window-line.js.map +1 -1
- package/dist/apply-window-recovery.js +18 -30
- package/dist/apply-window-recovery.js.map +1 -1
- package/dist/apply-window-reveal.d.ts +0 -7
- package/dist/apply-window-reveal.js +5 -48
- package/dist/apply-window-reveal.js.map +1 -1
- package/dist/apply-window-rows.d.ts +1 -24
- package/dist/apply-window-rows.js.map +1 -1
- package/dist/apply-window-saves.d.ts +16 -9
- package/dist/apply-window-saves.js +65 -19
- package/dist/apply-window-saves.js.map +1 -1
- package/dist/apply-window-store.d.ts +6 -6
- package/dist/apply-window-store.js +7 -4
- package/dist/apply-window-store.js.map +1 -1
- package/dist/apply-window-verify.d.ts +4 -7
- package/dist/apply-window-verify.js +4 -23
- package/dist/apply-window-verify.js.map +1 -1
- package/dist/baseline-content.d.ts +3 -5
- package/dist/baseline-content.js +7 -44
- package/dist/baseline-content.js.map +1 -1
- package/dist/content-cache-retention.d.ts +3 -2
- package/dist/content-cache-retention.js +11 -11
- package/dist/content-cache-retention.js.map +1 -1
- package/dist/content-capture-pool.d.ts +4 -47
- package/dist/content-capture-pool.js +3 -42
- package/dist/content-capture-pool.js.map +1 -1
- package/dist/content-capture-worker.d.ts +2 -3
- package/dist/content-capture-worker.js +2 -19
- package/dist/content-capture-worker.js.map +1 -1
- package/dist/declaration-absorption.d.ts +9 -15
- package/dist/declaration-absorption.js +14 -32
- package/dist/declaration-absorption.js.map +1 -1
- package/dist/declaration-commit.d.ts +0 -5
- package/dist/declaration-commit.js +1 -6
- package/dist/declaration-commit.js.map +1 -1
- package/dist/declaration-save.d.ts +0 -4
- package/dist/declaration-save.js +0 -4
- package/dist/declaration-save.js.map +1 -1
- package/dist/detection/accepted-result.js +1 -1
- package/dist/detection/accepted-result.js.map +1 -1
- package/dist/detection/admission-save.d.ts +7 -17
- package/dist/detection/admission-save.js +4 -11
- package/dist/detection/admission-save.js.map +1 -1
- package/dist/detection/admission-units.d.ts +10 -26
- package/dist/detection/admission-units.js +12 -50
- package/dist/detection/admission-units.js.map +1 -1
- package/dist/detection/apply-ownership.d.ts +2 -2
- package/dist/detection/apply-ownership.js +2 -7
- package/dist/detection/apply-ownership.js.map +1 -1
- package/dist/detection/capture-outcome.js +12 -19
- package/dist/detection/capture-outcome.js.map +1 -1
- package/dist/detection/dispositions.d.ts +1 -1
- package/dist/detection/dispositions.js +3 -4
- package/dist/detection/dispositions.js.map +1 -1
- package/dist/detection/ground-proof.d.ts +1 -3
- package/dist/detection/ground-proof.js +0 -9
- package/dist/detection/ground-proof.js.map +1 -1
- package/dist/detection/ground-reader.d.ts +1 -5
- package/dist/detection/ground-reader.js +1 -31
- package/dist/detection/ground-reader.js.map +1 -1
- package/dist/detection/notebook-basis.d.ts +1 -2
- package/dist/detection/notebook-basis.js +2 -4
- package/dist/detection/notebook-basis.js.map +1 -1
- package/dist/detection/owed-selection.d.ts +2 -3
- package/dist/detection/owed-selection.js +3 -6
- package/dist/detection/owed-selection.js.map +1 -1
- package/dist/detection/portable.d.ts +7 -48
- package/dist/detection/portable.js +46 -155
- package/dist/detection/portable.js.map +1 -1
- package/dist/detection/repository-state.d.ts +35 -0
- package/dist/detection/repository-state.js +51 -0
- package/dist/detection/repository-state.js.map +1 -0
- package/dist/detection/root-examination.d.ts +1 -11
- package/dist/detection/root-examination.js +69 -127
- package/dist/detection/root-examination.js.map +1 -1
- package/dist/detection/runtime.d.ts +8 -32
- package/dist/detection/runtime.js +36 -140
- package/dist/detection/runtime.js.map +1 -1
- package/dist/detection/scope-frame.d.ts +32 -62
- package/dist/detection/scope-frame.js +139 -214
- package/dist/detection/scope-frame.js.map +1 -1
- package/dist/detection/scoped-identity-port.d.ts +1 -1
- package/dist/detection/scoped-identity-port.js +3 -4
- package/dist/detection/scoped-identity-port.js.map +1 -1
- package/dist/detection/walk-law.d.ts +3 -11
- package/dist/detection/walk-law.js +5 -9
- package/dist/detection/walk-law.js.map +1 -1
- package/dist/git/ground-owners.d.ts +8 -0
- package/dist/git/ground-owners.js +25 -0
- package/dist/git/ground-owners.js.map +1 -0
- package/dist/git/home.d.ts +39 -0
- package/dist/git/home.js +81 -0
- package/dist/git/home.js.map +1 -0
- package/dist/git/marker.d.ts +21 -0
- package/dist/git/marker.js +30 -0
- package/dist/git/marker.js.map +1 -0
- package/dist/git/objects.d.ts +42 -0
- package/dist/git/objects.js +144 -0
- package/dist/git/objects.js.map +1 -0
- package/dist/git/rail.d.ts +90 -0
- package/dist/git/rail.js +341 -0
- package/dist/git/rail.js.map +1 -0
- package/dist/git/read-state.d.ts +21 -0
- package/dist/git/read-state.js +143 -0
- package/dist/git/read-state.js.map +1 -0
- package/dist/git/repository.d.ts +48 -0
- package/dist/git/repository.js +110 -0
- package/dist/git/repository.js.map +1 -0
- package/dist/git/write-files.d.ts +9 -0
- package/dist/git/write-files.js +125 -0
- package/dist/git/write-files.js.map +1 -0
- package/dist/git-binding.d.ts +0 -53
- package/dist/git-binding.js +3 -114
- package/dist/git-binding.js.map +1 -1
- package/dist/git-command.js +11 -2
- package/dist/git-command.js.map +1 -1
- package/dist/git-index-entries.d.ts +7 -15
- package/dist/git-index-entries.js +3 -41
- package/dist/git-index-entries.js.map +1 -1
- package/dist/git-index-format.d.ts +4 -7
- package/dist/git-index-format.js +41 -106
- package/dist/git-index-format.js.map +1 -1
- package/dist/graph-publication.d.ts +6 -7
- package/dist/graph-publication.js +9 -21
- package/dist/graph-publication.js.map +1 -1
- package/dist/ground-basis.d.ts +1 -37
- package/dist/ground-basis.js +5 -162
- package/dist/ground-basis.js.map +1 -1
- package/dist/ground-database.js +0 -22
- package/dist/ground-database.js.map +1 -1
- package/dist/ground-install-saves.d.ts +0 -4
- package/dist/ground-install-saves.js +0 -4
- package/dist/ground-install-saves.js.map +1 -1
- package/dist/ground-inventory-schema.js +0 -3
- package/dist/ground-inventory-schema.js.map +1 -1
- package/dist/ground-marks.d.ts +7 -33
- package/dist/ground-marks.js +8 -55
- package/dist/ground-marks.js.map +1 -1
- package/dist/ground-relations.d.ts +2 -2
- package/dist/ground-relations.js +5 -10
- package/dist/ground-relations.js.map +1 -1
- package/dist/ground-row.d.ts +0 -7
- package/dist/ground-row.js +7 -12
- package/dist/ground-row.js.map +1 -1
- package/dist/ground-save-ops.d.ts +2 -1
- package/dist/ground-save-ops.js +2 -1
- package/dist/ground-save-ops.js.map +1 -1
- package/dist/ground-store.d.ts +0 -10
- package/dist/ground-store.js +19 -131
- package/dist/ground-store.js.map +1 -1
- package/dist/materialize-records.d.ts +19 -20
- package/dist/materialize-records.js +123 -244
- package/dist/materialize-records.js.map +1 -1
- package/dist/materialized-graph.d.ts +3 -22
- package/dist/materialized-graph.js +1 -142
- package/dist/materialized-graph.js.map +1 -1
- package/dist/received-state.d.ts +4 -6
- package/dist/received-state.js +6 -11
- package/dist/received-state.js.map +1 -1
- package/dist/root-install.d.ts +1 -2
- package/dist/root-install.js +2 -11
- package/dist/root-install.js.map +1 -1
- package/dist/sharing-admission.d.ts +1 -2
- package/dist/sharing-admission.js +8 -77
- package/dist/sharing-admission.js.map +1 -1
- package/dist/source-witness.d.ts +1 -7
- package/dist/source-witness.js +0 -12
- package/dist/source-witness.js.map +1 -1
- package/dist/user-ground-host.d.ts +21 -35
- package/dist/user-ground-host.js +423 -1484
- package/dist/user-ground-host.js.map +1 -1
- package/npm-shrinkwrap.json +24 -24
- package/package.json +5 -5
- package/dist/apply-window-repository.d.ts +0 -97
- package/dist/apply-window-repository.js +0 -464
- package/dist/apply-window-repository.js.map +0 -1
- package/dist/detection/codec-standing.d.ts +0 -27
- package/dist/detection/codec-standing.js +0 -86
- package/dist/detection/codec-standing.js.map +0 -1
- package/dist/detection/git-notice.d.ts +0 -104
- package/dist/detection/git-notice.js +0 -483
- package/dist/detection/git-notice.js.map +0 -1
- package/dist/detection/held-survey.d.ts +0 -39
- package/dist/detection/held-survey.js +0 -105
- package/dist/detection/held-survey.js.map +0 -1
- package/dist/detection/held-territory.d.ts +0 -73
- package/dist/detection/held-territory.js +0 -266
- package/dist/detection/held-territory.js.map +0 -1
- package/dist/detection/name-reach.d.ts +0 -12
- package/dist/detection/name-reach.js +0 -28
- package/dist/detection/name-reach.js.map +0 -1
- package/dist/detection/own-channel.d.ts +0 -17
- package/dist/detection/own-channel.js +0 -31
- package/dist/detection/own-channel.js.map +0 -1
- package/dist/detection/repository-publication.d.ts +0 -22
- package/dist/detection/repository-publication.js +0 -81
- package/dist/detection/repository-publication.js.map +0 -1
- package/dist/detection/repository-routes.d.ts +0 -50
- package/dist/detection/repository-routes.js +0 -118
- package/dist/detection/repository-routes.js.map +0 -1
- package/dist/detection/repository-seals.d.ts +0 -98
- package/dist/detection/repository-seals.js +0 -145
- package/dist/detection/repository-seals.js.map +0 -1
- package/dist/detection/seal-law.d.ts +0 -59
- package/dist/detection/seal-law.js +0 -103
- package/dist/detection/seal-law.js.map +0 -1
- package/dist/git-capture.d.ts +0 -47
- package/dist/git-capture.js +0 -153
- package/dist/git-capture.js.map +0 -1
- package/dist/git-card.d.ts +0 -30
- package/dist/git-card.js +0 -136
- package/dist/git-card.js.map +0 -1
- package/dist/git-checkpoint-construction.d.ts +0 -54
- package/dist/git-checkpoint-construction.js +0 -126
- package/dist/git-checkpoint-construction.js.map +0 -1
- package/dist/git-checkpoint-preparation.d.ts +0 -47
- package/dist/git-checkpoint-preparation.js +0 -201
- package/dist/git-checkpoint-preparation.js.map +0 -1
- package/dist/git-configuration.d.ts +0 -53
- package/dist/git-configuration.js +0 -238
- package/dist/git-configuration.js.map +0 -1
- package/dist/git-evidence.d.ts +0 -50
- package/dist/git-evidence.js +0 -114
- package/dist/git-evidence.js.map +0 -1
- package/dist/git-facts.d.ts +0 -2
- package/dist/git-facts.js +0 -35
- package/dist/git-facts.js.map +0 -1
- package/dist/git-index-witness.d.ts +0 -34
- package/dist/git-index-witness.js +0 -85
- package/dist/git-index-witness.js.map +0 -1
- package/dist/git-literal-batch.d.ts +0 -82
- package/dist/git-literal-batch.js +0 -152
- package/dist/git-literal-batch.js.map +0 -1
- package/dist/git-literal-host.d.ts +0 -76
- package/dist/git-literal-host.js +0 -185
- package/dist/git-literal-host.js.map +0 -1
- package/dist/git-literal-read.d.ts +0 -74
- package/dist/git-literal-read.js +0 -186
- package/dist/git-literal-read.js.map +0 -1
- package/dist/git-literal-replay.d.ts +0 -83
- package/dist/git-literal-replay.js +0 -393
- package/dist/git-literal-replay.js.map +0 -1
- package/dist/git-native-file.d.ts +0 -42
- package/dist/git-native-file.js +0 -145
- package/dist/git-native-file.js.map +0 -1
- package/dist/git-native-index.d.ts +0 -27
- package/dist/git-native-index.js +0 -44
- package/dist/git-native-index.js.map +0 -1
- package/dist/git-operation-host.d.ts +0 -42
- package/dist/git-operation-host.js +0 -115
- package/dist/git-operation-host.js.map +0 -1
- package/dist/git-private-repository.d.ts +0 -4
- package/dist/git-private-repository.js +0 -66
- package/dist/git-private-repository.js.map +0 -1
- package/dist/git-private-view.d.ts +0 -72
- package/dist/git-private-view.js +0 -318
- package/dist/git-private-view.js.map +0 -1
- package/dist/git-records.d.ts +0 -29
- package/dist/git-records.js +0 -119
- package/dist/git-records.js.map +0 -1
- package/dist/git-ref-store.d.ts +0 -12
- package/dist/git-ref-store.js +0 -68
- package/dist/git-ref-store.js.map +0 -1
- package/dist/git-registration-host.d.ts +0 -42
- package/dist/git-registration-host.js +0 -98
- package/dist/git-registration-host.js.map +0 -1
- package/dist/git-repository-host.d.ts +0 -291
- package/dist/git-repository-host.js +0 -1291
- package/dist/git-repository-host.js.map +0 -1
- package/dist/git-spelling.d.ts +0 -41
- package/dist/git-spelling.js +0 -233
- package/dist/git-spelling.js.map +0 -1
- package/dist/git-tree-objects.d.ts +0 -22
- package/dist/git-tree-objects.js +0 -205
- package/dist/git-tree-objects.js.map +0 -1
- package/dist/git-worktree-host.d.ts +0 -2
- package/dist/git-worktree-host.js +0 -16
- package/dist/git-worktree-host.js.map +0 -1
- package/dist/ground-territory.d.ts +0 -106
- package/dist/ground-territory.js +0 -340
- package/dist/ground-territory.js.map +0 -1
- package/dist/repository-checkpoint-file.d.ts +0 -20
- package/dist/repository-checkpoint-file.js +0 -129
- package/dist/repository-checkpoint-file.js.map +0 -1
- package/dist/repository-statement.d.ts +0 -21
- package/dist/repository-statement.js +0 -33
- package/dist/repository-statement.js.map +0 -1
- package/dist/reveal-owner.d.ts +0 -16
- package/dist/reveal-owner.js +0 -74
- package/dist/reveal-owner.js.map +0 -1
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* - Verify (#verify): one reread of real ground, its rows staged for the end;
|
|
15
15
|
* - the durability point (apply-durability.ts), owed where the window placed
|
|
16
16
|
* its results, runs at idle or at the cap. */
|
|
17
|
-
import { chmodSync, copyFileSync, lstatSync, readFileSync, readdirSync, readlinkSync, rmSync } from "node:fs";
|
|
18
|
-
import { rm } from "node:fs/promises";
|
|
17
|
+
import { chmodSync, copyFileSync, lstatSync, readFileSync, readdirSync, readlinkSync, rmSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { readFile, rm } from "node:fs/promises";
|
|
19
19
|
import { basename, dirname, join, relative } from "node:path";
|
|
20
|
-
import { CONTAINERS, buildEntityApplyEffects, isRefusal, portableFileMode,
|
|
20
|
+
import { CONTAINERS, buildEntityApplyEffects, classifyFile, isRefusal, portableFileMode, resolvedPrefix, revealOrder } from "@amalgm/live";
|
|
21
21
|
import { LOCAL_DIR_NAME } from "@amalgm/core/identity";
|
|
22
|
-
import { applyControlRoot, displacedGitPath, displacedPath, enterControl, ensureApplyPrivate, judgeBoundRoot, stagedPath, windowControl } from "./apply-control.js";
|
|
22
|
+
import { applyControlRoot, displacedGitPath, displacedPath, enterControl, ensureApplyPrivate, gitPartPath, judgeBoundRoot, readGitPart, stagedPath, windowControl } from "./apply-control.js";
|
|
23
23
|
import { ApplyDurability } from "./apply-durability.js";
|
|
24
24
|
import { keepRemainder, returnKept, topmostRemainder, vacateKept } from "./apply-kept.js";
|
|
25
25
|
import { flushEach } from "./flush.js";
|
|
@@ -27,41 +27,46 @@ import { WindowCargo } from "./apply-window-cargo.js";
|
|
|
27
27
|
import { boundEnter, enterStaging, prepareEnter, sealShows } from "./apply-enter-build.js";
|
|
28
28
|
import { divideEnter, entersContainer, readEnterClosure } from "./apply-enter-plan.js";
|
|
29
29
|
import { captureGitStorage, displaceGitStorage, keptStorageIsO } from "./apply-git-storage.js";
|
|
30
|
-
import {
|
|
31
|
-
import { ShownGround } from "./apply-showing.js";
|
|
30
|
+
import { NOTHING_ON_DEMAND, ShownGround } from "./apply-showing.js";
|
|
32
31
|
import { holds, moveWithoutReplacing, occupiedByOther, standing } from "./apply-spelling.js";
|
|
33
32
|
import { ApplyWindowStore } from "./apply-window-store.js";
|
|
34
33
|
import { heldCovers, isContainerType, meetsAny, placedByBinding, tryLstat, WindowGround } from "./apply-window-ground.js";
|
|
35
34
|
import { containerGround, enterGround, leaveGround, receiptStats, readVerificationFacts, roomRows, verifiedRow } from "./apply-window-verify.js";
|
|
36
|
-
import { RepositoryGround, repositoryArtifact, repositoryMembers } from "./apply-window-repository.js";
|
|
37
35
|
import { boundAttempts, readEndedWindows, readWindow } from "./apply-window-rows.js";
|
|
38
36
|
import { recoveryVerdict } from "./apply-window-recovery.js";
|
|
39
|
-
import {
|
|
37
|
+
import { replaceAt, stageDirectory, takeSource } from "./apply-window-reveal.js";
|
|
40
38
|
import { constructApplyAdapters } from "./construct-apply-host.js";
|
|
41
39
|
import { ConstructLedger } from "./construct-ledger.js";
|
|
42
40
|
import { contentCacheOwnership } from "./content-cache-ownership.js";
|
|
41
|
+
import { captureContent } from "./content-capture-pool.js";
|
|
43
42
|
import { stampAfterWrites } from "./content-clock.js";
|
|
44
43
|
import { DerivedRelocationCycle, relocateDerived } from "./derived-relocation.js";
|
|
45
44
|
import { ApplyOwnershipSnapshot, ownedObject, ownershipWait, sqliteApplyOwnership, windowFootprint } from "./detection/apply-ownership.js";
|
|
46
45
|
import { settledCaptureOutcome } from "./detection/capture-outcome.js";
|
|
46
|
+
import { cachedNotebook } from "./detection/repository-state.js";
|
|
47
47
|
import { ensureDirBeneath } from "./filesystem.js";
|
|
48
48
|
import { reflogKeys, repositoryGroundCones } from "./git-binding.js";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import { unsupportedGitOperation, UnsupportedGitOperationError } from "./git-operation-host.js";
|
|
53
|
-
import { applyRepositoryFiles, hasGitMarker, cachedRepositoryIdentity, repositoryRevealRefusal } from "./git-repository-host.js";
|
|
54
|
-
import { inspectGitWorktreeStorage } from "./git-worktree-host.js";
|
|
49
|
+
import { hasGitMarker } from "./git/marker.js";
|
|
50
|
+
import { groundGitOwners } from "./git/ground-owners.js";
|
|
51
|
+
import { applyGit, GitApplyWait, gitStateIdOf } from "./git/rail.js";
|
|
55
52
|
import { openGroundConnection } from "./ground-database.js";
|
|
56
53
|
import { portableGroundRecord as portable } from "./ground-row.js";
|
|
57
|
-
import { writeLinkTarget } from "./link-target.js";
|
|
54
|
+
import { readLinkTarget, writeLinkTarget } from "./link-target.js";
|
|
58
55
|
import { addressWitness, optionalLstat, PhysicalPathWitnesses } from "./physical-path-witness.js";
|
|
59
56
|
import { HeldHeads, ReceivedStateUnavailableError } from "./received-state.js";
|
|
60
|
-
import { revealStorageOf, revealStoragePhysical } from "./reveal-owner.js";
|
|
61
57
|
import { sha256Hex } from "./sha256.js";
|
|
62
58
|
import { closePhysically, closeSource, sourceProofs, witnessProof } from "./source-proof.js";
|
|
63
59
|
import { physicalKey, sourceReusable, sourceSignature } from "./source-signature.js";
|
|
64
60
|
import { awaitTurn } from "./turns.js";
|
|
61
|
+
/** The immutable artifact a repository or structural result names, if any. */
|
|
62
|
+
const resultArtifact = (plan) => plan.kind === "repo.git" ? plan.artifact : plan.kind === "structure" ? plan.resultArtifact : null;
|
|
63
|
+
/** Apply cannot act on a repository yet (src/git/rail.ts). A worktree or
|
|
64
|
+
* submodule waits on the repository whose Git directory holds its own, whose
|
|
65
|
+
* Apply releases it; any other wait, on a change there, which Detect
|
|
66
|
+
* observes. */
|
|
67
|
+
const gitWait = (intent, error) => ({ kind: "dependency", reason: error.message, waitFor: error.owner
|
|
68
|
+
? { producer: "apply", entityIds: [error.owner] }
|
|
69
|
+
: { producer: "capability", entityIds: [intent.entityId] } });
|
|
65
70
|
const objectOf = (path, stats) => ({ path, physicalKey: physicalKey(stats), signature: sourceSignature(stats) });
|
|
66
71
|
/** The member's kind, from its plan. */
|
|
67
72
|
const kindOf = (plan) => {
|
|
@@ -85,7 +90,6 @@ const kindOf = (plan) => {
|
|
|
85
90
|
const declined = (reason) => ({ kind: "declined", reason });
|
|
86
91
|
/** The receipts whose reveal can take a container from its address. */
|
|
87
92
|
const DISPLACING = new Set(["leave", "leaf", "link", "reference"]);
|
|
88
|
-
const isWait = (value) => "kind" in value && value.kind === "dependency";
|
|
89
93
|
/** One persistent machine-effect owner for the Apply rail lifetime. */
|
|
90
94
|
export class ApplyWindowHost {
|
|
91
95
|
store;
|
|
@@ -103,14 +107,20 @@ export class ApplyWindowHost {
|
|
|
103
107
|
#acquireGround;
|
|
104
108
|
#onStage;
|
|
105
109
|
#onWindowEnded;
|
|
110
|
+
#onDemand;
|
|
111
|
+
/** The units something opened, each answered once its line ends it, and
|
|
112
|
+
* the wake that rings that line. */
|
|
113
|
+
#opening = new Map();
|
|
106
114
|
#now;
|
|
107
115
|
#ground;
|
|
116
|
+
/** The repositories this machine holds, where worktrees and submodules
|
|
117
|
+
* find the Git directory that holds their own (src/git/home.ts). */
|
|
118
|
+
#gitOwners;
|
|
108
119
|
#onDerivedRelocationStage;
|
|
109
120
|
#prepared = new Map();
|
|
110
121
|
#enterClosures = new Map();
|
|
111
122
|
/** The ground the window in flight holds. */
|
|
112
123
|
#held = null;
|
|
113
|
-
#repository;
|
|
114
124
|
/** The Git storage manifest a final guard took before proving a repository
|
|
115
125
|
* is O, for the receipt the same pass freezes. */
|
|
116
126
|
#gitStorage = new Map();
|
|
@@ -123,10 +133,12 @@ export class ApplyWindowHost {
|
|
|
123
133
|
// Read-only: the file's saver thread makes every write this host posts.
|
|
124
134
|
this.#database = openGroundConnection(options.databaseFile);
|
|
125
135
|
this.#now = options.now ?? Date.now;
|
|
136
|
+
this.#onDemand = { root: options.onDemand ?? NOTHING_ON_DEMAND.root, opened: uuid => this.#opening.has(uuid) };
|
|
126
137
|
this.durability = new ApplyDurability({ databaseFile: options.databaseFile,
|
|
127
138
|
...(options.onBackgroundError ? { onError: options.onBackgroundError } : {}) });
|
|
128
139
|
this.store = new ApplyWindowStore(this.#database, {
|
|
129
140
|
now: this.#now,
|
|
141
|
+
onDemand: this.#onDemand,
|
|
130
142
|
onEnded: (intent, members) => this.#ended(intent, members),
|
|
131
143
|
// Not a failure: the line proves again at its next fair turn.
|
|
132
144
|
onStale: (members, reason) => {
|
|
@@ -144,18 +156,12 @@ export class ApplyWindowHost {
|
|
|
144
156
|
readAhead: (authorityId, after, limit) => this.store.readApplyAhead(authorityId, after, limit),
|
|
145
157
|
fetch: async (wants) => { await this.#cargo.read(wants); },
|
|
146
158
|
};
|
|
147
|
-
this.#heads = new HeldHeads(options.readGraphPage
|
|
159
|
+
this.#heads = new HeldHeads(options.readGraphPage);
|
|
148
160
|
this.#acquireGround = options.acquireGround;
|
|
149
161
|
this.#onStage = options.onStage;
|
|
150
162
|
this.#onWindowEnded = options.onWindowEnded;
|
|
151
163
|
this.#ground = new WindowGround(this.#database);
|
|
152
|
-
this.#
|
|
153
|
-
matches: (intent, record, path, plan) => this.#matches(intent, record, path, plan),
|
|
154
|
-
prepared: (intent, plan) => this.#ensurePrepared(intent, plan),
|
|
155
|
-
receiptOf: intent => this.#receiptOf(intent),
|
|
156
|
-
readOne: artifact => this.#cargo.readOne(artifact),
|
|
157
|
-
key: intent => this.#key(intent),
|
|
158
|
-
});
|
|
164
|
+
this.#gitOwners = groundGitOwners(this.#database);
|
|
159
165
|
this.#onDerivedRelocationStage = options.onDerivedRelocationStage;
|
|
160
166
|
// Every type in Live's alphabet binds both sockets or the registry
|
|
161
167
|
// refuses to build. Filesystem entities reread their native ground;
|
|
@@ -255,11 +261,21 @@ export class ApplyWindowHost {
|
|
|
255
261
|
});
|
|
256
262
|
}
|
|
257
263
|
// ---------------------------------------------------------------- prepare
|
|
264
|
+
/** A repository in an Enter that cannot be built yet, such as a linked
|
|
265
|
+
* worktree whose main checkout's Apply has yet to bring its objects,
|
|
266
|
+
* waits on it, so the window ends before it (journey.ts). */
|
|
258
267
|
async #prepare(intent, plan) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
try {
|
|
269
|
+
if (entersContainer(plan))
|
|
270
|
+
await this.#prepareEnter(intent, plan);
|
|
271
|
+
else
|
|
272
|
+
await this.#ensurePrepared(intent, plan);
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
if (error instanceof GitApplyWait)
|
|
276
|
+
return gitWait(intent, error);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
263
279
|
}
|
|
264
280
|
async #ensurePrepared(intent, plan) {
|
|
265
281
|
const key = this.#key(intent);
|
|
@@ -274,24 +290,12 @@ export class ApplyWindowHost {
|
|
|
274
290
|
}
|
|
275
291
|
this.#emit(intent, plan, "preparation-started");
|
|
276
292
|
let prepared = {};
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
279
|
-
const chain = await this.#repository.chain(repository);
|
|
280
|
-
const latest = chain.links.at(-1).layout;
|
|
281
|
-
if (repositoryPayloadVersion(latest, sha256Hex) !== plan.target.payloadVersion
|
|
282
|
-
|| (plan.kind === "repo.git" && (latest.stateId !== plan.stateId
|
|
283
|
-
|| latest.cardId !== plan.cardId || latest.checkpointId !== plan.checkpointId
|
|
284
|
-
|| latest.identityHash !== plan.identityHash
|
|
285
|
-
|| latest.parentTransportVersion !== plan.parentTransportVersion))) {
|
|
286
|
-
throw new Error("repository package does not describe the accepted complete result");
|
|
287
|
-
}
|
|
288
|
-
prepared = { repository: { ...chain, objectFormat: latest.card.objectFormat } };
|
|
289
|
-
}
|
|
290
|
-
else if (plan.kind === "file.text" || plan.kind === "file.binary" || plan.kind === "link") {
|
|
293
|
+
const artifact = resultArtifact(plan);
|
|
294
|
+
if (plan.kind === "file.text" || plan.kind === "file.binary" || plan.kind === "link") {
|
|
291
295
|
prepared = { artifact: await this.#cargo.prepare(plan) };
|
|
292
296
|
}
|
|
293
|
-
else if (
|
|
294
|
-
prepared = { artifact: await this.#cargo.sealed(
|
|
297
|
+
else if (artifact) {
|
|
298
|
+
prepared = { artifact: await this.#cargo.sealed(artifact.contentHash) ?? await this.#cargo.readOne(artifact) };
|
|
295
299
|
}
|
|
296
300
|
this.#prepared.set(key, prepared);
|
|
297
301
|
this.#emit(intent, plan, "cargo-verified");
|
|
@@ -329,8 +333,8 @@ export class ApplyWindowHost {
|
|
|
329
333
|
targetPath: context.targetPath },
|
|
330
334
|
clockRoot: this.#ground.bindingRoot(context),
|
|
331
335
|
databaseFile: this.#database.name,
|
|
332
|
-
cacheDir: this.#cacheDir,
|
|
333
336
|
bindingDir: this.#bindingDir,
|
|
337
|
+
held: this.#gitOwners,
|
|
334
338
|
readContent: artifacts => this.#cargo.read(artifacts.map(artifact => ({ artifact }))),
|
|
335
339
|
});
|
|
336
340
|
this.#emit(intent, plan, "cargo-verified");
|
|
@@ -342,7 +346,8 @@ export class ApplyWindowHost {
|
|
|
342
346
|
const key = this.#key(intent);
|
|
343
347
|
let closure = this.#enterClosures.get(key);
|
|
344
348
|
if (!closure) {
|
|
345
|
-
closure = await readEnterClosure({ database: this.#database, intent, target: plan.target, heads: this.#heads
|
|
349
|
+
closure = await readEnterClosure({ database: this.#database, intent, target: plan.target, heads: this.#heads,
|
|
350
|
+
unit: new ShownGround(this.#database, this.#onDemand).beneathOnDemand(plan.target) });
|
|
346
351
|
this.#enterClosures.set(key, closure);
|
|
347
352
|
}
|
|
348
353
|
const division = await divideEnter(closure.records, plan.target.uuid, uuid => this.#ground.current(uuid) !== null);
|
|
@@ -353,7 +358,6 @@ export class ApplyWindowHost {
|
|
|
353
358
|
this.#prepared.delete(key);
|
|
354
359
|
this.#enterClosures.delete(key);
|
|
355
360
|
this.#gitStorage.delete(key);
|
|
356
|
-
this.#repository.forget(key);
|
|
357
361
|
}
|
|
358
362
|
// ------------------------------------------------------------------ guard
|
|
359
363
|
/** Only a final safe or already-target guard keeps its member in the window. */
|
|
@@ -373,7 +377,6 @@ export class ApplyWindowHost {
|
|
|
373
377
|
async #inspectGround(intent, plan, stage) {
|
|
374
378
|
const finalGuard = stage === "final";
|
|
375
379
|
const key = this.#key(intent);
|
|
376
|
-
this.#repository.forget(key);
|
|
377
380
|
this.#gitStorage.delete(key);
|
|
378
381
|
try {
|
|
379
382
|
if (finalGuard) {
|
|
@@ -387,7 +390,7 @@ export class ApplyWindowHost {
|
|
|
387
390
|
}
|
|
388
391
|
// The line judged this play from the tables, and Detect may have
|
|
389
392
|
// changed them since: a play that no longer holds is judged again.
|
|
390
|
-
const judged = new ShownGround(this.#database).judge(plan.target);
|
|
393
|
+
const judged = new ShownGround(this.#database, this.#onDemand).judge(plan.target);
|
|
391
394
|
if (judged !== plan.play) {
|
|
392
395
|
return { kind: "rejudge", reason: `The accepted result now plays ${judged} on this computer, not ${plan.play}.` };
|
|
393
396
|
}
|
|
@@ -417,9 +420,6 @@ export class ApplyWindowHost {
|
|
|
417
420
|
.every(row => row === null || row === undefined || this.#ground.directoryAncestorsMatch(row, directories))) {
|
|
418
421
|
return replacedParent;
|
|
419
422
|
}
|
|
420
|
-
let repositoryTargetMatches = false;
|
|
421
|
-
let repositoryRelocationsPending = false;
|
|
422
|
-
let repositoryIdentityMatches = true;
|
|
423
423
|
// A reveal installs the repository's own `.git` where the entity
|
|
424
424
|
// stands. A `.git` there that names no repository exists only on this
|
|
425
425
|
// computer, so the reveal waits until the person removes or repairs it.
|
|
@@ -429,68 +429,18 @@ export class ApplyWindowHost {
|
|
|
429
429
|
blocker: { code: "local-ground-would-be-displaced", effect: "repository-reveal" },
|
|
430
430
|
reason: `${current.absolutePath} holds Git metadata that names no repository; only this computer has it.` };
|
|
431
431
|
}
|
|
432
|
-
if (plan
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const storage = await inspectGitWorktreeStorage(path);
|
|
437
|
-
const unsupported = unsupportedGitOperation(storage.privateDirectory);
|
|
438
|
-
if (unsupported) {
|
|
439
|
-
return { kind: "dependency", reason: new UnsupportedGitOperationError(unsupported).message,
|
|
440
|
-
waitFor: { producer: "capability", entityIds: [intent.entityId] } };
|
|
441
|
-
}
|
|
442
|
-
if (repositorySharesWorktreeStorage(storage)) {
|
|
443
|
-
return { kind: "dependency",
|
|
444
|
-
reason: "This checkout shares Git storage with another worktree. Apply requires an independent checkout.",
|
|
445
|
-
waitFor: { producer: "capability", entityIds: [intent.entityId] },
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
if (entersContainer(plan)) {
|
|
432
|
+
if (entersContainer(plan) && finalGuard) {
|
|
433
|
+
// The build assumed the ground's division and its address. A build
|
|
434
|
+
// that no longer shows them is dropped and built again by the next
|
|
435
|
+
// attempt.
|
|
451
436
|
const { closure, division } = await this.#enterDivision(intent, plan);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (!enter || !holds(enter.tree, enter.seal.root) || !sealShows(enter.seal, { target: plan.target,
|
|
458
|
-
position: closure.position, leftOut: division.leftOut, targetPath: context.targetPath })) {
|
|
459
|
-
this.#prepared.delete(key);
|
|
460
|
-
return { kind: "retry", reason: "The entering tree no longer shows this computer's ground; it is built again." };
|
|
461
|
-
}
|
|
462
|
-
for (const group of this.#repository.enterRelocations(context.targetPath, enter)) {
|
|
463
|
-
for (const row of group.rows) {
|
|
464
|
-
if (!await this.#matches(intent, portable(row), row.absolutePath, plan)) {
|
|
465
|
-
return { kind: "retry", reason: `repository relocation ${row.uuid} changed before Apply` };
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
437
|
+
const enter = this.#prepared.get(key)?.enter;
|
|
438
|
+
if (!enter || !holds(enter.tree, enter.seal.root) || !sealShows(enter.seal, { target: plan.target,
|
|
439
|
+
position: closure.position, leftOut: division.leftOut, targetPath: context.targetPath })) {
|
|
440
|
+
this.#prepared.delete(key);
|
|
441
|
+
return { kind: "retry", reason: "The entering tree no longer shows this computer's ground; it is built again." };
|
|
469
442
|
}
|
|
470
443
|
}
|
|
471
|
-
else if (plan.target.type === "repo.git" && !leaving) {
|
|
472
|
-
const repository = (await this.#ensurePrepared(intent, plan)).repository;
|
|
473
|
-
if (!repository)
|
|
474
|
-
throw new Error("repository Apply has no prepared transport identity");
|
|
475
|
-
// The result acts only on its territory, so ground another rail owns
|
|
476
|
-
// here never waits on that rail's later record (docs/entity-apply.md).
|
|
477
|
-
const territory = this.#repository.territory(intent, repository.identity, context.current);
|
|
478
|
-
const ground = current && tryLstat(current.absolutePath) ? current.absolutePath : context.targetPath;
|
|
479
|
-
const refused = await repositoryRevealRefusal(ground, root, repository.objectFormat, !hasGitMarker(ground));
|
|
480
|
-
if (refused)
|
|
481
|
-
return { kind: "dependency", reason: refused, waitFor: { producer: "capability", entityIds: [intent.entityId] } };
|
|
482
|
-
const groups = this.#repository.relocations(context, territory.identity);
|
|
483
|
-
for (const group of groups) {
|
|
484
|
-
for (const row of group.rows) {
|
|
485
|
-
if (!await this.#matches(intent, portable(row), row.absolutePath, plan)) {
|
|
486
|
-
return { kind: "retry", reason: `repository relocation ${row.uuid} changed before Apply` };
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
repositoryRelocationsPending = groups.length > 0;
|
|
491
|
-
repositoryIdentityMatches = this.#repository.identityMatches(intent, context.targetPath, repository.identity);
|
|
492
|
-
repositoryTargetMatches = current !== null && await this.#matches(intent, plan.target, context.targetPath, plan);
|
|
493
|
-
}
|
|
494
444
|
// Identity comes from O, never a historical sharing address or byte
|
|
495
445
|
// equality. A same-identity complete target can be adopted even when B
|
|
496
446
|
// lags, provided no other physical effect remains. A Leave's target
|
|
@@ -501,10 +451,8 @@ export class ApplyWindowHost {
|
|
|
501
451
|
&& physical.absolutePath === context.targetPath
|
|
502
452
|
&& targetStats !== null && physicalKey(targetStats) === physical.physicalKey;
|
|
503
453
|
if (targetIdentity
|
|
504
|
-
&& repositoryIdentityMatches
|
|
505
|
-
&& !repositoryRelocationsPending
|
|
506
454
|
&& context.room.length === 0
|
|
507
|
-
&&
|
|
455
|
+
&& await this.#matches(intent, plan.target, context.targetPath, plan)
|
|
508
456
|
&& this.#ground.physicalDirectoriesMatch(physical, directories)) {
|
|
509
457
|
if (!this.#ground.directoriesStand(directories))
|
|
510
458
|
return replacedParent;
|
|
@@ -512,8 +460,6 @@ export class ApplyWindowHost {
|
|
|
512
460
|
const receipt = await this.#receipt(intent, plan, context, "already-target");
|
|
513
461
|
if (receipt === null)
|
|
514
462
|
return { kind: "local-change", reason: "The ground this member stands on changed after its guard." };
|
|
515
|
-
if (isWait(receipt))
|
|
516
|
-
return receipt;
|
|
517
463
|
this.store.stageReceipt(receipt);
|
|
518
464
|
}
|
|
519
465
|
return { kind: "already-target" };
|
|
@@ -532,13 +478,13 @@ export class ApplyWindowHost {
|
|
|
532
478
|
// effect waits for Detect to see that ground leave or become shared.
|
|
533
479
|
if (current && isContainerType(current.type) && tryLstat(current.absolutePath)
|
|
534
480
|
&& (leaving || !isContainerType(plan.target.type))) {
|
|
535
|
-
const named = this.#
|
|
481
|
+
const named = this.#ground.unsharedGitWithin(current.absolutePath);
|
|
536
482
|
if (named.length > 0) {
|
|
537
483
|
return { kind: "dependency", waitFor: { producer: "detect", entityIds: named },
|
|
538
484
|
blocker: { code: "local-ground-would-be-displaced", effect: leaving ? "leave" : "replace-container" },
|
|
539
485
|
reason: `${current.absolutePath} holds local ground sharing never held; removing it would destroy that ground.` };
|
|
540
486
|
}
|
|
541
|
-
const publishing = this.#
|
|
487
|
+
const publishing = this.#ground.pendingWithin(intent.authorityId, current);
|
|
542
488
|
if (publishing.length > 0) {
|
|
543
489
|
return { kind: "dependency", waitFor: { producer: "send", entityIds: publishing },
|
|
544
490
|
reason: `${current.absolutePath} holds local results not yet sequenced; removing it would hide them.` };
|
|
@@ -548,9 +494,6 @@ export class ApplyWindowHost {
|
|
|
548
494
|
return { kind: "local-change", reason: "A required sibling relocation has unproved ground." };
|
|
549
495
|
}
|
|
550
496
|
let safe;
|
|
551
|
-
// The source already shows the target's exact package, every member
|
|
552
|
-
// where its map places it.
|
|
553
|
-
let showsTarget = false;
|
|
554
497
|
if (!current) {
|
|
555
498
|
safe = !tryLstat(context.targetPath) ? { kind: "safe" } : await this.#occupiedDestination(intent, plan, context);
|
|
556
499
|
}
|
|
@@ -575,58 +518,43 @@ export class ApplyWindowHost {
|
|
|
575
518
|
&& (plan.target.type === "workspace" || plan.target.type === "folder") && hasGitMarker(current.absolutePath)) {
|
|
576
519
|
this.#gitStorage.set(key, await captureGitStorage(current.absolutePath));
|
|
577
520
|
}
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
const showing = await this.#repository.showsExpected(intent, plan, current, shared);
|
|
584
|
-
shows = showing !== null;
|
|
585
|
-
showsTarget = showing === "package" && plan.target.type === "repo.git"
|
|
586
|
-
&& shared.payloadVersion === plan.target.payloadVersion && shared.transportVersion === plan.target.transportVersion;
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
shows = await this.#matches(intent, portable(shared?.status === "active" ? shared : current), current.absolutePath, plan);
|
|
590
|
-
}
|
|
591
|
-
safe = shows && this.#ground.physicalDirectoriesMatch(current, directories) ? { kind: "safe" } : { kind: "local-change" };
|
|
521
|
+
// The ground is safe while it shows what this computer last observed
|
|
522
|
+
// there, its O row; anything else is a person's change, which Detect
|
|
523
|
+
// records before Apply looks again.
|
|
524
|
+
safe = await this.#matches(intent, portable(current), current.absolutePath, plan)
|
|
525
|
+
&& this.#ground.physicalDirectoriesMatch(current, directories) ? { kind: "safe" } : { kind: "local-change" };
|
|
592
526
|
}
|
|
593
527
|
if (safe.kind === "safe" && !this.#ground.directoriesStand(directories))
|
|
594
528
|
return replacedParent;
|
|
595
529
|
if (safe.kind === "safe" && finalGuard) {
|
|
596
|
-
const receipt = await this.#receipt(intent, plan, context, "safe"
|
|
530
|
+
const receipt = await this.#receipt(intent, plan, context, "safe");
|
|
597
531
|
if (receipt === null)
|
|
598
532
|
return { kind: "local-change", reason: "The ground this member would reveal over changed after its guard." };
|
|
599
|
-
if (isWait(receipt))
|
|
600
|
-
return receipt;
|
|
601
533
|
this.store.stageReceipt(receipt);
|
|
602
534
|
}
|
|
603
535
|
return safe;
|
|
604
536
|
}
|
|
605
537
|
catch (error) {
|
|
606
|
-
if (error instanceof
|
|
607
|
-
return
|
|
608
|
-
}
|
|
538
|
+
if (error instanceof GitApplyWait)
|
|
539
|
+
return gitWait(intent, error);
|
|
609
540
|
// No kept graph head reaches the Enter's position yet: the line holds.
|
|
610
541
|
if (error instanceof ReceivedStateUnavailableError)
|
|
611
542
|
return { kind: "dependency", reason: error.message };
|
|
612
543
|
throw error;
|
|
613
544
|
}
|
|
614
545
|
finally {
|
|
615
|
-
if (!finalGuard)
|
|
616
|
-
this.#repository.forget(key);
|
|
546
|
+
if (!finalGuard)
|
|
617
547
|
this.#emit(intent, plan, "preflight-finished");
|
|
618
|
-
}
|
|
619
548
|
}
|
|
620
549
|
}
|
|
621
550
|
/**
|
|
622
551
|
* The member's receipt, frozen from the ground its final guard proved:
|
|
623
552
|
* its address, its binding root, the object it reveals over, the object it
|
|
624
|
-
* stages, the sibling moves that free its address,
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
* binds for it. A dependency is a repository obstruction.
|
|
553
|
+
* stages, the sibling moves that free its address, and a former
|
|
554
|
+
* repository's Git storage. Null when a person replaced the source since
|
|
555
|
+
* the guard: nothing binds for it.
|
|
628
556
|
*/
|
|
629
|
-
async #receipt(intent, plan, context, look
|
|
557
|
+
async #receipt(intent, plan, context, look) {
|
|
630
558
|
const key = this.#key(intent);
|
|
631
559
|
const anchor = context.current ?? context.parent;
|
|
632
560
|
if (!anchor)
|
|
@@ -645,11 +573,7 @@ export class ApplyWindowHost {
|
|
|
645
573
|
throw new Error("Apply room move has no physical identity");
|
|
646
574
|
return { uuid: physical.uuid, source: from, destination, physicalKey: physical.physicalKey };
|
|
647
575
|
});
|
|
648
|
-
const relocation = (group) => ({ uuid: group.sourceRoot.uuid,
|
|
649
|
-
source: group.sourceRoot.absolutePath, physicalKey: group.sourceRoot.physicalKey });
|
|
650
576
|
let staged = null;
|
|
651
|
-
let repository = null;
|
|
652
|
-
let relocated = [];
|
|
653
577
|
if (look === "safe") {
|
|
654
578
|
if (kind === "leaf" || kind === "link" || kind === "reference") {
|
|
655
579
|
const path = await this.#stageResult(intent, plan, context, control);
|
|
@@ -660,43 +584,12 @@ export class ApplyWindowHost {
|
|
|
660
584
|
if (!enter)
|
|
661
585
|
throw new Error("container Enter binds without its prepared tree");
|
|
662
586
|
staged = objectOf(enter.tree, lstatSync(enter.tree, { bigint: true }));
|
|
663
|
-
relocated = this.#repository.enterRelocations(context.targetPath, enter).map(relocation);
|
|
664
|
-
}
|
|
665
|
-
else if (kind === "repository") {
|
|
666
|
-
const chain = prepared?.repository;
|
|
667
|
-
if (!chain)
|
|
668
|
-
throw new Error("repository Apply has no prepared transport chain");
|
|
669
|
-
const basis = await this.#repository.revealBasis(context);
|
|
670
|
-
const kept = basis?.unstated ?? [];
|
|
671
|
-
let removals = { leaves: [], directories: [] }, standing = [];
|
|
672
|
-
if (context.current && sourceStats) {
|
|
673
|
-
standing = this.#repository.elsewhere(context.current, chain.identity);
|
|
674
|
-
try {
|
|
675
|
-
removals = planWorkingReveal(context.current.absolutePath, repositoryApplyTerritory(chain.identity, standing), basis?.held ?? [], new Set(kept.map(entry => entry.path)));
|
|
676
|
-
}
|
|
677
|
-
catch (error) {
|
|
678
|
-
if (!(error instanceof RepositoryGroundObstructed))
|
|
679
|
-
throw error;
|
|
680
|
-
return this.#repository.obstructed(context.current, error);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
const sourcePath = source?.path ?? null;
|
|
684
|
-
const storage = sourcePath === null || !hasGitMarker(sourcePath) ? null : revealStorageOf(sourcePath);
|
|
685
|
-
// Only a self-contained checkout moves whole: its own `.git`
|
|
686
|
-
// directory, nothing to remove around the package it shows, and no
|
|
687
|
-
// configured worktree, which would leave Git reading the old place.
|
|
688
|
-
const shown = showsTarget && sourcePath !== null && tryLstat(join(sourcePath, ".git"))?.isDirectory() === true
|
|
689
|
-
&& removals.leaves.length === 0 && removals.directories.length === 0
|
|
690
|
-
&& !(await new GitCapture(sourcePath).configuration()).has("core.worktree");
|
|
691
|
-
repository = { removals, standing, remainder: kept, storage: storage === null ? null : revealStoragePhysical(storage), shown };
|
|
692
|
-
relocated = this.#repository.relocations(context, repositoryApplyTerritory(chain.identity, standing).identity).map(relocation);
|
|
693
587
|
}
|
|
694
588
|
}
|
|
695
589
|
return {
|
|
696
590
|
intent, target: plan.target, kind, look, address: context.targetPath,
|
|
697
591
|
root: { path: root.absolutePath, physicalKey: root.physicalKey }, control,
|
|
698
|
-
source, staged, room,
|
|
699
|
-
gitStorage: this.#gitStorage.get(key) ?? null,
|
|
592
|
+
source, staged, room, gitStorage: this.#gitStorage.get(key) ?? null,
|
|
700
593
|
};
|
|
701
594
|
}
|
|
702
595
|
/** A file or link result staged at its vacant private address, with its
|
|
@@ -769,12 +662,6 @@ export class ApplyWindowHost {
|
|
|
769
662
|
* cones discovered after acquisition without proving them again. */
|
|
770
663
|
async #hold(intent, plans) {
|
|
771
664
|
const members = intent.members.map((member, index) => ({ intent: member, plan: plans[index] }));
|
|
772
|
-
// Immutable identity determines a repository's relocation cones. Load it
|
|
773
|
-
// before acquiring ground, including after restart with an empty cache.
|
|
774
|
-
for (const { intent: member, plan } of members) {
|
|
775
|
-
if (plan.target.type === "repo.git" && plan.kind !== "leave" && !entersContainer(plan))
|
|
776
|
-
await this.#ensurePrepared(member, plan);
|
|
777
|
-
}
|
|
778
665
|
const cones = () => [...new Set(members.flatMap(({ intent: member, plan }) => this.#groundCones(member, plan)))];
|
|
779
666
|
const reflogs = members.some(({ plan }) => plan.target.type === "repo.git" && !entersContainer(plan))
|
|
780
667
|
? () => members.flatMap(({ intent: member, plan }) => plan.target.type === "repo.git" && !entersContainer(plan)
|
|
@@ -812,9 +699,7 @@ export class ApplyWindowHost {
|
|
|
812
699
|
/**
|
|
813
700
|
* The visible addresses one member may read or replace: its target
|
|
814
701
|
* address, the entity's current address when it moves, its room chain's
|
|
815
|
-
* sources and destinations
|
|
816
|
-
* materialized address its identity map relocates. A bound member's are
|
|
817
|
-
* its receipt's. A member current rows no longer place holds only its O
|
|
702
|
+
* sources and destinations. A bound member's are its receipt's. A member current rows no longer place holds only its O
|
|
818
703
|
* address, and its guard then finds its play changed.
|
|
819
704
|
*/
|
|
820
705
|
applyAddresses(intent, plan) {
|
|
@@ -837,12 +722,6 @@ export class ApplyWindowHost {
|
|
|
837
722
|
addresses.add(source);
|
|
838
723
|
addresses.add(destination);
|
|
839
724
|
}
|
|
840
|
-
const prepared = this.#prepared.get(this.#key(intent));
|
|
841
|
-
const groups = prepared?.enter ? this.#repository.enterRelocations(context.targetPath, prepared.enter)
|
|
842
|
-
: plan.target.type === "repo.git" && prepared?.repository
|
|
843
|
-
? this.#repository.relocations(context, this.#repository.territory(intent, prepared.repository.identity, context.current).identity) : [];
|
|
844
|
-
for (const group of groups)
|
|
845
|
-
addresses.add(group.sourceRoot.absolutePath);
|
|
846
725
|
return [...addresses];
|
|
847
726
|
}
|
|
848
727
|
/** Called only after the requesting Watch cutoff settles. Outbox protection
|
|
@@ -872,9 +751,6 @@ export class ApplyWindowHost {
|
|
|
872
751
|
const root = judgeBoundRoot(receipt.root);
|
|
873
752
|
if (root !== "present")
|
|
874
753
|
return declined(`Materialized root ${receipt.root.path} is ${root}.`);
|
|
875
|
-
const key = this.#key(intent);
|
|
876
|
-
// The guard's readings describe ground this reveal is about to change.
|
|
877
|
-
this.#repository.forget(key);
|
|
878
754
|
const { address, control, source } = receipt;
|
|
879
755
|
await this.#makeRoom(receipt);
|
|
880
756
|
const remainder = this.#remainder(intent, receipt);
|
|
@@ -894,7 +770,7 @@ export class ApplyWindowHost {
|
|
|
894
770
|
if (!moveWithoutReplacing(source.path, address))
|
|
895
771
|
return declined(`${address} holds another object.`);
|
|
896
772
|
}
|
|
897
|
-
if (receipt.kind === "container") {
|
|
773
|
+
if (receipt.kind === "container" || receipt.kind === "repository") {
|
|
898
774
|
const at = standing(address);
|
|
899
775
|
if (at && (!at.isDirectory() || at.isSymbolicLink())) {
|
|
900
776
|
if (!replaceAt(receipt, stageDirectory(control, intent.entityId)))
|
|
@@ -911,30 +787,8 @@ export class ApplyWindowHost {
|
|
|
911
787
|
displaceGitStorage(displaced, address, receipt.gitStorage);
|
|
912
788
|
}
|
|
913
789
|
await this.#return(receipt.root.path, [{ uuid: intent.entityId, path: address }]);
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
if (receipt.kind === "repository") {
|
|
917
|
-
if (!receipt.repository)
|
|
918
|
-
throw new Error("repository Apply binds without its reveal plan");
|
|
919
|
-
// Optimistic equality: the source already showed this exact package,
|
|
920
|
-
// so the move above was the whole reveal. Verify reads it afresh.
|
|
921
|
-
if (receipt.repository.shown) {
|
|
922
|
-
relocateGroups(receipt);
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
const chain = (await this.#ensurePrepared(intent, plan)).repository;
|
|
926
|
-
if (!chain)
|
|
927
|
-
throw new Error("repository Apply has no prepared transport chain");
|
|
928
|
-
ensureDirBeneath(receipt.root.path, address, 0o755);
|
|
929
|
-
const staging = stagedPath(control, intent.entityId);
|
|
930
|
-
ensureApplyPrivate(control, dirname(staging));
|
|
931
|
-
const applied = await applyRepositoryFiles(address, chain, { kind: "working", root: receipt.root.path,
|
|
932
|
-
removals: receipt.repository.removals, staging, standing: receipt.repository.standing,
|
|
933
|
-
reveal: { attempt: intent.attemptId, storage: receipt.repository.storage },
|
|
934
|
-
proven: this.#repository.proofs(address) });
|
|
935
|
-
// The reveal's readback is the reading Verify inherits.
|
|
936
|
-
this.#repository.remember(key, address, applied.reading);
|
|
937
|
-
relocateGroups(receipt);
|
|
790
|
+
if (receipt.kind === "repository")
|
|
791
|
+
return await this.#revealGit(intent, plan, receipt);
|
|
938
792
|
return;
|
|
939
793
|
}
|
|
940
794
|
if (receipt.kind === "enter") {
|
|
@@ -947,7 +801,6 @@ export class ApplyWindowHost {
|
|
|
947
801
|
if (!replaceAt(receipt, staged.path))
|
|
948
802
|
return declined(`${address} holds another object.`);
|
|
949
803
|
}
|
|
950
|
-
relocateGroups(receipt);
|
|
951
804
|
const { seal } = (await this.#ensurePrepared(intent, plan)).enter;
|
|
952
805
|
await this.#return(receipt.root.path, seal.rows.filter(row => CONTAINERS.has(row.record.type))
|
|
953
806
|
.map(row => ({ uuid: row.record.uuid, path: join(address, ...row.relativePath.split("/").filter(Boolean)) })));
|
|
@@ -973,6 +826,46 @@ export class ApplyWindowHost {
|
|
|
973
826
|
this.#emit(intent, plan, "reveal-finished");
|
|
974
827
|
}
|
|
975
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* A repository's Git part: its folder stands, and Git's own files are
|
|
831
|
+
* made to hold the target's state (src/git/rail.ts). The part marker says
|
|
832
|
+
* `started`, durably, before Git writes anything, so recovery knows a torn
|
|
833
|
+
* install is Apply's own; `ended` follows Git's read of the result. A
|
|
834
|
+
* folder that already shows the state, as a move or rename leaves it, is
|
|
835
|
+
* read and left alone. Its working-tree files are their own members.
|
|
836
|
+
*/
|
|
837
|
+
async #revealGit(intent, plan, receipt) {
|
|
838
|
+
const target = plan.target.transportVersion, artifact = resultArtifact(plan);
|
|
839
|
+
if (!target || !artifact)
|
|
840
|
+
throw new Error(`repository ${intent.entityId} Apply names no Git artifact`);
|
|
841
|
+
const marker = gitPartPath(receipt.control, intent.entityId);
|
|
842
|
+
const before = this.#ground.current(intent.entityId);
|
|
843
|
+
const known = async () => before?.type === "repo.git" ? cachedNotebook(this.#cacheDir, before.transportVersion) : null;
|
|
844
|
+
try {
|
|
845
|
+
if (readGitPart(receipt.control, intent.entityId) === null) {
|
|
846
|
+
if (hasGitMarker(receipt.address)) {
|
|
847
|
+
const shown = await gitStateIdOf(receipt.address, this.#gitOwners, async () => (await known())?.state ?? null);
|
|
848
|
+
if ("stateId" in shown && shown.stateId === plan.target.payloadVersion)
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
ensureApplyPrivate(receipt.control, dirname(marker));
|
|
852
|
+
writeFileSync(marker, "started");
|
|
853
|
+
await flushEach([marker], [dirname(marker)]);
|
|
854
|
+
}
|
|
855
|
+
// The target and its parents, from the cache when its bytes prove
|
|
856
|
+
// their name, else the wire.
|
|
857
|
+
const source = async (version) => readFile((await this.#cargo.sealed(version)
|
|
858
|
+
?? await this.#cargo.readOne({ ...artifact, contentHash: version })).file);
|
|
859
|
+
await applyGit(receipt.address, target, source, await known(), this.#gitOwners);
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
if (error instanceof GitApplyWait)
|
|
863
|
+
return gitWait(intent, error);
|
|
864
|
+
throw error;
|
|
865
|
+
}
|
|
866
|
+
// Unflushed: a lost `ended` only runs the same install again.
|
|
867
|
+
writeFileSync(marker, "ended");
|
|
868
|
+
}
|
|
976
869
|
/** The topmost local remainder beneath a container this Leave or leaf
|
|
977
870
|
* displaces, before the reveal or after it; null when that ground is no
|
|
978
871
|
* longer settled. */
|
|
@@ -1050,15 +943,14 @@ export class ApplyWindowHost {
|
|
|
1050
943
|
&& !await keptStorageIsO(displacedGitPath(receipt.control, intent.entityId), receipt.address, receipt.gitStorage)) {
|
|
1051
944
|
return { kind: "local-change" };
|
|
1052
945
|
}
|
|
1053
|
-
const judged = new ShownGround(this.#database).judge(plan.target);
|
|
946
|
+
const judged = new ShownGround(this.#database, this.#onDemand).judge(plan.target);
|
|
1054
947
|
if (judged !== plan.play) {
|
|
1055
948
|
return { kind: "rejudge", reason: `The accepted result now plays ${judged} on this computer, not ${plan.play}.` };
|
|
1056
949
|
}
|
|
1057
950
|
const enter = receipt.kind === "enter" ? (await this.#ensurePrepared(intent, plan)).enter : undefined;
|
|
1058
|
-
const identity = receipt.kind === "repository" ? (await this.#ensurePrepared(intent, plan)).repository?.identity : undefined;
|
|
1059
951
|
const [members, containers] = enter
|
|
1060
952
|
? [enter.seal.rows.map(row => row.record.uuid), enter.seal.rows.filter(row => CONTAINERS.has(row.record.type)).map(row => row.record.uuid)]
|
|
1061
|
-
:
|
|
953
|
+
: [[], []];
|
|
1062
954
|
const moved = receipt.room.map(move => move.uuid);
|
|
1063
955
|
const read = this.store.verificationRead(intent.attemptId, reader => {
|
|
1064
956
|
readVerificationFacts(reader, plan.target, members, containers, moved);
|
|
@@ -1070,7 +962,6 @@ export class ApplyWindowHost {
|
|
|
1070
962
|
const context = this.#boundContext(receipt);
|
|
1071
963
|
// Every read Verify proves follows its root's content clock.
|
|
1072
964
|
const clock = await this.#clock(intent.attemptId, receipt.root.path);
|
|
1073
|
-
await this.#repository.closeInherited(intent);
|
|
1074
965
|
let proof;
|
|
1075
966
|
let ground;
|
|
1076
967
|
if (receipt.kind === "leave") {
|
|
@@ -1087,8 +978,7 @@ export class ApplyWindowHost {
|
|
|
1087
978
|
const matches = await this.#matches(intent, plan.target, receipt.address, plan, receipt.address, found => { proof = found; });
|
|
1088
979
|
if (!matches)
|
|
1089
980
|
return { kind: "local-change" };
|
|
1090
|
-
ground =
|
|
1091
|
-
: containerGround(this.#ground, plan.target, context, verifiedRow(this.#ground, plan.target, context, proof, clock));
|
|
981
|
+
ground = containerGround(this.#ground, plan.target, context, verifiedRow(this.#ground, plan.target, context, proof, clock));
|
|
1092
982
|
}
|
|
1093
983
|
const verification = proof.proof;
|
|
1094
984
|
const closed = { semantic: () => verification.semantic(), witnesses: [],
|
|
@@ -1098,6 +988,11 @@ export class ApplyWindowHost {
|
|
|
1098
988
|
shared: [...ground.shared, ...room.shared] }, closed);
|
|
1099
989
|
return { kind: "match" };
|
|
1100
990
|
}
|
|
991
|
+
catch (error) {
|
|
992
|
+
if (error instanceof GitApplyWait)
|
|
993
|
+
return gitWait(intent, error);
|
|
994
|
+
throw error;
|
|
995
|
+
}
|
|
1101
996
|
finally {
|
|
1102
997
|
this.#emit(intent, plan, "verify-finished");
|
|
1103
998
|
}
|
|
@@ -1214,10 +1109,6 @@ export class ApplyWindowHost {
|
|
|
1214
1109
|
}
|
|
1215
1110
|
}
|
|
1216
1111
|
const verification = await adapter.verify.verify(member, plan);
|
|
1217
|
-
// An ended Git part lets go of the ground its parcel recreated only
|
|
1218
|
-
// once its result is proven; that ground lies outside the repository.
|
|
1219
|
-
if (verification.kind === "match" && verdict === "revealed")
|
|
1220
|
-
relocateGroups(receipt);
|
|
1221
1112
|
if (verification.kind === "match")
|
|
1222
1113
|
outcomes.set(entityId, { kind: "materialized" });
|
|
1223
1114
|
else
|
|
@@ -1232,17 +1123,20 @@ export class ApplyWindowHost {
|
|
|
1232
1123
|
return intent.members.map(member => outcomes.get(member.entityId) ?? { kind: "owed", reason: "not reached" });
|
|
1233
1124
|
}
|
|
1234
1125
|
/** Whether the ground at `at` shows what the member's final guard proved
|
|
1235
|
-
* of its source (#guard), read the same way: the source's O row,
|
|
1236
|
-
*
|
|
1126
|
+
* of its source (#guard), read the same way: the source's O row, which
|
|
1127
|
+
* stands until the window ends. A repository Git refuses shows nothing. */
|
|
1237
1128
|
async #showsGuarded(intent, plan, at) {
|
|
1238
1129
|
const current = this.#ground.current(intent.entityId);
|
|
1239
1130
|
if (!current)
|
|
1240
1131
|
return false;
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1132
|
+
try {
|
|
1133
|
+
return await this.#matches(intent, portable(current), at, plan);
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
if (error instanceof GitApplyWait)
|
|
1137
|
+
return false;
|
|
1138
|
+
throw error;
|
|
1244
1139
|
}
|
|
1245
|
-
return this.#matches(intent, portable(shared?.status === "active" ? shared : current), at, plan);
|
|
1246
1140
|
}
|
|
1247
1141
|
/** A window that never bound leaves nothing anyone owns: its preparation
|
|
1248
1142
|
* and its control trees go. A bound window keeps both for #recover. */
|
|
@@ -1265,6 +1159,41 @@ export class ApplyWindowHost {
|
|
|
1265
1159
|
await rm(control, { recursive: true, force: true });
|
|
1266
1160
|
}
|
|
1267
1161
|
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Place one unit its root on demand lists (src/drive/): its line plays it
|
|
1164
|
+
* as one ordinary Enter of that unit, through intent, guard, reveal and
|
|
1165
|
+
* Verify, and the answer comes when the window holding it ends. `wake`
|
|
1166
|
+
* rings the line once the unit is owed. One placement per unit is in
|
|
1167
|
+
* flight: a second ask joins the first.
|
|
1168
|
+
*/
|
|
1169
|
+
place(entityId, wake) {
|
|
1170
|
+
return new Promise(answer => {
|
|
1171
|
+
const joined = this.#opening.get(entityId);
|
|
1172
|
+
this.#opening.set(entityId, joined
|
|
1173
|
+
? { answer: placement => { joined.answer(placement); answer(placement); }, wake: joined.wake }
|
|
1174
|
+
: { answer, wake });
|
|
1175
|
+
if (!joined)
|
|
1176
|
+
this.#open(entityId);
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
/** Owe an opened unit to its line and ring it; answer at once when O
|
|
1180
|
+
* already shows the unit or this computer never received it. */
|
|
1181
|
+
#open(entityId) {
|
|
1182
|
+
void this.store.openUnit(entityId).then(opened => {
|
|
1183
|
+
if (opened === "owed")
|
|
1184
|
+
return this.#opening.get(entityId)?.wake();
|
|
1185
|
+
this.#answer(entityId, opened === "shown" ? { kind: "placed" } : { kind: "unknown" });
|
|
1186
|
+
}, (error) => this.#answer(entityId, { kind: "failed", error }));
|
|
1187
|
+
}
|
|
1188
|
+
/** Stop placing a unit: its line lists it again unless its window bound. */
|
|
1189
|
+
abandon(entityId) {
|
|
1190
|
+
this.#opening.delete(entityId);
|
|
1191
|
+
}
|
|
1192
|
+
#answer(entityId, placement) {
|
|
1193
|
+
const opening = this.#opening.get(entityId);
|
|
1194
|
+
this.#opening.delete(entityId);
|
|
1195
|
+
opening?.answer(placement);
|
|
1196
|
+
}
|
|
1268
1197
|
/** The end commit landed: the window's ground is no longer owned, and
|
|
1269
1198
|
* every byte it revealed is owed to the durability point. */
|
|
1270
1199
|
#ended(intent, members) {
|
|
@@ -1285,9 +1214,15 @@ export class ApplyWindowHost {
|
|
|
1285
1214
|
}
|
|
1286
1215
|
else if (member.outcome.kind === "settled") {
|
|
1287
1216
|
this.#onStage?.({ ...common, stage: "settled", settlement: member.outcome.settlement });
|
|
1217
|
+
// A window judged before the unit opened listed it: owe it again.
|
|
1218
|
+
if (member.outcome.settlement === "listed" && this.#opening.has(member.entityId))
|
|
1219
|
+
this.#open(member.entityId);
|
|
1220
|
+
else
|
|
1221
|
+
this.#answer(member.entityId, { kind: "settled", settlement: member.outcome.settlement });
|
|
1288
1222
|
}
|
|
1289
1223
|
else {
|
|
1290
1224
|
this.#onStage?.({ ...common, stage: "retired", completion: "materialized" });
|
|
1225
|
+
this.#answer(member.entityId, { kind: "placed" });
|
|
1291
1226
|
}
|
|
1292
1227
|
if (receipt)
|
|
1293
1228
|
this.#forgetPreparation(receipt.intent);
|
|
@@ -1316,8 +1251,6 @@ export class ApplyWindowHost {
|
|
|
1316
1251
|
directories.add(dirname(move.source));
|
|
1317
1252
|
directories.add(dirname(move.destination));
|
|
1318
1253
|
}
|
|
1319
|
-
for (const entry of receipt.relocated)
|
|
1320
|
-
directories.add(dirname(entry.source));
|
|
1321
1254
|
switch (receipt.kind) {
|
|
1322
1255
|
case "leaf":
|
|
1323
1256
|
files.add(receipt.address);
|
|
@@ -1373,35 +1306,36 @@ export class ApplyWindowHost {
|
|
|
1373
1306
|
};
|
|
1374
1307
|
if (!stats)
|
|
1375
1308
|
return false;
|
|
1376
|
-
if (
|
|
1377
|
-
const expected = record.payloadVersion
|
|
1378
|
-
if (!expected
|
|
1379
|
-
throw new Error(`Apply matched ${record.uuid} with no
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
// its bytes are not read again, and they answer for every payload
|
|
1383
|
-
// their codec names. An object Apply just placed carries the change
|
|
1384
|
-
// time of its rename, past every earlier stamp, so it is always read
|
|
1385
|
-
// once, and that read becomes its row's proof.
|
|
1386
|
-
const proven = this.#ground.atPath(path);
|
|
1387
|
-
if (proven?.payloadVersion && sameCodec(proven.payloadVersion, expected) && sourceReusable(proven, stats)) {
|
|
1388
|
-
if (proven.type !== record.type || proven.payloadVersion !== expected)
|
|
1389
|
-
return false;
|
|
1309
|
+
if (record.type === "file.text" || record.type === "file.binary" || record.type === "link") {
|
|
1310
|
+
const expected = record.payloadVersion;
|
|
1311
|
+
if (!expected)
|
|
1312
|
+
throw new Error(`Apply matched ${record.uuid} with no payload`);
|
|
1313
|
+
const modeShown = record.type === "link" || record.fileMode === portableFileMode(record.type, Number(stats.mode));
|
|
1314
|
+
const shown = async () => {
|
|
1390
1315
|
const witnesses = new PhysicalPathWitnesses();
|
|
1391
1316
|
witnesses.remember(dirname(path), optionalLstat(dirname(path)));
|
|
1392
1317
|
witnesses.remember(path, stats);
|
|
1393
|
-
return
|
|
1394
|
-
|
|
1318
|
+
return modeShown && retain(stats, witnessProof([witnesses.seal()]));
|
|
1319
|
+
};
|
|
1320
|
+
// A leaf this computer proved keeps its proof while the slot shows its
|
|
1321
|
+
// exact signature, by the rule Detect reuses it (source-signature.ts):
|
|
1322
|
+
// its bytes are not read again. An object Apply just placed carries
|
|
1323
|
+
// the change time of its rename, past every earlier stamp, so it is
|
|
1324
|
+
// always read once, and that read becomes its row's proof.
|
|
1325
|
+
const proven = this.#ground.atPath(path);
|
|
1326
|
+
if (proven?.payloadVersion && sourceReusable(proven, stats)) {
|
|
1327
|
+
return proven.type === record.type && proven.payloadVersion === expected && shown();
|
|
1395
1328
|
}
|
|
1396
1329
|
const key = this.#key(intent);
|
|
1397
1330
|
this.#contentReads.set(key, (this.#contentReads.get(key) ?? 0) + 1);
|
|
1398
|
-
|
|
1399
|
-
if (
|
|
1331
|
+
// Read the way Detect reads it (src/detection/runtime.ts).
|
|
1332
|
+
if (record.type === "link") {
|
|
1333
|
+
return stats.isSymbolicLink() && sha256Hex(Buffer.from(readLinkTarget(path), "utf8")) === expected && shown();
|
|
1334
|
+
}
|
|
1335
|
+
if (!stats.isFile())
|
|
1400
1336
|
return false;
|
|
1401
|
-
const
|
|
1402
|
-
return
|
|
1403
|
-
|| record.fileMode === portableFileMode(record.type, Number(leaf.stats.mode)))
|
|
1404
|
-
&& await retain(leaf.stats, witnessProof([witness]));
|
|
1337
|
+
const content = await captureContent(path, stats, null, { lane: "named" });
|
|
1338
|
+
return classifyFile({ binary: content.binary }) === record.type && content.contentHash === expected && shown();
|
|
1405
1339
|
}
|
|
1406
1340
|
if (record.type === "reference") {
|
|
1407
1341
|
if (!record.payloadVersion)
|
|
@@ -1415,16 +1349,14 @@ export class ApplyWindowHost {
|
|
|
1415
1349
|
}
|
|
1416
1350
|
const addressProof = witnessProof([addressWitness(path, stats)]);
|
|
1417
1351
|
if (record.type === "repo.git") {
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
const own = record.uuid === intent.entityId;
|
|
1422
|
-
const territory = own ? this.#repository.territory(intent, repository.identity) : repositoryApplyTerritory(repository.identity, []);
|
|
1423
|
-
const remainder = own ? this.#repository.allowance(intent, repository.identity) : [];
|
|
1424
|
-
if (!remainder)
|
|
1352
|
+
// A repository is its folder plus its Git directory's state, read
|
|
1353
|
+
// without a Git process; its working-tree files are their own entities.
|
|
1354
|
+
if (!stats.isDirectory() || stats.isSymbolicLink() || !hasGitMarker(path))
|
|
1425
1355
|
return false;
|
|
1426
|
-
const
|
|
1427
|
-
|
|
1356
|
+
const read = await gitStateIdOf(path, this.#gitOwners, async () => (await cachedNotebook(this.#cacheDir, record.transportVersion))?.state ?? null);
|
|
1357
|
+
if ("unsupported" in read)
|
|
1358
|
+
throw new GitApplyWait(`${path} holds ${read.unsupported}; Apply waits for it to change`);
|
|
1359
|
+
return read.stateId === record.payloadVersion && retain(stats, addressProof);
|
|
1428
1360
|
}
|
|
1429
1361
|
if (!stats.isDirectory() || stats.isSymbolicLink())
|
|
1430
1362
|
return false;
|