run402 4.95.0 → 4.96.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/README.md +3 -3
- package/cli.mjs +1 -21
- package/core-dist/keystore.js +1 -1
- package/git-remote-run402.mjs +6 -6
- package/lib/cold-start.mjs +2 -2
- package/lib/command-manifest.mjs +3 -41
- package/lib/credentials.mjs +1 -1
- package/lib/daemon-path.mjs +3 -3
- package/lib/deploy-v2.mjs +17 -17
- package/lib/doctor.mjs +45 -54
- package/lib/init.mjs +29 -29
- package/lib/next-actions.mjs +1 -1
- package/lib/org-context.mjs +9 -9
- package/lib/orgs.mjs +19 -19
- package/lib/path-lookup.mjs +7 -10
- package/lib/path-lookup.test.mjs +19 -21
- package/lib/remote-helper-session.mjs +93 -93
- package/lib/repos.mjs +174 -175
- package/lib/rooms-context.mjs +7 -7
- package/lib/up.mjs +14 -14
- package/lib/{gitvault-capabilities.mjs → vault-capabilities.mjs} +10 -14
- package/lib/{gitvault-daemon-run.mjs → vault-daemon-run.mjs} +2 -2
- package/lib/{gitvault-daemon.mjs → vault-daemon.mjs} +23 -23
- package/lib/{gitvault-scaffold.mjs → vault-scaffold.mjs} +12 -12
- package/lib/{gitvault-target.mjs → vault-target.mjs} +22 -17
- package/package.json +2 -2
- package/sdk/core-dist/keystore.js +1 -1
- package/sdk/dist/errors.d.ts +4 -4
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/index.d.ts +9 -9
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +8 -8
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts +5 -5
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +20 -20
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +17 -17
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.d.ts +2 -2
- package/sdk/dist/namespaces/org.js +2 -2
- package/sdk/dist/namespaces/org.types.d.ts +3 -3
- package/sdk/dist/namespaces/pay.js +1 -1
- package/sdk/dist/namespaces/{gitvault.d.ts → repos.d.ts} +436 -449
- package/sdk/dist/namespaces/repos.d.ts.map +1 -0
- package/sdk/dist/namespaces/{gitvault.js → repos.js} +451 -459
- package/sdk/dist/namespaces/repos.js.map +1 -0
- package/sdk/dist/namespaces/rooms.js +2 -2
- package/sdk/dist/namespaces/rooms.js.map +1 -1
- package/sdk/dist/namespaces/session.d.ts +2 -2
- package/sdk/dist/namespaces/session.d.ts.map +1 -1
- package/sdk/dist/namespaces/session.js +2 -2
- package/sdk/dist/namespaces/session.js.map +1 -1
- package/sdk/dist/namespaces/tier.d.ts +3 -3
- package/sdk/dist/namespaces/tier.d.ts.map +1 -1
- package/sdk/dist/namespaces/{gitvault.crypto.d.ts → vault.crypto.d.ts} +141 -141
- package/sdk/dist/namespaces/vault.crypto.d.ts.map +1 -0
- package/sdk/dist/namespaces/{gitvault.crypto.js → vault.crypto.js} +173 -173
- package/sdk/dist/namespaces/vault.crypto.js.map +1 -0
- package/sdk/dist/namespaces/{gitvault.types.d.ts → vault.types.d.ts} +136 -136
- package/sdk/dist/namespaces/vault.types.d.ts.map +1 -0
- package/sdk/dist/namespaces/{gitvault.types.js → vault.types.js} +4 -4
- package/sdk/dist/namespaces/vault.types.js.map +1 -0
- package/sdk/dist/node/bearer-redeem-key.d.ts +1 -1
- package/sdk/dist/node/bearer-redeem-key.js +5 -5
- package/sdk/dist/node/bearer-redeem-key.js.map +1 -1
- package/sdk/dist/node/http-dispatcher.js +5 -5
- package/sdk/dist/node/http-dispatcher.js.map +1 -1
- package/sdk/dist/node/index.d.ts +29 -29
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +39 -39
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/{gitvault-address.d.ts → vault-address.d.ts} +42 -42
- package/sdk/dist/node/vault-address.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-address.js → vault-address.js} +43 -43
- package/sdk/dist/node/vault-address.js.map +1 -0
- package/sdk/dist/node/{gitvault-apply.d.ts → vault-apply.d.ts} +27 -27
- package/sdk/dist/node/vault-apply.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-apply.js → vault-apply.js} +38 -38
- package/sdk/dist/node/vault-apply.js.map +1 -0
- package/sdk/dist/node/vault-byo-config.d.ts +29 -0
- package/sdk/dist/node/vault-byo-config.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-byo-config.js → vault-byo-config.js} +18 -18
- package/sdk/dist/node/vault-byo-config.js.map +1 -0
- package/sdk/dist/node/vault-byo-probe.d.ts +20 -0
- package/sdk/dist/node/vault-byo-probe.d.ts.map +1 -0
- package/sdk/dist/node/vault-byo-probe.js +57 -0
- package/sdk/dist/node/vault-byo-probe.js.map +1 -0
- package/sdk/dist/node/{gitvault-creation-journal.d.ts → vault-creation-journal.d.ts} +69 -69
- package/sdk/dist/node/vault-creation-journal.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-creation-journal.js → vault-creation-journal.js} +54 -54
- package/sdk/dist/node/vault-creation-journal.js.map +1 -0
- package/sdk/dist/node/{gitvault-degraded-read.d.ts → vault-degraded-read.d.ts} +34 -34
- package/sdk/dist/node/vault-degraded-read.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-degraded-read.js → vault-degraded-read.js} +24 -24
- package/sdk/dist/node/vault-degraded-read.js.map +1 -0
- package/sdk/dist/node/{gitvault-deploy.d.ts → vault-deploy.d.ts} +67 -67
- package/sdk/dist/node/vault-deploy.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-deploy.js → vault-deploy.js} +27 -27
- package/sdk/dist/node/vault-deploy.js.map +1 -0
- package/sdk/dist/node/{gitvault-edge-fetch.d.ts → vault-edge-fetch.d.ts} +9 -9
- package/sdk/dist/node/vault-edge-fetch.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-edge-fetch.js → vault-edge-fetch.js} +11 -11
- package/sdk/dist/node/vault-edge-fetch.js.map +1 -0
- package/sdk/dist/node/{gitvault-handoff.d.ts → vault-handoff.d.ts} +9 -9
- package/sdk/dist/node/vault-handoff.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-handoff.js → vault-handoff.js} +24 -24
- package/sdk/dist/node/vault-handoff.js.map +1 -0
- package/sdk/dist/node/{gitvault-keystore.d.ts → vault-keystore.d.ts} +87 -77
- package/sdk/dist/node/vault-keystore.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-keystore.js → vault-keystore.js} +105 -68
- package/sdk/dist/node/vault-keystore.js.map +1 -0
- package/sdk/dist/node/{gitvault-member-bundle.d.ts → vault-member-bundle.d.ts} +17 -17
- package/sdk/dist/node/vault-member-bundle.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-member-bundle.js → vault-member-bundle.js} +11 -11
- package/sdk/dist/node/vault-member-bundle.js.map +1 -0
- package/sdk/dist/node/{gitvault-mirror-backend.d.ts → vault-mirror-backend.d.ts} +26 -26
- package/sdk/dist/node/vault-mirror-backend.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-mirror-backend.js → vault-mirror-backend.js} +25 -25
- package/sdk/dist/node/vault-mirror-backend.js.map +1 -0
- package/sdk/dist/node/{gitvault-mirror-config.d.ts → vault-mirror-config.d.ts} +23 -23
- package/sdk/dist/node/vault-mirror-config.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-mirror-config.js → vault-mirror-config.js} +16 -16
- package/sdk/dist/node/vault-mirror-config.js.map +1 -0
- package/sdk/dist/node/{gitvault-mirror.d.ts → vault-mirror.d.ts} +36 -36
- package/sdk/dist/node/vault-mirror.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-mirror.js → vault-mirror.js} +75 -75
- package/sdk/dist/node/vault-mirror.js.map +1 -0
- package/sdk/dist/node/{gitvault-native-crypto.d.ts → vault-native-crypto.d.ts} +10 -10
- package/sdk/dist/node/vault-native-crypto.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-native-crypto.js → vault-native-crypto.js} +16 -16
- package/sdk/dist/node/vault-native-crypto.js.map +1 -0
- package/sdk/dist/node/{gitvault-open-or-create.d.ts → vault-open-or-create.d.ts} +16 -16
- package/sdk/dist/node/vault-open-or-create.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-open-or-create.js → vault-open-or-create.js} +10 -10
- package/sdk/dist/node/vault-open-or-create.js.map +1 -0
- package/sdk/dist/node/{gitvault-prewarm.d.ts → vault-prewarm.d.ts} +13 -13
- package/sdk/dist/node/vault-prewarm.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-prewarm.js → vault-prewarm.js} +25 -25
- package/sdk/dist/node/vault-prewarm.js.map +1 -0
- package/sdk/dist/node/{gitvault-profile-scan.d.ts → vault-profile-scan.d.ts} +3 -3
- package/sdk/dist/node/vault-profile-scan.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-profile-scan.js → vault-profile-scan.js} +12 -12
- package/sdk/dist/node/vault-profile-scan.js.map +1 -0
- package/sdk/dist/node/{gitvault-prune.d.ts → vault-prune.d.ts} +61 -61
- package/sdk/dist/node/vault-prune.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-prune.js → vault-prune.js} +34 -34
- package/sdk/dist/node/vault-prune.js.map +1 -0
- package/sdk/dist/node/{gitvault-publication.d.ts → vault-publication.d.ts} +399 -399
- package/sdk/dist/node/vault-publication.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-publication.js → vault-publication.js} +584 -584
- package/sdk/dist/node/vault-publication.js.map +1 -0
- package/sdk/dist/node/{gitvault-push-to-create.d.ts → vault-push-to-create.d.ts} +16 -16
- package/sdk/dist/node/vault-push-to-create.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-push-to-create.js → vault-push-to-create.js} +9 -9
- package/sdk/dist/node/vault-push-to-create.js.map +1 -0
- package/sdk/dist/node/{gitvault-recover.d.ts → vault-recover.d.ts} +50 -50
- package/sdk/dist/node/vault-recover.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-recover.js → vault-recover.js} +84 -84
- package/sdk/dist/node/vault-recover.js.map +1 -0
- package/sdk/dist/node/{gitvault-restore.d.ts → vault-restore.d.ts} +8 -8
- package/sdk/dist/node/vault-restore.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-restore.js → vault-restore.js} +11 -11
- package/sdk/dist/node/vault-restore.js.map +1 -0
- package/sdk/dist/node/{gitvault-snapshot.d.ts → vault-snapshot.d.ts} +48 -48
- package/sdk/dist/node/vault-snapshot.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-snapshot.js → vault-snapshot.js} +61 -61
- package/sdk/dist/node/vault-snapshot.js.map +1 -0
- package/sdk/dist/node/{gitvault-writer-state.d.ts → vault-writer-state.d.ts} +8 -8
- package/sdk/dist/node/vault-writer-state.d.ts.map +1 -0
- package/sdk/dist/node/{gitvault-writer-state.js → vault-writer-state.js} +15 -15
- package/sdk/dist/node/vault-writer-state.js.map +1 -0
- package/sdk/dist/node/workflow-output.js +4 -4
- package/sdk/dist/node/workflow-output.js.map +1 -1
- package/vault-surface.json +40 -0
- package/gitvault-surface.json +0 -89
- package/lib/gitvault.mjs +0 -163
- package/lib/source-access.mjs +0 -70
- package/sdk/dist/namespaces/gitvault.crypto.d.ts.map +0 -1
- package/sdk/dist/namespaces/gitvault.crypto.js.map +0 -1
- package/sdk/dist/namespaces/gitvault.d.ts.map +0 -1
- package/sdk/dist/namespaces/gitvault.js.map +0 -1
- package/sdk/dist/namespaces/gitvault.types.d.ts.map +0 -1
- package/sdk/dist/namespaces/gitvault.types.js.map +0 -1
- package/sdk/dist/node/gitvault-address.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-address.js.map +0 -1
- package/sdk/dist/node/gitvault-apply.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-apply.js.map +0 -1
- package/sdk/dist/node/gitvault-byo-config.d.ts +0 -29
- package/sdk/dist/node/gitvault-byo-config.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-byo-config.js.map +0 -1
- package/sdk/dist/node/gitvault-byo-probe.d.ts +0 -20
- package/sdk/dist/node/gitvault-byo-probe.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-byo-probe.js +0 -57
- package/sdk/dist/node/gitvault-byo-probe.js.map +0 -1
- package/sdk/dist/node/gitvault-creation-journal.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-creation-journal.js.map +0 -1
- package/sdk/dist/node/gitvault-degraded-read.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-degraded-read.js.map +0 -1
- package/sdk/dist/node/gitvault-deploy.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-deploy.js.map +0 -1
- package/sdk/dist/node/gitvault-edge-fetch.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-edge-fetch.js.map +0 -1
- package/sdk/dist/node/gitvault-handoff.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-handoff.js.map +0 -1
- package/sdk/dist/node/gitvault-keystore.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-keystore.js.map +0 -1
- package/sdk/dist/node/gitvault-member-bundle.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-member-bundle.js.map +0 -1
- package/sdk/dist/node/gitvault-mirror-backend.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-mirror-backend.js.map +0 -1
- package/sdk/dist/node/gitvault-mirror-config.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-mirror-config.js.map +0 -1
- package/sdk/dist/node/gitvault-mirror.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-mirror.js.map +0 -1
- package/sdk/dist/node/gitvault-native-crypto.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-native-crypto.js.map +0 -1
- package/sdk/dist/node/gitvault-open-or-create.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-open-or-create.js.map +0 -1
- package/sdk/dist/node/gitvault-prewarm.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-prewarm.js.map +0 -1
- package/sdk/dist/node/gitvault-profile-scan.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-profile-scan.js.map +0 -1
- package/sdk/dist/node/gitvault-prune.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-prune.js.map +0 -1
- package/sdk/dist/node/gitvault-publication.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-publication.js.map +0 -1
- package/sdk/dist/node/gitvault-push-to-create.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-push-to-create.js.map +0 -1
- package/sdk/dist/node/gitvault-recover.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-recover.js.map +0 -1
- package/sdk/dist/node/gitvault-restore.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-restore.js.map +0 -1
- package/sdk/dist/node/gitvault-snapshot.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-snapshot.js.map +0 -1
- package/sdk/dist/node/gitvault-writer-state.d.ts.map +0 -1
- package/sdk/dist/node/gitvault-writer-state.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The HOST-AGNOSTIC remote-helper session (
|
|
2
|
+
* The HOST-AGNOSTIC remote-helper session (vault-persistent-helper D1).
|
|
3
3
|
*
|
|
4
4
|
* Extracted verbatim from `cli/git-remote-run402.mjs` so ONE implementation
|
|
5
5
|
* serves two hosts: the in-process fallback (the thin bin imports this and
|
|
6
6
|
* runs it with the real process's stdio) and the resident daemon
|
|
7
|
-
* (`cli/lib/
|
|
7
|
+
* (`cli/lib/vault-daemon.mjs`, which forwards a client's session into it).
|
|
8
8
|
* Per-invocation state — wallet resolution, repository resolution, env-
|
|
9
9
|
* derived config — is resolved fresh per `runHelperSession` call; the only
|
|
10
10
|
* thing that persists across sessions in a daemon is warm code and warm
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
* The original file-level doctrine follows, unchanged:
|
|
17
17
|
*
|
|
18
18
|
/**
|
|
19
|
-
* `git-remote-run402` — the git remote helper for
|
|
19
|
+
* `git-remote-run402` — the git remote helper for vault, so plain
|
|
20
20
|
* `git clone|fetch|push run402::<org_id>/<project_id>` speaks to a host-blind
|
|
21
21
|
* encrypted vault with no run402-specific git ceremony.
|
|
22
22
|
*
|
|
23
|
-
* ARCHITECTURAL LAW (
|
|
24
|
-
* SDK"): this file is a THIN ADAPTER over `r.
|
|
23
|
+
* ARCHITECTURAL LAW (vault-client-surface, "All protocol logic lives in the
|
|
24
|
+
* SDK"): this file is a THIN ADAPTER over `r.repos`. It translates git's
|
|
25
25
|
* remote-helper wire protocol into SDK calls and back, and does nothing else.
|
|
26
26
|
* No crypto, no HTTP, no ref-policy decisions, no pack building — those live
|
|
27
27
|
* once in `@run402/sdk`. Even git itself is invoked only through the SDK's own
|
|
@@ -39,18 +39,18 @@
|
|
|
39
39
|
* an unallocated vault reports as an empty ref set, exactly what a fresh
|
|
40
40
|
* repository looks like — but `push` does: `git push origin main` against a
|
|
41
41
|
* project whose vault does not exist yet runs the six-stage creation journal
|
|
42
|
-
* inline (`r.
|
|
42
|
+
* inline (`r.repos.openOrCreate`, the SDK-owned primitive), prints the
|
|
43
43
|
* one-shot recovery receipt and the keystore path to stderr, and then
|
|
44
|
-
* completes the push. One command, no prior `
|
|
44
|
+
* completes the push. One command, no prior `vault init`. `git ls-remote`
|
|
45
45
|
* / `fetch` stay pure reads and allocate nothing.
|
|
46
46
|
*
|
|
47
47
|
* NAMED ADDRESSING + PUSH-TO-CREATE (repo-first-onramp task 4, design D6).
|
|
48
48
|
* `run402::<org>/<name>` admits TWO forms in the same slot — id-form
|
|
49
|
-
* (`org_id`/`prj_...`, unchanged: resolved via `r.
|
|
49
|
+
* (`org_id`/`prj_...`, unchanged: resolved via `r.repos.openOrCreate`
|
|
50
50
|
* above) and slug-form (`run402::<org-slug>/<name>`, e.g.
|
|
51
51
|
* `run402::acme/my-notes`) — discriminated by
|
|
52
|
-
* `
|
|
53
|
-
* `r.
|
|
52
|
+
* `vaultRemoteAddressForm`. A slug-form remote resolves through
|
|
53
|
+
* `r.repos.resolveOrCreateAddress`, which ALSO drives push-to-create on a
|
|
54
54
|
* miss (`push` only; `list`/`fetch` pass `allow_create: false`, same "reads
|
|
55
55
|
* never allocate" discipline as the id-form path) and PINS the resolved
|
|
56
56
|
* `repo_id` in this checkout's local git config the first time it resolves
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
* helper points it at one of the branches THIS push is publishing — the
|
|
96
96
|
* local repository's own HEAD branch when it is among them, else the
|
|
97
97
|
* first branch in the batch — and prints a one-line stderr note saying
|
|
98
|
-
* which and why (see `
|
|
98
|
+
* which and why (see `chooseVaultHeadTargetForPush`). A HEALTHY HEAD
|
|
99
99
|
* (one that already names a ref this push leaves present) is NEVER
|
|
100
100
|
* touched — push moving history never means push moving HEAD.
|
|
101
101
|
* - `option dry-run true` runs the REAL local
|
|
@@ -113,18 +113,18 @@
|
|
|
113
113
|
* `capabilities`, `option` and `list` work without one, which is exactly
|
|
114
114
|
* the set `git ls-remote <url>` outside a checkout needs.
|
|
115
115
|
*
|
|
116
|
-
* DEGRADED READ MODE (
|
|
116
|
+
* DEGRADED READ MODE (vault-byo-primary-bucket, design D4). `list` and
|
|
117
117
|
* `fetch` each wrap their own live gateway read in
|
|
118
|
-
* `getSdk().
|
|
118
|
+
* `getSdk().repos.withDegradedRead` — on a NETWORK-CLASS failure (never a
|
|
119
119
|
* 401/403/404 or any other 4xx; one bounded retry runs first so a transient
|
|
120
120
|
* blip does not flap between sources) with a mirror configured for this
|
|
121
121
|
* vault, the read is served from it instead via the SAME `r402s-recover`
|
|
122
122
|
* engine `run402 repos recover` uses — `git fetch`/`clone` keep working
|
|
123
123
|
* while run402 is down. The result is marked `degraded: true` with source
|
|
124
124
|
* provenance, and exactly one stderr line names the fallback and its source
|
|
125
|
-
* (`
|
|
125
|
+
* (`vaultDegradedReadNote`). Local trust pins never advance past what the
|
|
126
126
|
* mirror copy itself chain-verifies (the fallback engine never touches the
|
|
127
|
-
* live vault's own keystore pins at all — see `
|
|
127
|
+
* live vault's own keystore pins at all — see `vault-degraded-read.ts`'s
|
|
128
128
|
* own doc comment). A vault with no mirror configured is BYTE-IDENTICAL to
|
|
129
129
|
* today: the original gateway error surfaces unchanged. `push` is UNTOUCHED
|
|
130
130
|
* by this — writes are never rerouted; admission always requires the
|
|
@@ -136,7 +136,7 @@ import { statSync } from "node:fs";
|
|
|
136
136
|
|
|
137
137
|
// The heavy graphs load as ONE top-level await batch — in the in-process
|
|
138
138
|
// host this races the thin bin's already-fired prewarm; in the daemon host
|
|
139
|
-
// it happens once at daemon boot (
|
|
139
|
+
// it happens once at daemon boot (vault-startup-amortization D1).
|
|
140
140
|
const sdkModP = import("./sdk.mjs");
|
|
141
141
|
const walletModP = import("./wallet-context.mjs");
|
|
142
142
|
const isoModP = import("#sdk");
|
|
@@ -144,12 +144,12 @@ const nodeModP = import("#sdk/node");
|
|
|
144
144
|
const configModP = import("./config.mjs");
|
|
145
145
|
const { getSdk } = await sdkModP;
|
|
146
146
|
const { resolveWalletCore, enforceWalletExistsCore, WalletSelectionError } = await walletModP;
|
|
147
|
-
const {
|
|
148
|
-
const {
|
|
147
|
+
const { vaultRemoteAddressForm, vaultSlugReleasedInfo, parseVaultRemoteUrl, vaultDegradedReadNote } = await isoModP;
|
|
148
|
+
const { VAULT_R402_REF_NAMESPACE, hardenedGit, resolveGitInvocationRepo, readPinnedVaultRepo, pinVaultRepo, readVaultRestoreMarker, readVaultAutoGcThreshold, predialVaultObjectStore } = await nodeModP;
|
|
149
149
|
const { walletFile, projectCredentialsFile, profileStateFile } = await configModP;
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
* Per-session SDK construction cache (
|
|
152
|
+
* Per-session SDK construction cache (vault-first-op-premium task 2.2).
|
|
153
153
|
*
|
|
154
154
|
* `getSdk()` builds a fresh Node SDK instance on every call — cheap for a
|
|
155
155
|
* traditional one-process-per-invocation CLI, but this module is ALSO the
|
|
@@ -285,7 +285,7 @@ function describeError(err) {
|
|
|
285
285
|
const message = enrichWalletError(err?.message ?? err?.body?.message ?? String(err));
|
|
286
286
|
// SLUG_RELEASED is never auto-followed — but the successor slug (design D6)
|
|
287
287
|
// is exactly the fact a human/agent reading stderr needs to act on it.
|
|
288
|
-
const released =
|
|
288
|
+
const released = vaultSlugReleasedInfo(err);
|
|
289
289
|
const suffix = released?.successor_slug ? ` (renamed to "${released.successor_slug}" — update the remote and re-run)` : "";
|
|
290
290
|
return oneLine(code ? `${code}: ${message}${suffix}` : message);
|
|
291
291
|
}
|
|
@@ -307,7 +307,7 @@ function oneLine(value) {
|
|
|
307
307
|
function resolveRemoteAddress(argv) {
|
|
308
308
|
for (const raw of [argv[1], argv[0]]) {
|
|
309
309
|
if (typeof raw !== "string" || raw.length === 0) continue;
|
|
310
|
-
const direct =
|
|
310
|
+
const direct = parseVaultRemoteUrl(raw);
|
|
311
311
|
if (direct) return direct;
|
|
312
312
|
// Re-add the prefix ONLY for a bare, colon-free address. Without this
|
|
313
313
|
// guard `https://example.com/x` parses as org `https:` / project
|
|
@@ -315,7 +315,7 @@ function resolveRemoteAddress(argv) {
|
|
|
315
315
|
// — a confidently wrong answer is worse than no answer here. The colon is
|
|
316
316
|
// git's own URL punctuation, never part of a bare `<org_id>/<project_id>`.
|
|
317
317
|
if (raw.includes(":")) continue;
|
|
318
|
-
const prefixed =
|
|
318
|
+
const prefixed = parseVaultRemoteUrl(`run402::${raw}`);
|
|
319
319
|
if (prefixed) return prefixed;
|
|
320
320
|
}
|
|
321
321
|
return null;
|
|
@@ -331,11 +331,11 @@ function parsePushSpec(spec) {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
/** `R402_PROTECTED_REF_NAMESPACE`'s one-line reason, shared by the protocol `error` line and the stderr note. */
|
|
334
|
-
export const R402_PROTECTED_REF_NAMESPACE_REASON = `R402_PROTECTED_REF_NAMESPACE: ${
|
|
334
|
+
export const R402_PROTECTED_REF_NAMESPACE_REASON = `R402_PROTECTED_REF_NAMESPACE: ${VAULT_R402_REF_NAMESPACE}* is client-local bookkeeping maintained by fetch, not push — push branches instead.`;
|
|
335
335
|
|
|
336
336
|
/**
|
|
337
337
|
* D4: `refs/r402/*` is client-local (design D1/D2's local ref bookkeeping) —
|
|
338
|
-
* never advertised for push, never part of a `
|
|
338
|
+
* never advertised for push, never part of a `VaultRefTransaction`. Split
|
|
339
339
|
* one push batch into the specs this helper will actually publish and the
|
|
340
340
|
* ones it refuses, PURE and pre-repository (a refname prefix check needs no
|
|
341
341
|
* repo, no network, no wallet), so a batch made ENTIRELY of protected refs
|
|
@@ -349,7 +349,7 @@ export function partitionProtectedRefPushes(specs) {
|
|
|
349
349
|
const refused = [];
|
|
350
350
|
const allowed = [];
|
|
351
351
|
for (const spec of specs) {
|
|
352
|
-
if (spec.dst.startsWith(
|
|
352
|
+
if (spec.dst.startsWith(VAULT_R402_REF_NAMESPACE)) refused.push(spec);
|
|
353
353
|
else allowed.push(spec);
|
|
354
354
|
}
|
|
355
355
|
return { refused, allowed };
|
|
@@ -384,7 +384,7 @@ export function partitionProtectedRefPushes(specs) {
|
|
|
384
384
|
* has no branch update to repair it WITH (a tags-only or deletion-only
|
|
385
385
|
* batch cannot fix a dangling HEAD by itself).
|
|
386
386
|
*/
|
|
387
|
-
export function
|
|
387
|
+
export function chooseVaultHeadTargetForPush({ baseHeadTarget, baseRefs, updates, localHeadRef }) {
|
|
388
388
|
const postPushRefs = { ...(baseRefs ?? {}) };
|
|
389
389
|
for (const u of updates) {
|
|
390
390
|
if (u.new_oid === null) delete postPushRefs[u.ref];
|
|
@@ -412,13 +412,13 @@ export function chooseGitvaultHeadTargetForPush({ baseHeadTarget, baseRefs, upda
|
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
/**
|
|
415
|
-
*
|
|
415
|
+
* vault-checkpoint-cadence design D1 — the pure post-push auto-gc
|
|
416
416
|
* threshold decision, exported standalone so the threshold matrix (below /
|
|
417
417
|
* at / disabled) is directly unit-testable without the session's heavier
|
|
418
418
|
* closures (network, git, daemon plumbing). `0` (or anything not a
|
|
419
419
|
* positive finite number — a corrupt local config value) means disabled;
|
|
420
420
|
* `generationsSinceCheckpoint >= threshold` is the trigger (matches
|
|
421
|
-
* `
|
|
421
|
+
* `vaultCheckpointStaleness`'s own `since >= THRESHOLD` shape).
|
|
422
422
|
*/
|
|
423
423
|
export function shouldRunAutoGc(threshold, generationsSinceCheckpoint) {
|
|
424
424
|
return Number.isFinite(threshold) && threshold > 0 && Number.isFinite(generationsSinceCheckpoint) && generationsSinceCheckpoint >= threshold;
|
|
@@ -427,12 +427,12 @@ export function shouldRunAutoGc(threshold, generationsSinceCheckpoint) {
|
|
|
427
427
|
/**
|
|
428
428
|
* The auto-gc cycle's `compact()`/`prune()` target — exported standalone,
|
|
429
429
|
* same reasoning as `shouldRunAutoGc` above, because the merge itself was
|
|
430
|
-
* the bug: `
|
|
430
|
+
* the bug: `VaultHandleOptions.repo_dir` defaults to
|
|
431
431
|
* `process.cwd()` only in CALLER convention, never inside the SDK's own
|
|
432
432
|
* `open()` (which sets it ONLY when `options.repo_dir !== undefined`).
|
|
433
433
|
* Building the auto-gc target from `{ ...target }` alone — omitting
|
|
434
434
|
* `repo_dir` — makes every real post-push auto-gc cycle fail closed with
|
|
435
|
-
* `
|
|
435
|
+
* `VAULT_REPO_DIR_REQUIRED`, silently degrading to the advisory on
|
|
436
436
|
* EVERY push. `repos gc`'s CLI wrapper passes repo_dir explicitly, so it
|
|
437
437
|
* never exercises this path.
|
|
438
438
|
*/
|
|
@@ -441,8 +441,8 @@ export function buildAutoGcCompactionTarget(target, repoDir) {
|
|
|
441
441
|
}
|
|
442
442
|
|
|
443
443
|
async function main(argv, { onBackgroundWork } = {}) {
|
|
444
|
-
//
|
|
445
|
-
// at the module TOP, before the SDK graph loads (
|
|
444
|
+
// vault-connection-amortization (bench P5) note: the prewarm now fires
|
|
445
|
+
// at the module TOP, before the SDK graph loads (vault-startup-
|
|
446
446
|
// amortization D1) — connection dial and signer warmup both race module
|
|
447
447
|
// evaluation instead of starting here.
|
|
448
448
|
const address = resolveRemoteAddress(argv);
|
|
@@ -457,7 +457,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
457
457
|
// no separate lookup. Only meaningful for an ID-FORM address; a slug-form
|
|
458
458
|
// one resolves through `resolveOrCreateAddress` instead (below), which
|
|
459
459
|
// needs no separate org_id at all — the gateway resolves the slug itself.
|
|
460
|
-
const addressForm =
|
|
460
|
+
const addressForm = vaultRemoteAddressForm(address);
|
|
461
461
|
const target = { project_id: address.project_id, org_id: address.org_id };
|
|
462
462
|
let verbosity = 1;
|
|
463
463
|
// `option dry-run true` is a REAL dry run — see `handleOption`'s
|
|
@@ -476,7 +476,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
476
476
|
async function requireRepo() {
|
|
477
477
|
if (!resolvedRepo) {
|
|
478
478
|
resolvedRepo = await resolveGitInvocationRepo(process.env, process.cwd());
|
|
479
|
-
//
|
|
479
|
+
// vault-object-host-predial task 2.1 (trigger (a), the in-process
|
|
480
480
|
// fallback path — this module IS that fallback; a daemon-forwarded
|
|
481
481
|
// session reaches the same code and gets the same predial for free).
|
|
482
482
|
// The repository is now known OFFLINE (no network read, matching
|
|
@@ -488,8 +488,8 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
488
488
|
// yet predials nothing — never a source of a new failure mode.
|
|
489
489
|
void (async () => {
|
|
490
490
|
try {
|
|
491
|
-
const pinned = await
|
|
492
|
-
if (pinned)
|
|
491
|
+
const pinned = await readPinnedVaultRepo(resolvedRepo.repo_dir);
|
|
492
|
+
if (pinned) predialVaultObjectStore(pinned.repo_id);
|
|
493
493
|
} catch {
|
|
494
494
|
/* best-effort: must never surface from repository resolution */
|
|
495
495
|
}
|
|
@@ -499,7 +499,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
/**
|
|
502
|
-
* One materialize per push session (
|
|
502
|
+
* One materialize per push session (vault-client-round-trips design
|
|
503
503
|
* D1). Git guarantees `list` precedes `push` in the same helper process,
|
|
504
504
|
* so a `list` that resolves an EXISTING vault against a real repository
|
|
505
505
|
* stashes its vault instance + materialized base here; `runPush` reuses
|
|
@@ -547,8 +547,8 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
547
547
|
* Open the vault lazily — `capabilities` and `option` must never touch the
|
|
548
548
|
* network. Both address forms resolve (and, on the first successful
|
|
549
549
|
* resolution, PIN `repo_id` in local git state — task 4.5 for slug-form,
|
|
550
|
-
*
|
|
551
|
-
* id-form) through `
|
|
550
|
+
* vault-client-round-trips design D4 widening the same mechanism to
|
|
551
|
+
* id-form) through `repos.resolveOrCreateAddress` with
|
|
552
552
|
* `allow_create: false` — a read never allocates, and `allow_create` is
|
|
553
553
|
* meaningless for id-form's own dispatch anyway (it never creates,
|
|
554
554
|
* pinned or not). A repo-free call (`repoDir` undefined — `list` outside
|
|
@@ -556,7 +556,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
556
556
|
* pin.
|
|
557
557
|
*/
|
|
558
558
|
const openVault = async (repoDir) => {
|
|
559
|
-
const result = await getCachedSdk().
|
|
559
|
+
const result = await getCachedSdk().repos.resolveOrCreateAddress({ address, allow_create: false, ...(repoDir ? { repo_dir: repoDir } : {}) });
|
|
560
560
|
return { vault: result.handle.vault, keystore: result.handle.keystore, repo_id: result.handle.repo_id, resolution: result.resolution };
|
|
561
561
|
};
|
|
562
562
|
|
|
@@ -567,12 +567,12 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
567
567
|
* `list`/`fetch` stay pure reads and never create anything (see
|
|
568
568
|
* `runList`'s own not-found handling below).
|
|
569
569
|
*
|
|
570
|
-
* Id-form (
|
|
570
|
+
* Id-form (vault-client-round-trips design D4): a PINNED repo_id means
|
|
571
571
|
* this checkout has already resolved (or pushed to) this vault before, so
|
|
572
572
|
* there is nothing left to allocate — the read-only, pin-aware
|
|
573
573
|
* `resolveOrCreateAddress` path (same one `openVault` uses) is enough,
|
|
574
574
|
* and cheaper than re-running the allocation-capable flow on every push.
|
|
575
|
-
* With NO pin yet, this is unchanged: `
|
|
575
|
+
* With NO pin yet, this is unchanged: `repos.openOrCreate` runs its
|
|
576
576
|
* six-stage creation journal when the vault does not exist, exactly as
|
|
577
577
|
* before — and, on success, PINS the resolved id for every later push on
|
|
578
578
|
* this checkout (this is the "first successful resolution" the pin exists
|
|
@@ -586,27 +586,27 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
586
586
|
*/
|
|
587
587
|
async function openOrCreateVault(repoDir) {
|
|
588
588
|
if (addressForm === "id" && repoDir) {
|
|
589
|
-
const pinned = await
|
|
589
|
+
const pinned = await readPinnedVaultRepo(repoDir);
|
|
590
590
|
if (pinned) {
|
|
591
|
-
const result = await getCachedSdk().
|
|
591
|
+
const result = await getCachedSdk().repos.resolveOrCreateAddress({ address, repo_dir: repoDir, allow_create: false });
|
|
592
592
|
return result.handle.vault;
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
595
|
const result =
|
|
596
596
|
addressForm === "id"
|
|
597
|
-
? await getCachedSdk().
|
|
598
|
-
: await getCachedSdk().
|
|
599
|
-
if (addressForm === "id" && repoDir) await
|
|
597
|
+
? await getCachedSdk().repos.openOrCreate({ ...target, repo_dir: repoDir })
|
|
598
|
+
: await getCachedSdk().repos.resolveOrCreateAddress({ address, repo_dir: repoDir, allow_create: true });
|
|
599
|
+
if (addressForm === "id" && repoDir) await pinVaultRepo(repoDir, result.handle.repo_id, undefined, { project_id: target.project_id, org_id: target.org_id });
|
|
600
600
|
if (!result.found && result.created) {
|
|
601
601
|
note("");
|
|
602
602
|
note(`vault ${result.handle.repo_id} allocated (genesis ${result.created.genesis_sha256}) — one-shot recovery receipt, keep many copies:`);
|
|
603
603
|
note(JSON.stringify(result.created.recovery_receipt));
|
|
604
604
|
try {
|
|
605
|
-
const {
|
|
606
|
-
//
|
|
605
|
+
const { getVaultKeystoreRoot, VAULT_MIRROR_SETUP_HINT } = await import("#sdk/node");
|
|
606
|
+
// vault-mirror-default: every allocation teaches the mirror door
|
|
607
607
|
// beside the recovery receipt, lazy push-to-create included.
|
|
608
|
-
note(
|
|
609
|
-
note(`keystore: ${
|
|
608
|
+
note(VAULT_MIRROR_SETUP_HINT);
|
|
609
|
+
note(`keystore: ${getVaultKeystoreRoot()} — back this up; whole-machine or whole-keystore loss is terminal for vault history until human envelopes ship`);
|
|
610
610
|
} catch {
|
|
611
611
|
// Never let a diagnostic line fail a push that already allocated successfully.
|
|
612
612
|
}
|
|
@@ -633,7 +633,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
633
633
|
// checkout) — `list` still works, and there is nothing for `push` to
|
|
634
634
|
// share later in that case.
|
|
635
635
|
}
|
|
636
|
-
//
|
|
636
|
+
// vault-session-state-reuse design D2: read the restore MARKER —
|
|
637
637
|
// NEVER the chain-trust pin (see `tryStateFastPath`'s own doc comment on
|
|
638
638
|
// why the pin is the wrong `since` for a standing clone that is
|
|
639
639
|
// generations behind) — once, here, and thread it to the materialize
|
|
@@ -643,12 +643,12 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
643
643
|
let fetchMarker = null;
|
|
644
644
|
if (repoDir) {
|
|
645
645
|
try {
|
|
646
|
-
fetchMarker = await
|
|
646
|
+
fetchMarker = await readVaultRestoreMarker(repoDir);
|
|
647
647
|
} catch {
|
|
648
648
|
fetchMarker = null;
|
|
649
649
|
}
|
|
650
650
|
}
|
|
651
|
-
//
|
|
651
|
+
// vault-restore-recipe design D2/D6: a marker-absent fetch target is,
|
|
652
652
|
// by construction, the WHOLESALE restore shape (a fresh `git clone`, or
|
|
653
653
|
// a target that never completed a restore) — declare restore intent
|
|
654
654
|
// here so a capable gateway's plan rides THIS state read, reused by
|
|
@@ -673,18 +673,18 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
673
673
|
endBlock();
|
|
674
674
|
return;
|
|
675
675
|
}
|
|
676
|
-
//
|
|
676
|
+
// vault-byo-primary-bucket (design D4): the OPEN itself needed the
|
|
677
677
|
// gateway. On a network-class failure, with this checkout already
|
|
678
678
|
// knowing the vault and holding a local copy source (its BYO destination
|
|
679
679
|
// or a mirror), the listing is served from that copy — `null` means the
|
|
680
680
|
// fallback cannot help and the original error surfaces unchanged.
|
|
681
|
-
const fallback = repoDir ? await getCachedSdk().
|
|
681
|
+
const fallback = repoDir ? await getCachedSdk().repos.degradedOpenFallback?.({ address, repo_dir: repoDir, error: err }).catch(() => null) : null;
|
|
682
682
|
if (!fallback) throw err;
|
|
683
683
|
outcome = fallback;
|
|
684
684
|
}
|
|
685
685
|
let vault = opened?.vault;
|
|
686
686
|
|
|
687
|
-
//
|
|
687
|
+
// vault-byo-primary-bucket (design D4, task 3.4 — mirror half): the
|
|
688
688
|
// live materialize (with its own stale-pin retry, unchanged from before
|
|
689
689
|
// this change) is the "attemptLive" `withDegradedRead` wraps — on a
|
|
690
690
|
// NETWORK-CLASS failure (never 4xx) with a mirror configured for this
|
|
@@ -705,7 +705,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
705
705
|
// always runs `list` first in a helper session, so this one site
|
|
706
706
|
// heals the pin for the `fetch`/`push` that follows it.
|
|
707
707
|
const recovered = repoDir && opened.resolution?.offline
|
|
708
|
-
? await getCachedSdk().
|
|
708
|
+
? await getCachedSdk().repos.recoverStalePin({ address, repo_dir: repoDir, resolution: opened.resolution, error: err })
|
|
709
709
|
: null;
|
|
710
710
|
if (!recovered) throw err;
|
|
711
711
|
note(`pinned vault ${opened.resolution.repo_id} no longer resolves — re-resolved to ${recovered.resolution.repo_id}, retrying`);
|
|
@@ -717,7 +717,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
717
717
|
|
|
718
718
|
if (!outcome) {
|
|
719
719
|
try {
|
|
720
|
-
outcome = await getCachedSdk().
|
|
720
|
+
outcome = await getCachedSdk().repos.withDegradedRead({ attemptLive, keystore: opened.keystore, repo_id: opened.repo_id, out_dir: repoDir });
|
|
721
721
|
} catch (err) {
|
|
722
722
|
// Same "an unallocated vault is not an error" reasoning as above — a
|
|
723
723
|
// 404 discovered only once materialize actually runs takes this same
|
|
@@ -738,7 +738,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
738
738
|
// Exactly ONE stderr line naming the degraded read and its source
|
|
739
739
|
// (design D4) — the validity-not-freshness limit rides inside the
|
|
740
740
|
// canonical statement this composes, verbatim.
|
|
741
|
-
note(
|
|
741
|
+
note(vaultDegradedReadNote(outcome.result.source));
|
|
742
742
|
refs = outcome.result.refs ?? {};
|
|
743
743
|
head = outcome.result.head_target;
|
|
744
744
|
// No live vault instance materialized this pass — nothing safe to
|
|
@@ -749,7 +749,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
749
749
|
const state = outcome.live;
|
|
750
750
|
refs = state.refs ?? {};
|
|
751
751
|
head = state.head_target;
|
|
752
|
-
//
|
|
752
|
+
// vault-session-state-reuse design D1: `fetchState`/`fetchMarker`
|
|
753
753
|
// extend the SAME session-scoped handoff `push` already reuses (`base`)
|
|
754
754
|
// — the `fetch` phase of THIS session reuses this response instead of
|
|
755
755
|
// issuing its own state read. Session-scoped only: dropped the moment a
|
|
@@ -793,7 +793,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
793
793
|
// wherever clone was run FROM, unrelated to the target repository).
|
|
794
794
|
applyWalletForDir(repoDir);
|
|
795
795
|
if (verbosity >= 1) note(`restoring the vault object database for ${batch.length} ref(s) into ${repoDir}`);
|
|
796
|
-
//
|
|
796
|
+
// vault-session-state-reuse design D1/D4: reuse THIS session's `list`
|
|
797
797
|
// phase state — same resolved repository AND wallet, exactly the same
|
|
798
798
|
// matching rule `push`'s own reuse uses above — instead of a second
|
|
799
799
|
// network state read. Any mismatch (no prior `list`, a failed list, a
|
|
@@ -801,9 +801,9 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
801
801
|
// same session — see `runPush`'s reset) falls back to the vault's own
|
|
802
802
|
// read, unchanged.
|
|
803
803
|
//
|
|
804
|
-
//
|
|
804
|
+
// vault-byo-primary-bucket (design D4, task 3.4 — mirror half):
|
|
805
805
|
// either path's actual chain/payload read is the "attemptLive" that
|
|
806
|
-
// `withDegradedRead` wraps — `
|
|
806
|
+
// `withDegradedRead` wraps — `repos.restore(...)` is exactly `open()`
|
|
807
807
|
// followed by `handle.vault.restoreObjectsInto(target_dir)` (see that
|
|
808
808
|
// method's own one-line body), decomposed here so the SECOND half can be
|
|
809
809
|
// wrapped, with byte-identical resolution to today on the live-success
|
|
@@ -824,11 +824,11 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
824
824
|
} else {
|
|
825
825
|
let handle = null;
|
|
826
826
|
try {
|
|
827
|
-
handle = await getCachedSdk().
|
|
827
|
+
handle = await getCachedSdk().repos.open({ ...target, repo_dir: repoDir });
|
|
828
828
|
} catch (err) {
|
|
829
|
-
//
|
|
829
|
+
// vault-byo-primary-bucket (design D4): the open needed the
|
|
830
830
|
// gateway — see runList's identical fallback.
|
|
831
|
-
const fallback = await getCachedSdk().
|
|
831
|
+
const fallback = await getCachedSdk().repos.degradedOpenFallback?.({ address, repo_dir: repoDir, error: err }).catch(() => null);
|
|
832
832
|
if (!fallback) throw err;
|
|
833
833
|
outcome = fallback;
|
|
834
834
|
}
|
|
@@ -839,7 +839,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
839
839
|
}
|
|
840
840
|
}
|
|
841
841
|
if (!outcome) {
|
|
842
|
-
outcome = await getCachedSdk().
|
|
842
|
+
outcome = await getCachedSdk().repos.withDegradedRead({
|
|
843
843
|
attemptLive,
|
|
844
844
|
keystore: degradedKeystore,
|
|
845
845
|
repo_id: degradedRepoId,
|
|
@@ -853,7 +853,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
853
853
|
// canonical statement this composes, verbatim. A later `git push`
|
|
854
854
|
// still requires the gateway unchanged — this function only ever
|
|
855
855
|
// serves reads; `runPush` below is untouched by this change.
|
|
856
|
-
note(
|
|
856
|
+
note(vaultDegradedReadNote(outcome.result.source));
|
|
857
857
|
restored = { generation: outcome.result.generation, retained_refs: outcome.result.retained_refs };
|
|
858
858
|
} else {
|
|
859
859
|
restored = { generation: outcome.live.generation, retained_refs: outcome.live.retained_refs };
|
|
@@ -872,7 +872,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
872
872
|
}
|
|
873
873
|
|
|
874
874
|
/**
|
|
875
|
-
*
|
|
875
|
+
* vault-checkpoint-cadence (design D1/D2) — the post-push auto-gc
|
|
876
876
|
* cadence, `git gc --auto`'s shape: a cheap local threshold check after
|
|
877
877
|
* every successful push, maintenance only past it.
|
|
878
878
|
*
|
|
@@ -884,7 +884,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
884
884
|
* it.
|
|
885
885
|
*
|
|
886
886
|
* Threshold: `repoDir`'s local `auto_gc_generations` (default 32, `0`
|
|
887
|
-
* disables — `
|
|
887
|
+
* disables — `readVaultAutoGcThreshold`, design D1's "rides the
|
|
888
888
|
* existing vault policy surface" as a per-checkout `repos policy` knob).
|
|
889
889
|
*
|
|
890
890
|
* Dispatch: with a daemon-supplied `onBackgroundWork`, the compaction is
|
|
@@ -894,9 +894,9 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
894
894
|
* one (the in-process fallback), the SAME cycle is awaited right here,
|
|
895
895
|
* with one stderr advisory line naming the wait.
|
|
896
896
|
*
|
|
897
|
-
* `compact()` (namespace, `sdk/src/namespaces/
|
|
897
|
+
* `compact()` (namespace, `sdk/src/namespaces/repos.ts`) already owns
|
|
898
898
|
* the compaction headroom grant's open/close and single-flight refusal
|
|
899
|
-
* (`
|
|
899
|
+
* (`VAULT_COMPACTION_IN_PROGRESS`) — this function only decides WHETHER
|
|
900
900
|
* and HOW to run the cycle, never re-implements those. `--force-headroom`
|
|
901
901
|
* is NEVER passed on this path (design D5) — an insufficient-headroom
|
|
902
902
|
* refusal, a conflicting in-flight compaction, or any other failure all
|
|
@@ -906,23 +906,23 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
906
906
|
async function maybeRunAutoGc({ repoDir, generationsSinceCheckpoint }) {
|
|
907
907
|
let threshold;
|
|
908
908
|
try {
|
|
909
|
-
threshold = await
|
|
909
|
+
threshold = await readVaultAutoGcThreshold(repoDir);
|
|
910
910
|
} catch {
|
|
911
911
|
return; // never let a local-config read failure touch the push it follows
|
|
912
912
|
}
|
|
913
913
|
if (!shouldRunAutoGc(threshold, generationsSinceCheckpoint)) return;
|
|
914
914
|
|
|
915
915
|
// `compact()`/`prune()` never default repo_dir to process.cwd() —
|
|
916
|
-
//
|
|
916
|
+
// VaultHandleOptions's own doc comment describes CALLER
|
|
917
917
|
// convention, not an SDK fallback (`open()` only sets repo_dir when
|
|
918
918
|
// `options.repo_dir !== undefined`). Omitting it here made every real
|
|
919
|
-
// post-push auto-gc cycle fail closed with
|
|
919
|
+
// post-push auto-gc cycle fail closed with VAULT_REPO_DIR_REQUIRED,
|
|
920
920
|
// silently degrading to the advisory on every push.
|
|
921
921
|
const compactionTarget = buildAutoGcCompactionTarget(target, repoDir);
|
|
922
922
|
const runCycle = async () => {
|
|
923
923
|
const sdk = getCachedSdk();
|
|
924
|
-
const checkpoint = await sdk.
|
|
925
|
-
const prune = await sdk.
|
|
924
|
+
const checkpoint = await sdk.repos.compact({ ...compactionTarget });
|
|
925
|
+
const prune = await sdk.repos.prune(compactionTarget); // PLAN only — never `submit`; see compact()'s own grant-close doc comment for why prune needs no headroom of its own
|
|
926
926
|
return { checkpoint, prune };
|
|
927
927
|
};
|
|
928
928
|
|
|
@@ -938,17 +938,17 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
938
938
|
}
|
|
939
939
|
|
|
940
940
|
// In-process fallback: the extra wall time is real, so name it.
|
|
941
|
-
note(`
|
|
941
|
+
note(`vault: compacting (${generationsSinceCheckpoint} generations since checkpoint)…`);
|
|
942
942
|
try {
|
|
943
943
|
await runCycle();
|
|
944
944
|
} catch (err) {
|
|
945
|
-
note(`
|
|
945
|
+
note(`vault: auto-compaction stopped short — ${describeError(err)} — run \`run402 repos gc\` to finish it by hand.`);
|
|
946
946
|
}
|
|
947
947
|
}
|
|
948
948
|
|
|
949
949
|
async function runPush(batch) {
|
|
950
950
|
const specs = batch.map(parsePushSpec);
|
|
951
|
-
//
|
|
951
|
+
// vault-checkpoint-cadence: set ONLY after a successful admission
|
|
952
952
|
// (never in the catch block) — `null` means "auto-gc has nothing to
|
|
953
953
|
// do", which is also the correct value for every early-return path
|
|
954
954
|
// above (nothing pushed, nothing refused-only, dry-run).
|
|
@@ -1052,10 +1052,10 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1052
1052
|
});
|
|
1053
1053
|
}
|
|
1054
1054
|
// Repair a DANGLING HEAD from this batch's own branches — see
|
|
1055
|
-
// `
|
|
1055
|
+
// `chooseVaultHeadTargetForPush`'s own doc comment for the exact
|
|
1056
1056
|
// rule. `localHeadRef` is read from THIS repository (never cwd, same
|
|
1057
1057
|
// fail-closed resolution as everything else in this function).
|
|
1058
|
-
const headFix =
|
|
1058
|
+
const headFix = chooseVaultHeadTargetForPush({
|
|
1059
1059
|
baseHeadTarget: base.head_target,
|
|
1060
1060
|
baseRefs: base.refs,
|
|
1061
1061
|
updates,
|
|
@@ -1072,7 +1072,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1072
1072
|
base,
|
|
1073
1073
|
...(headFix.head_target ? { head_target: headFix.head_target } : {}),
|
|
1074
1074
|
});
|
|
1075
|
-
//
|
|
1075
|
+
// vault-session-state-reuse design D4: this admission just advanced
|
|
1076
1076
|
// the vault, so the `list` phase's handoff (if any) is now stale —
|
|
1077
1077
|
// drop it. A `fetch` later in this SAME session (an unusual ordering
|
|
1078
1078
|
// git's own protocol does not normally produce) reads fresh rather
|
|
@@ -1083,12 +1083,12 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1083
1083
|
// opt-in mirror dual-push and a BYO vault's signed-chain copy into the
|
|
1084
1084
|
// customer bucket. Best-effort: never alters the push above, one
|
|
1085
1085
|
// stderr line per outcome worth knowing.
|
|
1086
|
-
const copies = await getCachedSdk().
|
|
1086
|
+
const copies = await getCachedSdk().repos.postPublishCopies?.({ repo_id: vault.repoId, keystore: vault.keystore }).catch(() => null);
|
|
1087
1087
|
if (copies?.mirror_push?.outcome === "pushed") note(`mirror: pushed generation ${published.generation} (${copies.mirror_push.summary?.objects_copied ?? 0} object(s) copied)`);
|
|
1088
|
-
else if (copies?.mirror_push?.outcome === "failed") note(`mirror:
|
|
1088
|
+
else if (copies?.mirror_push?.outcome === "failed") note(`mirror: mirroring this capture FAILED (the push is unaffected) — ${copies.mirror_push.error ?? "see run402 repos fsck --mirror"}`);
|
|
1089
1089
|
if (copies?.byo_chain_copy?.outcome === "pushed") note(`byo: signed-chain copy written to your bucket (${copies.byo_chain_copy.summary?.objects_copied ?? 0} object(s))`);
|
|
1090
1090
|
else if (copies?.byo_chain_copy?.outcome === "failed") note(`byo: signed-chain copy FAILED (the push is unaffected) — ${copies.byo_chain_copy.error ?? copies.byo_chain_copy.summary?.errors?.[0]?.error ?? "see run402 repos fsck"}`);
|
|
1091
|
-
//
|
|
1091
|
+
// vault-clone-scaling (P3): advisory only — informational, always
|
|
1092
1092
|
// fires at 25 generations regardless of the SEPARATE auto-gc
|
|
1093
1093
|
// threshold below (design D1's `auto_gc_generations`, default 32) —
|
|
1094
1094
|
// the two are deliberately different numbers for different purposes.
|
|
@@ -1096,7 +1096,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1096
1096
|
note(`${published.checkpoint_staleness.generations_since_checkpoint} generations since the last checkpoint — cold clones re-verify each one; run402 repos gc compacts them`);
|
|
1097
1097
|
}
|
|
1098
1098
|
for (const spec of allowed) out(`ok ${spec.dst}`);
|
|
1099
|
-
//
|
|
1099
|
+
// vault-checkpoint-cadence: captured here (never in the catch
|
|
1100
1100
|
// block below — auto-gc must never fire on a failed push) and acted
|
|
1101
1101
|
// on AFTER this function's own `endBlock()`, so the auto-gc check
|
|
1102
1102
|
// itself can never delay, alter, or reorder the push's own report.
|
|
@@ -1105,7 +1105,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1105
1105
|
// The transaction is atomic, so a failure failed every ref in it. Report
|
|
1106
1106
|
// it against each one rather than letting some look like they landed.
|
|
1107
1107
|
if (err?.code === "GIT_INVOCATION_REPO_UNRESOLVED") repoRefusalNote(err);
|
|
1108
|
-
// Force-spelling truth (
|
|
1108
|
+
// Force-spelling truth (vault-force-spelling-and-pin-fold): render
|
|
1109
1109
|
// the SDK's own `git push --force` next_action beside git's per-ref
|
|
1110
1110
|
// rejection — humans read stderr, agents read the structured error.
|
|
1111
1111
|
const forceHint = Array.isArray(err?.body?.next_actions) ? err.body.next_actions.find((a) => a?.action === "git push --force") : null;
|
|
@@ -1114,7 +1114,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1114
1114
|
for (const spec of allowed) out(`error ${spec.dst} ${reason}`);
|
|
1115
1115
|
}
|
|
1116
1116
|
endBlock();
|
|
1117
|
-
//
|
|
1117
|
+
// vault-checkpoint-cadence design D1/D2: strictly AFTER the push's
|
|
1118
1118
|
// own report — `null` (a failed push, a refused-only batch, dry-run)
|
|
1119
1119
|
// is a silent no-op. `maybeRunAutoGc` itself never throws.
|
|
1120
1120
|
if (autoGcCandidate) await maybeRunAutoGc(autoGcCandidate);
|
|
@@ -1221,7 +1221,7 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1221
1221
|
}
|
|
1222
1222
|
|
|
1223
1223
|
/**
|
|
1224
|
-
* Run one remote-helper session to completion (
|
|
1224
|
+
* Run one remote-helper session to completion (vault-persistent-helper
|
|
1225
1225
|
* D1). `argv` is git's argv slice (`[remote, address]`); `stdin` is the
|
|
1226
1226
|
* session's input stream (defaults to the real process stdin for the
|
|
1227
1227
|
* in-process host). Per-session module state is reset here so a daemon
|
|
@@ -1229,8 +1229,8 @@ async function main(argv, { onBackgroundWork } = {}) {
|
|
|
1229
1229
|
* the next (D2). Never throws — the error path is the same
|
|
1230
1230
|
* note-and-exit-1 the standalone binary always had.
|
|
1231
1231
|
*
|
|
1232
|
-
* `onBackgroundWork` (
|
|
1233
|
-
* (the DAEMON host only — see `
|
|
1232
|
+
* `onBackgroundWork` (vault-checkpoint-cadence design D2): when supplied
|
|
1233
|
+
* (the DAEMON host only — see `vault-daemon.mjs`), a successful push's
|
|
1234
1234
|
* auto-gc cycle is handed to it as an ALREADY-STARTED promise instead of
|
|
1235
1235
|
* being awaited inline, so this call resolves (and the client-visible
|
|
1236
1236
|
* session ends) at push speed. The caller is responsible for keeping
|