run402 4.36.1 → 4.37.1
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 +15 -0
- package/cli.mjs +6 -0
- package/git-remote-run402.mjs +63 -3
- package/lib/command-manifest.mjs +13 -1
- package/lib/gitvault-scaffold.mjs +59 -0
- package/lib/gitvault.mjs +69 -22
- package/lib/init.mjs +8 -3
- package/lib/projects.mjs +16 -0
- package/lib/repos.mjs +324 -0
- package/lib/up.mjs +167 -29
- package/package.json +1 -1
- package/sdk/dist/errors.d.ts +1 -1
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts +1 -1
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +1 -1
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +9 -0
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.types.js.map +1 -1
- package/sdk/dist/namespaces/gitvault.d.ts +133 -16
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +207 -16
- package/sdk/dist/namespaces/gitvault.js.map +1 -1
- package/sdk/dist/node/gitvault-apply.d.ts +18 -1
- package/sdk/dist/node/gitvault-apply.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-apply.js +38 -1
- package/sdk/dist/node/gitvault-apply.js.map +1 -1
- package/sdk/dist/node/gitvault-creation-journal.d.ts +22 -0
- package/sdk/dist/node/gitvault-creation-journal.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-creation-journal.js +28 -0
- package/sdk/dist/node/gitvault-creation-journal.js.map +1 -1
- package/sdk/dist/node/gitvault-open-or-create.d.ts +59 -0
- package/sdk/dist/node/gitvault-open-or-create.d.ts.map +1 -0
- package/sdk/dist/node/gitvault-open-or-create.js +62 -0
- package/sdk/dist/node/gitvault-open-or-create.js.map +1 -0
- package/sdk/dist/node/index.d.ts +3 -1
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +4 -1
- package/sdk/dist/node/index.js.map +1 -1
|
@@ -112,6 +112,21 @@ export interface GitvaultStatus {
|
|
|
112
112
|
command?: string;
|
|
113
113
|
}[];
|
|
114
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* What {@link Gitvault.scaffoldRemote} did, and why (D1). `name` is `origin`
|
|
117
|
+
* when it was free (or a caller-supplied name), `run402` when `origin` was
|
|
118
|
+
* already taken by something else, or the caller's explicit `remote_name`.
|
|
119
|
+
* `reason` is a human-readable sentence naming exactly what happened —
|
|
120
|
+
* printed to stderr by every CLI caller, never synthesized twice.
|
|
121
|
+
*/
|
|
122
|
+
export interface GitvaultScaffoldRemoteResult {
|
|
123
|
+
name: string;
|
|
124
|
+
url: string;
|
|
125
|
+
created_repository: boolean;
|
|
126
|
+
already_present: boolean;
|
|
127
|
+
existing_url: string | null;
|
|
128
|
+
reason: string;
|
|
129
|
+
}
|
|
115
130
|
export interface GitvaultInitResult {
|
|
116
131
|
repo_id: string;
|
|
117
132
|
project_id: string;
|
|
@@ -119,10 +134,7 @@ export interface GitvaultInitResult {
|
|
|
119
134
|
recovery_receipt: GitvaultCreationResult["recovery_receipt"];
|
|
120
135
|
genesis_sha256: string;
|
|
121
136
|
/** The git remote that was added, when a working tree was scaffolded. */
|
|
122
|
-
remote:
|
|
123
|
-
name: string;
|
|
124
|
-
url: string;
|
|
125
|
-
} | null;
|
|
137
|
+
remote: GitvaultScaffoldRemoteResult | null;
|
|
126
138
|
deduplicated: boolean;
|
|
127
139
|
terminal_loss_statement: typeof GITVAULT_TERMINAL_LOSS_STATEMENT;
|
|
128
140
|
}
|
|
@@ -214,6 +226,20 @@ export interface GitvaultHandle {
|
|
|
214
226
|
/** The full protocol object — every verb below is built on it. */
|
|
215
227
|
vault: import("../node/gitvault-publication.js").GitvaultVault;
|
|
216
228
|
}
|
|
229
|
+
/** What {@link Gitvault.openOrCreate} did. `created` is `null` exactly when `found` is `true`. */
|
|
230
|
+
export interface GitvaultOpenOrCreateResult {
|
|
231
|
+
handle: GitvaultHandle;
|
|
232
|
+
/** `true` when the vault already existed — nothing was allocated by this call. */
|
|
233
|
+
found: boolean;
|
|
234
|
+
created: {
|
|
235
|
+
/** Mirrors `GitvaultInitResult.deduplicated`: an existing local creation journal was resumed to completion rather than started fresh — nothing was re-minted. */
|
|
236
|
+
deduplicated: boolean;
|
|
237
|
+
/** Emitted once at creation — integrity data, not a secret. Print it, copy it, keep many copies. Persisted into the keystore regardless. */
|
|
238
|
+
recovery_receipt: GitvaultCreationResult["recovery_receipt"];
|
|
239
|
+
genesis_sha256: string;
|
|
240
|
+
} | null;
|
|
241
|
+
terminal_loss_statement: typeof GITVAULT_TERMINAL_LOSS_STATEMENT;
|
|
242
|
+
}
|
|
217
243
|
export declare class Gitvault {
|
|
218
244
|
#private;
|
|
219
245
|
constructor(client: Client);
|
|
@@ -293,6 +319,33 @@ export declare class Gitvault {
|
|
|
293
319
|
* surface (ref transactions, repair, checkpoint building).
|
|
294
320
|
*/
|
|
295
321
|
open(options?: GitvaultVaultHandleOptions): Promise<GitvaultHandle>;
|
|
322
|
+
/**
|
|
323
|
+
* Open a vault, allocating it first when it does not exist yet (D2 — lazy
|
|
324
|
+
* allocation on first push).
|
|
325
|
+
*
|
|
326
|
+
* This is the ONE primitive the remote helper and the capture lane
|
|
327
|
+
* (`run402 gitvault push`/`snapshot`) drive so that a push against an
|
|
328
|
+
* unallocated project runs the six-stage creation journal inline instead of
|
|
329
|
+
* refusing: it resolves `repo_id` from `project_id` exactly like
|
|
330
|
+
* {@link open}, and when that resolution fails, tries to create the vault —
|
|
331
|
+
* but ONLY when `org_id` was supplied. Without `org_id` this method is
|
|
332
|
+
* byte-identical to `open()`: the original resolution failure is rethrown
|
|
333
|
+
* unchanged, so every existing caller of `open()` that has no reason to
|
|
334
|
+
* create anything sees no behavior change at all by switching to this.
|
|
335
|
+
*
|
|
336
|
+
* RESUMABILITY (client-surface spec, D2): before starting a fresh creation
|
|
337
|
+
* attempt this looks for an INCOMPLETE local journal already matching this
|
|
338
|
+
* exact `(org_id, project_id)` and resumes ITS `client_creation_id`, rather
|
|
339
|
+
* than starting a second competing attempt every time the process is
|
|
340
|
+
* interrupted mid-creation. Kill the process after ALLOCATED and call this
|
|
341
|
+
* again: the same journal — not a new one — drives to ACTIVE, and exactly
|
|
342
|
+
* one vault exists either way. An explicit `client_creation_id` (tests, or
|
|
343
|
+
* a caller resuming a specific attempt by hand) always wins over that search.
|
|
344
|
+
*/
|
|
345
|
+
openOrCreate(options: GitvaultVaultHandleOptions & {
|
|
346
|
+
org_id?: string;
|
|
347
|
+
client_creation_id?: string;
|
|
348
|
+
}): Promise<GitvaultOpenOrCreateResult>;
|
|
296
349
|
/**
|
|
297
350
|
* Create the vault for a project and scaffold the git remote.
|
|
298
351
|
*
|
|
@@ -319,12 +372,24 @@ export declare class Gitvault {
|
|
|
319
372
|
service_public_key?: Uint8Array | string;
|
|
320
373
|
}): Promise<GitvaultInitResult>;
|
|
321
374
|
/**
|
|
322
|
-
* Add the
|
|
375
|
+
* Add the run402 git remote, initialising the repository if absent.
|
|
376
|
+
*
|
|
377
|
+
* D1 — claim `origin` additively. LLM muscle memory is `git push origin
|
|
378
|
+
* main` from a billion training examples, and a side-remote name costs
|
|
379
|
+
* every agent a correction cycle, so when the repository has no `origin`
|
|
380
|
+
* remote ours BECOMES `origin`. An existing `origin` is NEVER modified or
|
|
381
|
+
* reclaimed — no matter what it points at, including a prior run of this
|
|
382
|
+
* exact call — so the fallback is `run402`, and when THAT is also taken by
|
|
383
|
+
* something else, nothing is added at all: the additive discipline holds
|
|
384
|
+
* for every remote name this method ever touches, not just `origin`.
|
|
385
|
+
*
|
|
386
|
+
* An explicit `remote_name` is a caller override (no current caller passes
|
|
387
|
+
* one) and skips the origin/run402 dance entirely — the caller already
|
|
388
|
+
* decided the name; this method still never modifies an existing remote
|
|
389
|
+
* under it.
|
|
323
390
|
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
* silently rewritten. No key material or allocation is required — the
|
|
327
|
-
* cold-start path gains no prompts or network dependencies from this.
|
|
391
|
+
* No key material or allocation is required — the cold-start path gains no
|
|
392
|
+
* prompts or network dependencies from this.
|
|
328
393
|
*/
|
|
329
394
|
scaffoldRemote(options: {
|
|
330
395
|
repo_dir: string;
|
|
@@ -332,13 +397,7 @@ export declare class Gitvault {
|
|
|
332
397
|
project_id: string;
|
|
333
398
|
remote_name?: string;
|
|
334
399
|
remote_url?: string;
|
|
335
|
-
}): Promise<
|
|
336
|
-
name: string;
|
|
337
|
-
url: string;
|
|
338
|
-
created_repository: boolean;
|
|
339
|
-
already_present: boolean;
|
|
340
|
-
existing_url: string | null;
|
|
341
|
-
}>;
|
|
400
|
+
}): Promise<GitvaultScaffoldRemoteResult>;
|
|
342
401
|
/**
|
|
343
402
|
* What this machine and the control plane each believe about the vault.
|
|
344
403
|
*
|
|
@@ -387,6 +446,25 @@ export declare class Gitvault {
|
|
|
387
446
|
* storage. A 200 alone is never enough (§0 client obligations).
|
|
388
447
|
*/
|
|
389
448
|
push(options: GitvaultVaultHandleOptions & {
|
|
449
|
+
/**
|
|
450
|
+
* The owning org. Supply it to run D2's lazy allocation: when this
|
|
451
|
+
* project's vault does not exist yet, push() runs the six-stage
|
|
452
|
+
* creation journal inline (via {@link openOrCreate}) before capturing
|
|
453
|
+
* and publishing — one command, no prior `gitvault init`. Without it,
|
|
454
|
+
* push() behaves exactly as it always did: a push against an
|
|
455
|
+
* unallocated vault throws the resolution failure unchanged.
|
|
456
|
+
*/
|
|
457
|
+
org_id?: string;
|
|
458
|
+
/** Resume a specific creation attempt (or pin it in tests); auto-discovered from the local keystore otherwise. */
|
|
459
|
+
client_creation_id?: string;
|
|
460
|
+
/**
|
|
461
|
+
* Fires once, only when THIS call allocated the vault — the moment to
|
|
462
|
+
* print the one-shot recovery receipt and keystore path. Awaited
|
|
463
|
+
* before capture/publish continue, so any async work inside it (e.g.
|
|
464
|
+
* resolving the keystore path to print) completes and stays ordered
|
|
465
|
+
* BEFORE the rest of this push's own output.
|
|
466
|
+
*/
|
|
467
|
+
onVaultCreated?: (created: NonNullable<GitvaultOpenOrCreateResult["created"]>) => void | Promise<void>;
|
|
390
468
|
/**
|
|
391
469
|
* Capture options, forwarded verbatim to `captureSnapshot`. The commit
|
|
392
470
|
* message for the synthetic commit a dirty tree produces lives HERE
|
|
@@ -511,6 +589,45 @@ export declare class Gitvault {
|
|
|
511
589
|
generation: string;
|
|
512
590
|
}>;
|
|
513
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* The composite escalation trigger (design D7): ANY of these crossing its
|
|
594
|
+
* threshold escalates the quiet genesis-time note into a standing warning.
|
|
595
|
+
* Deliberately an OR — any single metric alone is gameable by triviality
|
|
596
|
+
* (an agent that pads one dimension to stay under a lone threshold). Shipped
|
|
597
|
+
* as defaults; tunable in this ONE place, not a protocol contract.
|
|
598
|
+
*/
|
|
599
|
+
export declare const GITVAULT_LOSS_WARNING_THRESHOLDS: {
|
|
600
|
+
readonly generations: 10;
|
|
601
|
+
readonly source_bytes: number;
|
|
602
|
+
readonly days_since_genesis: 14;
|
|
603
|
+
};
|
|
604
|
+
/** Which composite metric(s) crossed their D7 threshold, if any. */
|
|
605
|
+
export interface GitvaultLossWarningTrip {
|
|
606
|
+
generations: boolean;
|
|
607
|
+
source_bytes: boolean;
|
|
608
|
+
days_since_genesis: boolean;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* D7: has this vault crossed the composite terminal-loss escalation trigger?
|
|
612
|
+
* Pure — no I/O, no clock dependency beyond the optional `now` override
|
|
613
|
+
* (tests). `admitted_generations` and `storage.source_bytes` are decimal
|
|
614
|
+
* strings (protocol convention for values that could exceed safe-integer
|
|
615
|
+
* precision in principle; comfortably within it here).
|
|
616
|
+
*
|
|
617
|
+
* There is deliberately no companion "is this resolved" function: V0-A
|
|
618
|
+
* cannot detect a second principal or human envelope able to open the vault
|
|
619
|
+
* (design D7's stricter-than-drafted resolution), so once tripped this has
|
|
620
|
+
* nothing further to compute — a caller does not un-trip it, ever, in V0.
|
|
621
|
+
*/
|
|
622
|
+
export declare function gitvaultLossWarningTrip(record: Pick<GitvaultVaultRecord, "admitted_generations" | "storage" | "genesis_admitted_at">, now?: Date): GitvaultLossWarningTrip;
|
|
623
|
+
/** Any composite metric tripped — the standing warning threshold itself. */
|
|
624
|
+
export declare function gitvaultLossWarningTripped(trip: GitvaultLossWarningTrip): boolean;
|
|
625
|
+
/**
|
|
626
|
+
* The standing warning text (design D7): names what tripped, states the
|
|
627
|
+
* resolution honestly (a second principal or human envelope — nothing this
|
|
628
|
+
* client can verify yet), and never claims an attestation would clear it.
|
|
629
|
+
*/
|
|
630
|
+
export declare function gitvaultLossWarningMessage(trip: GitvaultLossWarningTrip): string;
|
|
514
631
|
/** `run402::<org_id>/<project_id>` — what `git-remote-run402` resolves. */
|
|
515
632
|
export declare function gitvaultRemoteUrl(orgId: string, projectId: string): string;
|
|
516
633
|
/** Parse a `run402::<org>/<project>` remote URL. `null` when it is not one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitvault.d.ts","sourceRoot":"","sources":["../../src/namespaces/gitvault.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,kCAAkC,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AAC5G,OAAO,KAAK,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC7I,OAAO,KAAK,EACV,wBAAwB,EACxB,+BAA+B,EAC/B,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,OAAO,KAAK,EAAE,qBAAqB,EAAuB,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACzH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"gitvault.d.ts","sourceRoot":"","sources":["../../src/namespaces/gitvault.ts"],"names":[],"mappings":"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"}
|
|
@@ -170,6 +170,56 @@ export class Gitvault {
|
|
|
170
170
|
});
|
|
171
171
|
return { repo_id: repoId, keystore, transport, vault };
|
|
172
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Open a vault, allocating it first when it does not exist yet (D2 — lazy
|
|
175
|
+
* allocation on first push).
|
|
176
|
+
*
|
|
177
|
+
* This is the ONE primitive the remote helper and the capture lane
|
|
178
|
+
* (`run402 gitvault push`/`snapshot`) drive so that a push against an
|
|
179
|
+
* unallocated project runs the six-stage creation journal inline instead of
|
|
180
|
+
* refusing: it resolves `repo_id` from `project_id` exactly like
|
|
181
|
+
* {@link open}, and when that resolution fails, tries to create the vault —
|
|
182
|
+
* but ONLY when `org_id` was supplied. Without `org_id` this method is
|
|
183
|
+
* byte-identical to `open()`: the original resolution failure is rethrown
|
|
184
|
+
* unchanged, so every existing caller of `open()` that has no reason to
|
|
185
|
+
* create anything sees no behavior change at all by switching to this.
|
|
186
|
+
*
|
|
187
|
+
* RESUMABILITY (client-surface spec, D2): before starting a fresh creation
|
|
188
|
+
* attempt this looks for an INCOMPLETE local journal already matching this
|
|
189
|
+
* exact `(org_id, project_id)` and resumes ITS `client_creation_id`, rather
|
|
190
|
+
* than starting a second competing attempt every time the process is
|
|
191
|
+
* interrupted mid-creation. Kill the process after ALLOCATED and call this
|
|
192
|
+
* again: the same journal — not a new one — drives to ACTIVE, and exactly
|
|
193
|
+
* one vault exists either way. An explicit `client_creation_id` (tests, or
|
|
194
|
+
* a caller resuming a specific attempt by hand) always wins over that search.
|
|
195
|
+
*/
|
|
196
|
+
async openOrCreate(options) {
|
|
197
|
+
if (!options.repo_id && !options.project_id) {
|
|
198
|
+
throw new LocalError("pass repo_id, or project_id to resolve it from the control plane", "opening the gitvault", { code: "GITVAULT_VAULT_UNRESOLVED" });
|
|
199
|
+
}
|
|
200
|
+
// An explicit repo_id addresses the vault directly — there is nothing to
|
|
201
|
+
// resolve or lazily create from an id alone, so this degrades to a plain
|
|
202
|
+
// open (matches `open()`'s own precedence: repo_id always wins).
|
|
203
|
+
if (options.repo_id) {
|
|
204
|
+
const handle = await this.open(options);
|
|
205
|
+
return { handle, found: true, created: null, terminal_loss_statement: GITVAULT_TERMINAL_LOSS_STATEMENT };
|
|
206
|
+
}
|
|
207
|
+
const [{ createGitvaultHttpTransport }, { GitvaultKeystore }, { openOrCreateGitvault }] = await Promise.all([this.#publication(), this.#keystore(), this.#openOrCreate()]);
|
|
208
|
+
const keystore = new GitvaultKeystore(options.keystore_root !== undefined ? { rootDir: options.keystore_root } : {});
|
|
209
|
+
const transport = createGitvaultHttpTransport(this.#client);
|
|
210
|
+
const result = await openOrCreateGitvault({
|
|
211
|
+
keystore,
|
|
212
|
+
transport,
|
|
213
|
+
project_id: options.project_id,
|
|
214
|
+
...(options.org_id !== undefined ? { org_id: options.org_id } : {}),
|
|
215
|
+
...(options.client_creation_id !== undefined ? { client_creation_id: options.client_creation_id } : {}),
|
|
216
|
+
...(options.service_public_key !== undefined ? { service_public_key: options.service_public_key } : {}),
|
|
217
|
+
});
|
|
218
|
+
const handle = await this.open({ ...options, repo_id: result.repo_id });
|
|
219
|
+
return result.found
|
|
220
|
+
? { handle, found: true, created: null, terminal_loss_statement: GITVAULT_TERMINAL_LOSS_STATEMENT }
|
|
221
|
+
: { handle, found: false, created: result.created, terminal_loss_statement: GITVAULT_TERMINAL_LOSS_STATEMENT };
|
|
222
|
+
}
|
|
173
223
|
/**
|
|
174
224
|
* Create the vault for a project and scaffold the git remote.
|
|
175
225
|
*
|
|
@@ -214,16 +264,27 @@ export class Gitvault {
|
|
|
214
264
|
};
|
|
215
265
|
}
|
|
216
266
|
/**
|
|
217
|
-
* Add the
|
|
267
|
+
* Add the run402 git remote, initialising the repository if absent.
|
|
218
268
|
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
269
|
+
* D1 — claim `origin` additively. LLM muscle memory is `git push origin
|
|
270
|
+
* main` from a billion training examples, and a side-remote name costs
|
|
271
|
+
* every agent a correction cycle, so when the repository has no `origin`
|
|
272
|
+
* remote ours BECOMES `origin`. An existing `origin` is NEVER modified or
|
|
273
|
+
* reclaimed — no matter what it points at, including a prior run of this
|
|
274
|
+
* exact call — so the fallback is `run402`, and when THAT is also taken by
|
|
275
|
+
* something else, nothing is added at all: the additive discipline holds
|
|
276
|
+
* for every remote name this method ever touches, not just `origin`.
|
|
277
|
+
*
|
|
278
|
+
* An explicit `remote_name` is a caller override (no current caller passes
|
|
279
|
+
* one) and skips the origin/run402 dance entirely — the caller already
|
|
280
|
+
* decided the name; this method still never modifies an existing remote
|
|
281
|
+
* under it.
|
|
282
|
+
*
|
|
283
|
+
* No key material or allocation is required — the cold-start path gains no
|
|
284
|
+
* prompts or network dependencies from this.
|
|
223
285
|
*/
|
|
224
286
|
async scaffoldRemote(options) {
|
|
225
287
|
const { hardenedGit } = await this.#snapshot();
|
|
226
|
-
const name = options.remote_name ?? "run402";
|
|
227
288
|
const url = options.remote_url ?? gitvaultRemoteUrl(options.org_id, options.project_id);
|
|
228
289
|
let createdRepository = false;
|
|
229
290
|
try {
|
|
@@ -233,17 +294,67 @@ export class Gitvault {
|
|
|
233
294
|
await hardenedGit(options.repo_dir, ["init"]);
|
|
234
295
|
createdRepository = true;
|
|
235
296
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
297
|
+
const readRemote = async (name) => {
|
|
298
|
+
try {
|
|
299
|
+
const out = (await hardenedGit(options.repo_dir, ["remote", "get-url", name])).text().trim();
|
|
300
|
+
return out.length > 0 ? out : null;
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const add = async (name) => {
|
|
307
|
+
await hardenedGit(options.repo_dir, ["remote", "add", name, url]);
|
|
308
|
+
};
|
|
309
|
+
if (options.remote_name) {
|
|
310
|
+
const name = options.remote_name;
|
|
311
|
+
const existing = await readRemote(name);
|
|
312
|
+
if (existing) {
|
|
313
|
+
return {
|
|
314
|
+
name,
|
|
315
|
+
url,
|
|
316
|
+
created_repository: createdRepository,
|
|
317
|
+
already_present: true,
|
|
318
|
+
existing_url: existing,
|
|
319
|
+
reason: existing === url ? `'${name}' already points here — nothing to add` : `'${name}' points at ${existing} — left unchanged, nothing was added`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
await add(name);
|
|
323
|
+
return { name, url, created_repository: createdRepository, already_present: false, existing_url: null, reason: `no existing '${name}' remote — added` };
|
|
239
324
|
}
|
|
240
|
-
|
|
241
|
-
|
|
325
|
+
// D1: claim `origin` when it is free.
|
|
326
|
+
const existingOrigin = await readRemote("origin");
|
|
327
|
+
if (!existingOrigin) {
|
|
328
|
+
await add("origin");
|
|
329
|
+
return { name: "origin", url, created_repository: createdRepository, already_present: false, existing_url: null, reason: "no existing 'origin' remote — claimed it" };
|
|
330
|
+
}
|
|
331
|
+
if (existingOrigin === url) {
|
|
332
|
+
// Idempotent: a prior scaffold already claimed `origin` for this exact vault.
|
|
333
|
+
return { name: "origin", url, created_repository: createdRepository, already_present: true, existing_url: existingOrigin, reason: "'origin' already points here — nothing to add" };
|
|
334
|
+
}
|
|
335
|
+
// `origin` is taken by something else — never touched. Fall back to `run402`.
|
|
336
|
+
const existingRun402 = await readRemote("run402");
|
|
337
|
+
if (existingRun402) {
|
|
338
|
+
return {
|
|
339
|
+
name: "run402",
|
|
340
|
+
url,
|
|
341
|
+
created_repository: createdRepository,
|
|
342
|
+
already_present: true,
|
|
343
|
+
existing_url: existingRun402,
|
|
344
|
+
reason: existingRun402 === url
|
|
345
|
+
? `'origin' points at ${existingOrigin} — 'run402' already points here, nothing to add`
|
|
346
|
+
: `'origin' points at ${existingOrigin}; 'run402' points at ${existingRun402} — neither remote was touched`,
|
|
347
|
+
};
|
|
242
348
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
349
|
+
await add("run402");
|
|
350
|
+
return {
|
|
351
|
+
name: "run402",
|
|
352
|
+
url,
|
|
353
|
+
created_repository: createdRepository,
|
|
354
|
+
already_present: false,
|
|
355
|
+
existing_url: null,
|
|
356
|
+
reason: `'origin' points at ${existingOrigin} — added as 'run402' instead`,
|
|
357
|
+
};
|
|
247
358
|
}
|
|
248
359
|
/**
|
|
249
360
|
* What this machine and the control plane each believe about the vault.
|
|
@@ -308,6 +419,16 @@ export class Gitvault {
|
|
|
308
419
|
if (record?.gitvault_policy === "grandfathered") {
|
|
309
420
|
warnings.push({ kind: "policy_grandfathered", message: "activation does not require vault admission on this project; return it to `required` when the migration is done" });
|
|
310
421
|
}
|
|
422
|
+
// D7 (repo-first-onramp task 2.7): a vault that has accrued enough value
|
|
423
|
+
// at risk gets a STANDING warning instead of the one-time genesis note.
|
|
424
|
+
// `record` is `null` for an unallocated project, which is the ordinary
|
|
425
|
+
// "nothing to warn about" shape, not a gap in this check.
|
|
426
|
+
if (record) {
|
|
427
|
+
const trip = gitvaultLossWarningTrip(record);
|
|
428
|
+
if (gitvaultLossWarningTripped(trip)) {
|
|
429
|
+
warnings.push({ kind: "terminal_loss_risk", message: gitvaultLossWarningMessage(trip) });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
311
432
|
// The local git remote, when there is a repository to read it from. A
|
|
312
433
|
// pure read: `status` must never write git configuration.
|
|
313
434
|
let remote = null;
|
|
@@ -419,7 +540,10 @@ export class Gitvault {
|
|
|
419
540
|
*/
|
|
420
541
|
async push(options) {
|
|
421
542
|
const [{ deployRefTransaction }, { captureSnapshot, gitvaultCommitLine }] = await Promise.all([this.#publication(), this.#snapshot()]);
|
|
422
|
-
const
|
|
543
|
+
const opened = await this.openOrCreate(options);
|
|
544
|
+
if (!opened.found && opened.created)
|
|
545
|
+
await options.onVaultCreated?.(opened.created);
|
|
546
|
+
const handle = opened.handle;
|
|
423
547
|
const repoDir = options.repo_dir ?? process.cwd();
|
|
424
548
|
const snapshot = await captureSnapshot({ dir: repoDir, ...(options.snapshot ?? {}) });
|
|
425
549
|
const line = gitvaultCommitLine(snapshot);
|
|
@@ -766,6 +890,73 @@ export class Gitvault {
|
|
|
766
890
|
#prune() {
|
|
767
891
|
return nodeOnly(() => import("../node/gitvault-prune.js"), "prune");
|
|
768
892
|
}
|
|
893
|
+
#openOrCreate() {
|
|
894
|
+
return nodeOnly(() => import("../node/gitvault-open-or-create.js"), "openOrCreate");
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
// ─── D7 — progressive terminal-loss warning (repo-first-onramp task 2.7) ────
|
|
898
|
+
//
|
|
899
|
+
// The §0 terminal-loss statement (`GITVAULT_TERMINAL_LOSS_STATEMENT`) never
|
|
900
|
+
// changes — this governs only PROMINENCE and CADENCE. A quiet stderr line
|
|
901
|
+
// already runs at genesis (the one-shot receipt path in `push`/`openOrCreate`
|
|
902
|
+
// callers). This is the OTHER half: once the vault has accrued enough value
|
|
903
|
+
// at risk, `status`/`doctor` carry a STANDING warning instead of a one-time
|
|
904
|
+
// note nobody re-reads.
|
|
905
|
+
/**
|
|
906
|
+
* The composite escalation trigger (design D7): ANY of these crossing its
|
|
907
|
+
* threshold escalates the quiet genesis-time note into a standing warning.
|
|
908
|
+
* Deliberately an OR — any single metric alone is gameable by triviality
|
|
909
|
+
* (an agent that pads one dimension to stay under a lone threshold). Shipped
|
|
910
|
+
* as defaults; tunable in this ONE place, not a protocol contract.
|
|
911
|
+
*/
|
|
912
|
+
export const GITVAULT_LOSS_WARNING_THRESHOLDS = {
|
|
913
|
+
generations: 10,
|
|
914
|
+
source_bytes: 10 * 1024 * 1024,
|
|
915
|
+
days_since_genesis: 14,
|
|
916
|
+
};
|
|
917
|
+
/**
|
|
918
|
+
* D7: has this vault crossed the composite terminal-loss escalation trigger?
|
|
919
|
+
* Pure — no I/O, no clock dependency beyond the optional `now` override
|
|
920
|
+
* (tests). `admitted_generations` and `storage.source_bytes` are decimal
|
|
921
|
+
* strings (protocol convention for values that could exceed safe-integer
|
|
922
|
+
* precision in principle; comfortably within it here).
|
|
923
|
+
*
|
|
924
|
+
* There is deliberately no companion "is this resolved" function: V0-A
|
|
925
|
+
* cannot detect a second principal or human envelope able to open the vault
|
|
926
|
+
* (design D7's stricter-than-drafted resolution), so once tripped this has
|
|
927
|
+
* nothing further to compute — a caller does not un-trip it, ever, in V0.
|
|
928
|
+
*/
|
|
929
|
+
export function gitvaultLossWarningTrip(record, now = new Date()) {
|
|
930
|
+
const generations = Number(record.admitted_generations ?? "0");
|
|
931
|
+
const sourceBytes = Number(record.storage?.source_bytes ?? "0");
|
|
932
|
+
const genesisAt = record.genesis_admitted_at ? new Date(record.genesis_admitted_at) : null;
|
|
933
|
+
const daysSinceGenesis = genesisAt && !Number.isNaN(genesisAt.getTime()) ? (now.getTime() - genesisAt.getTime()) / 86_400_000 : null;
|
|
934
|
+
return {
|
|
935
|
+
generations: Number.isFinite(generations) && generations >= GITVAULT_LOSS_WARNING_THRESHOLDS.generations,
|
|
936
|
+
source_bytes: Number.isFinite(sourceBytes) && sourceBytes >= GITVAULT_LOSS_WARNING_THRESHOLDS.source_bytes,
|
|
937
|
+
days_since_genesis: daysSinceGenesis !== null && daysSinceGenesis >= GITVAULT_LOSS_WARNING_THRESHOLDS.days_since_genesis,
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
/** Any composite metric tripped — the standing warning threshold itself. */
|
|
941
|
+
export function gitvaultLossWarningTripped(trip) {
|
|
942
|
+
return trip.generations || trip.source_bytes || trip.days_since_genesis;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* The standing warning text (design D7): names what tripped, states the
|
|
946
|
+
* resolution honestly (a second principal or human envelope — nothing this
|
|
947
|
+
* client can verify yet), and never claims an attestation would clear it.
|
|
948
|
+
*/
|
|
949
|
+
export function gitvaultLossWarningMessage(trip) {
|
|
950
|
+
const reasons = [];
|
|
951
|
+
if (trip.generations)
|
|
952
|
+
reasons.push(`≥${GITVAULT_LOSS_WARNING_THRESHOLDS.generations} generations`);
|
|
953
|
+
if (trip.source_bytes)
|
|
954
|
+
reasons.push(`≥${Math.round(GITVAULT_LOSS_WARNING_THRESHOLDS.source_bytes / (1024 * 1024))} MB of source`);
|
|
955
|
+
if (trip.days_since_genesis)
|
|
956
|
+
reasons.push(`≥${GITVAULT_LOSS_WARNING_THRESHOLDS.days_since_genesis} days since genesis`);
|
|
957
|
+
return (`this vault has accrued real value at risk (${reasons.join(", ")}) while only one principal can open it. ` +
|
|
958
|
+
"Only a second principal — another keystore, or later a human envelope — demonstrably able to open the vault clears this warning; " +
|
|
959
|
+
"this client cannot verify that yet, so it stands until you add one. No attestation or flag clears it.");
|
|
769
960
|
}
|
|
770
961
|
/** `run402::<org_id>/<project_id>` — what `git-remote-run402` resolves. */
|
|
771
962
|
export function gitvaultRemoteUrl(orgId, projectId) {
|