run402 4.66.1 → 4.67.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 +4 -2
- package/gitvault-surface.json +10 -2
- package/lib/cold-start.mjs +77 -0
- package/lib/command-manifest.mjs +6 -1
- package/lib/doctor.mjs +10 -0
- package/lib/gitvault-capabilities.mjs +12 -0
- package/lib/org-context.mjs +26 -0
- package/lib/path-lookup.mjs +24 -0
- package/lib/path-lookup.test.mjs +66 -0
- package/lib/repos.mjs +307 -10
- package/lib/rooms-context.mjs +17 -1
- 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/namespaces/gitvault.d.ts +131 -4
- package/sdk/dist/namespaces/gitvault.d.ts.map +1 -1
- package/sdk/dist/namespaces/gitvault.js +268 -8
- package/sdk/dist/namespaces/gitvault.js.map +1 -1
- package/sdk/dist/node/gitvault-address.d.ts +2 -0
- package/sdk/dist/node/gitvault-address.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-address.js +13 -2
- package/sdk/dist/node/gitvault-address.js.map +1 -1
- package/sdk/dist/node/gitvault-handoff.d.ts +111 -0
- package/sdk/dist/node/gitvault-handoff.d.ts.map +1 -0
- package/sdk/dist/node/gitvault-handoff.js +277 -0
- package/sdk/dist/node/gitvault-handoff.js.map +1 -0
- package/sdk/dist/node/gitvault-keystore.d.ts +1 -1
- package/sdk/dist/node/gitvault-keystore.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-restore.d.ts +46 -0
- package/sdk/dist/node/gitvault-restore.d.ts.map +1 -0
- package/sdk/dist/node/gitvault-restore.js +123 -0
- package/sdk/dist/node/gitvault-restore.js.map +1 -0
- package/sdk/dist/node/gitvault-snapshot.d.ts +87 -0
- package/sdk/dist/node/gitvault-snapshot.d.ts.map +1 -1
- package/sdk/dist/node/gitvault-snapshot.js +216 -11
- package/sdk/dist/node/gitvault-snapshot.js.map +1 -1
- package/sdk/dist/node/index.d.ts +6 -2
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +8 -1
- package/sdk/dist/node/index.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitvault-handoff.d.ts","sourceRoot":"","sources":["../../src/node/gitvault-handoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gitvault — the Handoff Key (kygit-handoff design D3/D6/D10).
|
|
3
|
+
*
|
|
4
|
+
* A Handoff Key is a bearer bridge, never a K_repo derivation of its own:
|
|
5
|
+
* `kgh1_<base64url(handoff_id[16] || master_secret[32])>` (69 chars). Two
|
|
6
|
+
* HKDF-SHA-256 derivations off `master_secret` (salt = the 16 raw
|
|
7
|
+
* `handoff_id` bytes) produce `auth_secret` (what the gateway hashes and
|
|
8
|
+
* compares) and `wrap_key` (what seals/opens the small envelope carrying
|
|
9
|
+
* the vault's epoch key `k_e` directly — the gateway never sees either).
|
|
10
|
+
*
|
|
11
|
+
* The prefix is a REGISTRY (design D9 rule 4): `kgh1_` is the first row.
|
|
12
|
+
* `parseHandoffKey` refuses any other recognized-shape-but-wrong-kind
|
|
13
|
+
* prefix BY NAME, pointing at its own verb, rather than misreading it as a
|
|
14
|
+
* malformed handoff key.
|
|
15
|
+
*
|
|
16
|
+
* Reuses ONLY existing primitives — `jcs`/HKDF/HMAC/SHA-256 from
|
|
17
|
+
* `@noble/hashes`, the SAME `_gitvaultAeadBackend()` XChaCha20-Poly1305
|
|
18
|
+
* seam `sealFrame`/`openFrame` use — never a second crypto path. The wire
|
|
19
|
+
* envelope here is a DIFFERENT, smaller frame than `r402s/v0`'s seven-member
|
|
20
|
+
* object frame (design D3: "the sealed envelope lives in the gateway ROW,
|
|
21
|
+
* never in the vault object store — the frozen r402s/v0 protocol is
|
|
22
|
+
* untouched"), so it gets its own tiny header/AAD rather than reusing
|
|
23
|
+
* `frameAad`'s object-store-shaped seven fields.
|
|
24
|
+
*/
|
|
25
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
26
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
27
|
+
import { concatBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
28
|
+
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
29
|
+
import { LocalError } from "../errors.js";
|
|
30
|
+
import { _gitvaultAeadBackend, fromBase64url, randomBytes, sha256Hex, toBase64url } from "../namespaces/gitvault.crypto.js";
|
|
31
|
+
function fail(code, message, context, details) {
|
|
32
|
+
throw new LocalError(message, context, { code, details });
|
|
33
|
+
}
|
|
34
|
+
/** `kgh1_` is the first row. A future `kgi1_` (KyGit Invite) is a SIBLING row here, never a branch on this one's parser. */
|
|
35
|
+
export const HANDOFF_KEY_PREFIXES = [{ prefix: "kgh1_", kind: "handoff", verb: "resume" }];
|
|
36
|
+
const HANDOFF_ID_BYTES = 16;
|
|
37
|
+
const MASTER_SECRET_BYTES = 32;
|
|
38
|
+
const HANDOFF_KEY_BODY_BYTES = HANDOFF_ID_BYTES + MASTER_SECRET_BYTES;
|
|
39
|
+
function bytesToUuid(bytes) {
|
|
40
|
+
const h = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
41
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
42
|
+
}
|
|
43
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
44
|
+
export function uuidToBytes(uuid, field = "handoff_id") {
|
|
45
|
+
if (!UUID_RE.test(uuid))
|
|
46
|
+
fail("HANDOFF_ID_INVALID", `${field} is not a canonical UUID`, "parsing handoff id", { field });
|
|
47
|
+
const hex = uuid.replace(/-/g, "").toLowerCase();
|
|
48
|
+
const out = new Uint8Array(16);
|
|
49
|
+
for (let i = 0; i < 16; i++)
|
|
50
|
+
out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Assemble the printed key from a fresh 32-byte master secret and the
|
|
55
|
+
* gateway-minted `handoff_id`. The gateway never sees `master_secret` — the
|
|
56
|
+
* caller derives `auth_hash` (via {@link deriveHandoffSecrets}) and sends
|
|
57
|
+
* ONLY that.
|
|
58
|
+
*/
|
|
59
|
+
export function assembleHandoffKey(handoffId, masterSecret = randomBytes(MASTER_SECRET_BYTES)) {
|
|
60
|
+
if (masterSecret.length !== MASTER_SECRET_BYTES)
|
|
61
|
+
fail("HANDOFF_KEY_INVALID", "master_secret must be 32 bytes", "assembling handoff key");
|
|
62
|
+
const idBytes = uuidToBytes(handoffId);
|
|
63
|
+
const body = concatBytes(idBytes, masterSecret);
|
|
64
|
+
return { key: `kgh1_${toBase64url(body)}`, handoff_id_bytes: idBytes, master_secret: masterSecret };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parse ANY `kg**_` handoff-family key by its prefix registry. A recognized
|
|
68
|
+
* prefix of a DIFFERENT kind (a future `kgi1_` invite key handed to
|
|
69
|
+
* `resume`) refuses BY NAME pointing at its own verb — never misread as a
|
|
70
|
+
* malformed handoff key (design D9 rule 4).
|
|
71
|
+
*/
|
|
72
|
+
export function parseHandoffKey(raw) {
|
|
73
|
+
const trimmed = raw.trim();
|
|
74
|
+
const entry = HANDOFF_KEY_PREFIXES.find((e) => trimmed.startsWith(e.prefix));
|
|
75
|
+
if (!entry) {
|
|
76
|
+
// A recognized SIBLING prefix (future kind) would be matched here once
|
|
77
|
+
// it joins the registry; today only `kgh1_` is registered, so any
|
|
78
|
+
// non-matching prefix is a plain invalid key.
|
|
79
|
+
fail("HANDOFF_KEY_INVALID", "not a recognized kygit key (expected a key starting kgh1_)", "parsing handoff key");
|
|
80
|
+
}
|
|
81
|
+
if (entry.kind !== "handoff") {
|
|
82
|
+
fail("HANDOFF_KEY_WRONG_KIND", `this key is a ${entry.kind} key — use \`kygit ${entry.verb}\` instead of resume`, "parsing handoff key", { kind: entry.kind, verb: entry.verb });
|
|
83
|
+
}
|
|
84
|
+
const body = trimmed.slice(entry.prefix.length);
|
|
85
|
+
let bytes;
|
|
86
|
+
try {
|
|
87
|
+
bytes = fromBase64url(body, "handoff key body");
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
fail("HANDOFF_KEY_INVALID", "the key body is not valid base64url", "parsing handoff key");
|
|
91
|
+
}
|
|
92
|
+
if (bytes.length !== HANDOFF_KEY_BODY_BYTES) {
|
|
93
|
+
fail("HANDOFF_KEY_INVALID", `the key decodes to ${bytes.length} bytes; expected ${HANDOFF_KEY_BODY_BYTES}`, "parsing handoff key");
|
|
94
|
+
}
|
|
95
|
+
const idBytes = bytes.subarray(0, HANDOFF_ID_BYTES);
|
|
96
|
+
const masterSecret = bytes.subarray(HANDOFF_ID_BYTES);
|
|
97
|
+
return { kind: "handoff", handoff_id_bytes: idBytes, handoff_id: bytesToUuid(idBytes), master_secret: masterSecret };
|
|
98
|
+
}
|
|
99
|
+
// ─── HKDF derivations (design D3) ────────────────────────────────────────────
|
|
100
|
+
const HANDOFF_AUTH_INFO = "kygit/handoff/auth/v1";
|
|
101
|
+
const HANDOFF_WRAP_INFO = "kygit/handoff/wrap/v1";
|
|
102
|
+
const HANDOFF_AUTH_HASH_LABEL = "kygit/handoff/auth-hash/v1";
|
|
103
|
+
/** `HKDF-SHA256(ikm=master_secret, salt=handoff_id[16], info=…)` per D3, for both `auth_secret` and `wrap_key`. */
|
|
104
|
+
export function deriveHandoffSecrets(handoffIdBytes, masterSecret) {
|
|
105
|
+
const authSecret = hkdf(sha256, masterSecret, handoffIdBytes, utf8ToBytes(HANDOFF_AUTH_INFO), 32);
|
|
106
|
+
const wrapKey = hkdf(sha256, masterSecret, handoffIdBytes, utf8ToBytes(HANDOFF_WRAP_INFO), 32);
|
|
107
|
+
const authHash = sha256(concatBytes(utf8ToBytes(HANDOFF_AUTH_HASH_LABEL), authSecret));
|
|
108
|
+
return { auth_secret: authSecret, wrap_key: wrapKey, auth_hash_hex: sha256Hex(authHash) };
|
|
109
|
+
}
|
|
110
|
+
/** Frame tag for this envelope format — DISTINCT from `r402s/v0`'s `"R402S0"` object frame (design D3: never stored as a vault object). */
|
|
111
|
+
export const HANDOFF_ENVELOPE_KIND = "kygit-handoff-envelope-v1";
|
|
112
|
+
const HANDOFF_FRAME_MAGIC = "KGH1";
|
|
113
|
+
const HANDOFF_FRAME_MAGIC_BYTES = 4;
|
|
114
|
+
const HANDOFF_FRAME_VERSION_BYTE = 0x01;
|
|
115
|
+
const HANDOFF_NONCE_BYTES = 24;
|
|
116
|
+
const HANDOFF_FRAME_HEADER_BYTES = HANDOFF_FRAME_MAGIC_BYTES + 1 + HANDOFF_NONCE_BYTES;
|
|
117
|
+
function handoffAeadSeal(key32, nonce24, aad, plaintext) {
|
|
118
|
+
const backend = _gitvaultAeadBackend();
|
|
119
|
+
if (backend)
|
|
120
|
+
return backend.seal(key32, nonce24, aad, plaintext);
|
|
121
|
+
return xchacha20poly1305(key32, nonce24, aad).encrypt(plaintext);
|
|
122
|
+
}
|
|
123
|
+
function handoffAeadOpen(key32, nonce24, aad, ctAndTag) {
|
|
124
|
+
try {
|
|
125
|
+
const backend = _gitvaultAeadBackend();
|
|
126
|
+
if (backend)
|
|
127
|
+
return backend.open(key32, nonce24, aad, ctAndTag);
|
|
128
|
+
return xchacha20poly1305(key32, nonce24, aad).decrypt(ctAndTag);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** AAD = `handoff_id[16] ‖ kind` (design D3) — `kind` is this envelope format's own tag, UTF-8. */
|
|
135
|
+
function handoffEnvelopeAad(handoffIdBytes, envelopeKind) {
|
|
136
|
+
return concatBytes(handoffIdBytes, utf8ToBytes(envelopeKind));
|
|
137
|
+
}
|
|
138
|
+
/** Seal the handoff payload under `wrap_key`. Returns the base64url wire form + its declared kind tag. */
|
|
139
|
+
export function sealHandoffEnvelope(handoffIdBytes, wrapKey, payload, nonce) {
|
|
140
|
+
// Plain JSON, NOT the r402s/v0 no-JSON-numbers JCS profile: this envelope
|
|
141
|
+
// is never a vault object and only this SDK ever encodes/decodes it, so
|
|
142
|
+
// it needs deterministic round-tripping, not cross-implementation
|
|
143
|
+
// byte-canonical determinism (design D3's "the frozen protocol is
|
|
144
|
+
// untouched" — reusing the object-frame profile here would be exactly
|
|
145
|
+
// the kind of accidental protocol coupling that note warns against).
|
|
146
|
+
const plaintext = utf8ToBytes(JSON.stringify(payload));
|
|
147
|
+
const n = nonce ?? randomBytes(HANDOFF_NONCE_BYTES);
|
|
148
|
+
if (n.length !== HANDOFF_NONCE_BYTES)
|
|
149
|
+
fail("HANDOFF_ENVELOPE_INVALID", "nonce must be 24 bytes", "sealing handoff envelope");
|
|
150
|
+
const aad = handoffEnvelopeAad(handoffIdBytes, HANDOFF_ENVELOPE_KIND);
|
|
151
|
+
const ct = handoffAeadSeal(wrapKey, n, aad, plaintext);
|
|
152
|
+
const frame = concatBytes(utf8ToBytes(HANDOFF_FRAME_MAGIC), new Uint8Array([HANDOFF_FRAME_VERSION_BYTE]), n, ct);
|
|
153
|
+
return { sealed_envelope: toBase64url(frame), envelope_kind: HANDOFF_ENVELOPE_KIND };
|
|
154
|
+
}
|
|
155
|
+
/** Open a sealed handoff envelope under `wrap_key`. Throws `HANDOFF_ENVELOPE_INVALID` on any header mismatch and `HANDOFF_AEAD_AUTH_FAILURE` on a bad key/AAD/ciphertext. */
|
|
156
|
+
export function openHandoffEnvelope(handoffIdBytes, wrapKey, sealedEnvelopeB64u, envelopeKind = HANDOFF_ENVELOPE_KIND) {
|
|
157
|
+
let frame;
|
|
158
|
+
try {
|
|
159
|
+
frame = fromBase64url(sealedEnvelopeB64u, "sealed_envelope");
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
fail("HANDOFF_ENVELOPE_INVALID", "sealed_envelope is not valid base64url", "opening handoff envelope");
|
|
163
|
+
}
|
|
164
|
+
if (frame.length < HANDOFF_FRAME_HEADER_BYTES + 16) {
|
|
165
|
+
fail("HANDOFF_ENVELOPE_INVALID", "sealed_envelope is shorter than header + AEAD tag", "opening handoff envelope");
|
|
166
|
+
}
|
|
167
|
+
const magic = new TextDecoder().decode(frame.subarray(0, HANDOFF_FRAME_MAGIC_BYTES));
|
|
168
|
+
if (magic !== HANDOFF_FRAME_MAGIC || frame[HANDOFF_FRAME_MAGIC_BYTES] !== HANDOFF_FRAME_VERSION_BYTE) {
|
|
169
|
+
fail("HANDOFF_ENVELOPE_INVALID", "sealed_envelope header magic/version mismatch", "opening handoff envelope");
|
|
170
|
+
}
|
|
171
|
+
const nonce = frame.subarray(HANDOFF_FRAME_MAGIC_BYTES + 1, HANDOFF_FRAME_HEADER_BYTES);
|
|
172
|
+
const ct = frame.subarray(HANDOFF_FRAME_HEADER_BYTES);
|
|
173
|
+
const aad = handoffEnvelopeAad(handoffIdBytes, envelopeKind);
|
|
174
|
+
const opened = handoffAeadOpen(wrapKey, nonce, aad, ct);
|
|
175
|
+
if (opened === null)
|
|
176
|
+
fail("HANDOFF_AEAD_AUTH_FAILURE", "the sealed envelope failed AEAD authentication under this key", "opening handoff envelope");
|
|
177
|
+
let payload;
|
|
178
|
+
try {
|
|
179
|
+
payload = JSON.parse(new TextDecoder().decode(opened));
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
fail("HANDOFF_ENVELOPE_INVALID", "opened envelope is not valid JSON", "opening handoff envelope");
|
|
183
|
+
}
|
|
184
|
+
const p = payload;
|
|
185
|
+
if (p.v !== 1 || p.kind !== "handoff" || typeof p.repo_id !== "string" || typeof p.epoch !== "string" || typeof p.k_e_hex !== "string" || !p.checkpoint || p.note_schema !== "kygit.handoff-note.v1") {
|
|
186
|
+
fail("HANDOFF_ENVELOPE_INVALID", "opened envelope does not match the kygit.handoff-note.v1 payload shape", "opening handoff envelope");
|
|
187
|
+
}
|
|
188
|
+
return p;
|
|
189
|
+
}
|
|
190
|
+
export function isKygitHandoffNote(value) {
|
|
191
|
+
if (!value || typeof value !== "object")
|
|
192
|
+
return false;
|
|
193
|
+
const v = value;
|
|
194
|
+
return v.schema === "kygit.handoff-note.v1" && typeof v.summary === "string" && typeof v.created_at === "string" && !!v.from && !!v.capture;
|
|
195
|
+
}
|
|
196
|
+
// ─── Client-side secret scan (design D10 — no override flag) ────────────────
|
|
197
|
+
const HANDOFF_NOTE_SECRET_PREFIXES = [
|
|
198
|
+
/\bsk-[A-Za-z0-9]/,
|
|
199
|
+
/\bghp_[A-Za-z0-9]/,
|
|
200
|
+
/\bgho_[A-Za-z0-9]/,
|
|
201
|
+
/\bxox[abp]-[A-Za-z0-9]/,
|
|
202
|
+
/\bAKIA[A-Z0-9]{4,}/,
|
|
203
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
204
|
+
/-----BEGIN [A-Z ]*CERTIFICATE-----/,
|
|
205
|
+
/\bkgh1_[A-Za-z0-9_-]/,
|
|
206
|
+
];
|
|
207
|
+
/** Shannon entropy in bits/char over `s`. */
|
|
208
|
+
function shannonEntropy(s) {
|
|
209
|
+
const counts = new Map();
|
|
210
|
+
for (const ch of s)
|
|
211
|
+
counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
212
|
+
let entropy = 0;
|
|
213
|
+
for (const count of counts.values()) {
|
|
214
|
+
const p = count / s.length;
|
|
215
|
+
entropy -= p * Math.log2(p);
|
|
216
|
+
}
|
|
217
|
+
return entropy;
|
|
218
|
+
}
|
|
219
|
+
/** A run of ≥32 token-ish chars (letters/digits/`+/=_-`) with high per-char entropy reads as a bare secret, not prose. */
|
|
220
|
+
function hasHighEntropyToken(text) {
|
|
221
|
+
const tokenRe = /[A-Za-z0-9+/_=-]{32,}/g;
|
|
222
|
+
let m;
|
|
223
|
+
while ((m = tokenRe.exec(text))) {
|
|
224
|
+
const token = m[0];
|
|
225
|
+
if (shannonEntropy(token) >= 3.5)
|
|
226
|
+
return token;
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
/** Every string leaf in the note, `path` = dotted field name for the refusal. */
|
|
231
|
+
function* noteStringLeaves(note) {
|
|
232
|
+
yield { path: "summary", text: note.summary };
|
|
233
|
+
for (const [group, arr] of [
|
|
234
|
+
["completed", note.completed],
|
|
235
|
+
["in_progress", note.in_progress],
|
|
236
|
+
["failing", note.failing],
|
|
237
|
+
["tried", note.tried],
|
|
238
|
+
["next_steps", note.next_steps],
|
|
239
|
+
["decisions", note.decisions],
|
|
240
|
+
["open_questions", note.open_questions],
|
|
241
|
+
]) {
|
|
242
|
+
for (const [i, text] of (arr ?? []).entries())
|
|
243
|
+
yield { path: `${group}[${i}]`, text };
|
|
244
|
+
}
|
|
245
|
+
if (note.commands) {
|
|
246
|
+
for (const key of ["test", "build", "run"]) {
|
|
247
|
+
const v = note.commands[key];
|
|
248
|
+
if (v)
|
|
249
|
+
yield { path: `commands.${key}`, text: v };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Refuse a note that carries a bare secret — no override flag exists
|
|
255
|
+
* (design D10): a note is read by another agent, and secrets have the
|
|
256
|
+
* secrets API. `null` when the note is clean.
|
|
257
|
+
*/
|
|
258
|
+
export function scanHandoffNoteForSecrets(note) {
|
|
259
|
+
for (const { path, text } of noteStringLeaves(note)) {
|
|
260
|
+
for (const re of HANDOFF_NOTE_SECRET_PREFIXES) {
|
|
261
|
+
if (re.test(text))
|
|
262
|
+
return { field: path, reason: `matches a known secret prefix (${re.source})` };
|
|
263
|
+
}
|
|
264
|
+
const token = hasHighEntropyToken(text);
|
|
265
|
+
if (token)
|
|
266
|
+
return { field: path, reason: `contains a high-entropy token (${token.length} chars) that reads as a bare secret` };
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
/** Throws `HANDOFF_NOTE_CONTAINS_SECRET` naming the field — call before the handoff commit is written. */
|
|
271
|
+
export function assertHandoffNoteHasNoSecret(note) {
|
|
272
|
+
const finding = scanHandoffNoteForSecrets(note);
|
|
273
|
+
if (finding) {
|
|
274
|
+
fail("HANDOFF_NOTE_CONTAINS_SECRET", `the handoff note's \`${finding.field}\` ${finding.reason} — edit the note; secrets belong in the secrets API, never in a note another agent will read`, "scanning handoff note", { field: finding.field });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=gitvault-handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitvault-handoff.js","sourceRoot":"","sources":["../../src/node/gitvault-handoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -145,7 +145,7 @@ export interface GitvaultRepoFile {
|
|
|
145
145
|
/** The last ref transaction this principal published (5.4 fills it). */
|
|
146
146
|
last_ref_transaction: Record<string, unknown> | null;
|
|
147
147
|
/** How this file came to exist — creation, or a §5.1 restore from the principal's own envelope. */
|
|
148
|
-
provenance: "created" | "restored_from_envelope";
|
|
148
|
+
provenance: "created" | "restored_from_envelope" | "restored_from_handoff";
|
|
149
149
|
updated_at: string;
|
|
150
150
|
}
|
|
151
151
|
/** One `audit.log` line. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitvault-keystore.d.ts","sourceRoot":"","sources":["../../src/node/gitvault-keystore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA0BH,OAAO,KAAK,EACV,yBAAyB,EACzB,mBAAmB,EACnB,uBAAuB,EAEvB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,iCAAiC,CAAC;AAIzC,wGAAwG;AACxG,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,mGAAmG;IACnG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qFAAqF;IACrF,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,2HAA2H;IAC3H,UAAU,EAAE,MAAM,CAAC;IACnB,+KAA+K;IAC/K,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC3C,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,mJAAmJ;IACnJ,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,mHAAmH;IACnH,gBAAgB,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C,iIAAiI;IACjI,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC;;;;;;;;OAQG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACxD;;;;;;;;;;;;;;;;;OAiBG;IACH,kBAAkB,CAAC,EAAE;QAAE,oBAAoB,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,YAAY,EAAE,MAAM,CAAC;YAAC,cAAc,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IACpJ,wEAAwE;IACxE,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACrD,mGAAmG;IACnG,UAAU,EAAE,SAAS,GAAG,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"gitvault-keystore.d.ts","sourceRoot":"","sources":["../../src/node/gitvault-keystore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `git clone --no-checkout <remoteUrl> <targetDir>` — protocol-permitting
|
|
3
|
+
* (this is the one gitvault git invocation allowed to touch the network),
|
|
4
|
+
* hooks and terminal prompts still neutralized. `targetDir` must not
|
|
5
|
+
* already exist (git's own clone precondition).
|
|
6
|
+
*/
|
|
7
|
+
export declare function cloneGitvaultRemote(remoteUrl: string, targetDir: string): Promise<void>;
|
|
8
|
+
export interface GitvaultHandoffRestoreOptions {
|
|
9
|
+
/** The freshly cloned repository. */
|
|
10
|
+
dir: string;
|
|
11
|
+
/** The stash-shaped commit oid (design D1) — must already be reachable in `dir`'s object database (a retention root, materialized by clone). */
|
|
12
|
+
stash_oid: string;
|
|
13
|
+
/**
|
|
14
|
+
* `<stash_oid>`'s first parent (design D1's `base_head_oid`). When
|
|
15
|
+
* omitted it is read directly off the commit (`git rev-parse
|
|
16
|
+
* <stash_oid>^1`) — the object already carries it, so a caller resuming
|
|
17
|
+
* from the sealed envelope's `checkpoint.commit_oid` alone needs no
|
|
18
|
+
* second value to agree with it.
|
|
19
|
+
*/
|
|
20
|
+
base_head_oid?: string;
|
|
21
|
+
/** The vault's default branch name (e.g. from the head symref, stripped of `refs/heads/`). Read from the fresh clone's `HEAD` symref when omitted; falls back to `main`. */
|
|
22
|
+
branch_hint?: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface GitvaultHandoffRestoreResult {
|
|
25
|
+
branch: string;
|
|
26
|
+
base_head_oid: string;
|
|
27
|
+
stash_oid: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check out the base, land on a real branch (never left detached), then
|
|
31
|
+
* `git stash apply --index <stash_oid>` — staged, unstaged, deleted, and
|
|
32
|
+
* untracked changes come back distinctly (verified against real git 2.43
|
|
33
|
+
* plumbing during design). Every step here is LOCAL — no network — so it
|
|
34
|
+
* runs fully hardened.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyHandoffCheckpoint(options: GitvaultHandoffRestoreOptions): Promise<GitvaultHandoffRestoreResult>;
|
|
37
|
+
/**
|
|
38
|
+
* `--to <dir>` wins; otherwise the vault's address-form name (`org/name` →
|
|
39
|
+
* `name`) when the claim response carried one, otherwise the vault id.
|
|
40
|
+
* Always absolute — `cloneGitvaultRemote` runs in `tmpdir()`, so a
|
|
41
|
+
* relative destination must be resolved against the CALLER's cwd first.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveResumeTargetDir(to: string | undefined, address: string | null | undefined, vaultId: string): string;
|
|
44
|
+
/** The commit message (the Handoff Note, verbatim) — `null` when `oid` cannot be read (e.g. not yet present). */
|
|
45
|
+
export declare function readGitCommitMessage(dir: string, oid: string): Promise<string | null>;
|
|
46
|
+
//# sourceMappingURL=gitvault-restore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitvault-restore.d.ts","sourceRoot":"","sources":["../../src/node/gitvault-restore.ts"],"names":[],"mappings":"AA2CA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvF;AAED,MAAM,WAAW,6BAA6B;IAC5C,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,gJAAgJ;IAChJ,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4KAA4K;IAC5K,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CAAC,4BAA4B,CAAC,CA4B1H;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAI1H;AAED,iHAAiH;AACjH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3F"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gitvault — handoff restore (kygit-handoff design D1/D10).
|
|
3
|
+
*
|
|
4
|
+
* Restore is porcelain git, in two stages that deliberately run through
|
|
5
|
+
* DIFFERENT runners:
|
|
6
|
+
*
|
|
7
|
+
* 1. `git clone <remote-url> <dir>` — a REAL network operation (the vault
|
|
8
|
+
* is reached through the `git-remote-run402`/`git-remote-kygit` remote
|
|
9
|
+
* helper), so it must NOT run under `hardenedGit`'s
|
|
10
|
+
* `-c protocol.allow=never` (that flag exists to keep LOCAL plumbing
|
|
11
|
+
* calls — hash-object, commit-tree, write-tree — from ever touching
|
|
12
|
+
* the network by accident; a clone is the one call in this whole
|
|
13
|
+
* module that is SUPPOSED to). `--no-checkout` so nothing in the
|
|
14
|
+
* target directory's initial default-branch checkout can fire a
|
|
15
|
+
* template-installed hook before step 2 neutralizes hooks.
|
|
16
|
+
* 2. Every LOCAL-only step after that (checkout the base, apply the
|
|
17
|
+
* stash-shaped commit) runs through {@link hardenedGit} exactly like
|
|
18
|
+
* every other gitvault plumbing call — hooks, fsmonitor, and replace
|
|
19
|
+
* refs all disabled, argv-only, no shell.
|
|
20
|
+
*
|
|
21
|
+
* The handoff commit ITSELF needs no separate fetch: it is a `retention
|
|
22
|
+
* root` (design D6), and `restoreObjectsInto` — what the remote helper's
|
|
23
|
+
* `fetch` verb runs on every clone — materializes the vault's FULL
|
|
24
|
+
* retained object set, not just ref-reachable history. By the time step 1
|
|
25
|
+
* finishes, `<oid>` is already a loose object in the fresh clone's ODB.
|
|
26
|
+
*/
|
|
27
|
+
import { execFile } from "node:child_process";
|
|
28
|
+
import { mkdtempSync } from "node:fs";
|
|
29
|
+
import { tmpdir } from "node:os";
|
|
30
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
31
|
+
import { LocalError } from "../errors.js";
|
|
32
|
+
import { hardenedGit, hardenedGitEnv } from "./gitvault-snapshot.js";
|
|
33
|
+
function fail(code, message, context, details) {
|
|
34
|
+
throw new LocalError(message, context, { code, details });
|
|
35
|
+
}
|
|
36
|
+
let emptyCloneHooksDir = null;
|
|
37
|
+
function cloneHooksDir() {
|
|
38
|
+
emptyCloneHooksDir ??= mkdtempSync(join(tmpdir(), "run402-gitvault-resume-clone-nohooks-"));
|
|
39
|
+
return emptyCloneHooksDir;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `git clone --no-checkout <remoteUrl> <targetDir>` — protocol-permitting
|
|
43
|
+
* (this is the one gitvault git invocation allowed to touch the network),
|
|
44
|
+
* hooks and terminal prompts still neutralized. `targetDir` must not
|
|
45
|
+
* already exist (git's own clone precondition).
|
|
46
|
+
*/
|
|
47
|
+
export function cloneGitvaultRemote(remoteUrl, targetDir) {
|
|
48
|
+
return new Promise((resolvePromise, reject) => {
|
|
49
|
+
const argv = ["--no-replace-objects", "-c", `core.hooksPath=${cloneHooksDir()}`, "clone", "--no-checkout", "--", remoteUrl, targetDir];
|
|
50
|
+
execFile("git", argv, { cwd: tmpdir(), env: hardenedGitEnv(), encoding: "buffer", maxBuffer: 1024 * 1024 * 1024, windowsHide: true }, (error, _stdout, stderr) => {
|
|
51
|
+
if (error) {
|
|
52
|
+
const stderrText = Buffer.from(stderr).toString("utf8");
|
|
53
|
+
reject(new LocalError(`git clone ${remoteUrl} failed: ${stderrText.trim().slice(0, 1000) || error.message}`, "cloning the vault for resume", { code: "HANDOFF_CLONE_FAILED", details: { remote_url: remoteUrl, target_dir: targetDir, stderr: stderrText.slice(0, 2000) } }));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
resolvePromise();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function sanitizeBranchName(name) {
|
|
61
|
+
return name && /^[A-Za-z0-9._/-]+$/.test(name) && !name.startsWith("-") ? name : null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check out the base, land on a real branch (never left detached), then
|
|
65
|
+
* `git stash apply --index <stash_oid>` — staged, unstaged, deleted, and
|
|
66
|
+
* untracked changes come back distinctly (verified against real git 2.43
|
|
67
|
+
* plumbing during design). Every step here is LOCAL — no network — so it
|
|
68
|
+
* runs fully hardened.
|
|
69
|
+
*/
|
|
70
|
+
export async function applyHandoffCheckpoint(options) {
|
|
71
|
+
const { dir } = options;
|
|
72
|
+
let baseHeadOid = options.base_head_oid ?? null;
|
|
73
|
+
if (!baseHeadOid) {
|
|
74
|
+
try {
|
|
75
|
+
baseHeadOid = (await hardenedGit(dir, ["rev-parse", "--verify", `${options.stash_oid}^1`])).text().trim();
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
fail("HANDOFF_RESTORE_APPLY_FAILED", `could not read the base commit (first parent) off ${options.stash_oid} — it may not be present in the clone yet`, "restoring the handoff checkpoint", { stash_oid: options.stash_oid, cause: e instanceof Error ? e.message : String(e) });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
let branch = sanitizeBranchName(options.branch_hint);
|
|
82
|
+
if (!branch) {
|
|
83
|
+
try {
|
|
84
|
+
const symref = (await hardenedGit(dir, ["symbolic-ref", "-q", "--short", "HEAD"], { okStatuses: [1] })).text().trim();
|
|
85
|
+
branch = sanitizeBranchName(symref);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
branch = null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
branch ??= "main";
|
|
92
|
+
await hardenedGit(dir, ["checkout", "-q", baseHeadOid]);
|
|
93
|
+
await hardenedGit(dir, ["checkout", "-q", "-B", branch]);
|
|
94
|
+
try {
|
|
95
|
+
await hardenedGit(dir, ["stash", "apply", "--index", options.stash_oid]);
|
|
96
|
+
}
|
|
97
|
+
catch (e) {
|
|
98
|
+
fail("HANDOFF_RESTORE_APPLY_FAILED", `\`git stash apply --index\` failed to reconstruct the handed-off state: ${e instanceof Error ? e.message : String(e)}`, "restoring the handoff checkpoint", { base_head_oid: baseHeadOid, stash_oid: options.stash_oid, cause: e instanceof Error ? e.message : String(e) });
|
|
99
|
+
}
|
|
100
|
+
return { branch, base_head_oid: baseHeadOid, stash_oid: options.stash_oid };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* `--to <dir>` wins; otherwise the vault's address-form name (`org/name` →
|
|
104
|
+
* `name`) when the claim response carried one, otherwise the vault id.
|
|
105
|
+
* Always absolute — `cloneGitvaultRemote` runs in `tmpdir()`, so a
|
|
106
|
+
* relative destination must be resolved against the CALLER's cwd first.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveResumeTargetDir(to, address, vaultId) {
|
|
109
|
+
if (to)
|
|
110
|
+
return isAbsolute(to) ? to : resolve(process.cwd(), to);
|
|
111
|
+
const name = address ? address.split("/").pop() : null;
|
|
112
|
+
return resolve(process.cwd(), name || vaultId);
|
|
113
|
+
}
|
|
114
|
+
/** The commit message (the Handoff Note, verbatim) — `null` when `oid` cannot be read (e.g. not yet present). */
|
|
115
|
+
export async function readGitCommitMessage(dir, oid) {
|
|
116
|
+
try {
|
|
117
|
+
return (await hardenedGit(dir, ["log", "-1", "--format=%B", oid])).text().replace(/\n$/, "");
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=gitvault-restore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitvault-restore.js","sourceRoot":"","sources":["../../src/node/gitvault-restore.ts"],"names":[],"mappings":"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"}
|
|
@@ -303,6 +303,93 @@ export declare function capturedSetUnchanged(drift: GitvaultCapturedSetDrift): b
|
|
|
303
303
|
export declare function captureSnapshot(options: GitvaultSnapshotOptions): Promise<GitvaultSnapshot>;
|
|
304
304
|
/** `git check-attr filter` over paths; returns every path whose `filter` attribute is set (LFS included). */
|
|
305
305
|
export declare function detectActiveFilters(top: string, paths: string[]): Promise<GitvaultSnapshotRefusalPath[]>;
|
|
306
|
+
/**
|
|
307
|
+
* Sensitive untracked-path denylist (design D10, verbatim). Applies to the
|
|
308
|
+
* UNTRACKED set only — a tracked file is the user's own committed choice and
|
|
309
|
+
* is never filtered by this list. `--include-sensitive <glob>` re-admits a
|
|
310
|
+
* named path by matching the SAME glob grammar against the candidate.
|
|
311
|
+
*/
|
|
312
|
+
export declare const GITVAULT_HANDOFF_SENSITIVE_DENYLIST: readonly string[];
|
|
313
|
+
/**
|
|
314
|
+
* A slash-free glob matches the path's BASENAME at any depth (gitignore's
|
|
315
|
+
* "no slash" rule). A glob ending `/**` (e.g. `.aws/**`) matches the named
|
|
316
|
+
* directory component at ANY depth in the tree, plus everything under it —
|
|
317
|
+
* a deliberately broader-than-gitignore reading for a credential-directory
|
|
318
|
+
* denylist, where over-excluding is the safe failure mode. Any other
|
|
319
|
+
* slash-bearing glob matches the full relative path exactly.
|
|
320
|
+
*/
|
|
321
|
+
export declare function globMatchesGitPath(glob: string, relPath: string): boolean;
|
|
322
|
+
/** True iff `relPath` (an untracked-not-ignored path) matches the sensitive denylist and is not re-admitted by `includeSensitive`. */
|
|
323
|
+
export declare function isHandoffSensitivePath(relPath: string, includeSensitive?: readonly string[]): boolean;
|
|
324
|
+
/** What {@link GitvaultHandoffCaptureOptions.message} learns once capture figures are known — everything a Handoff Note's `capture` block needs, before the outer commit exists. */
|
|
325
|
+
export interface GitvaultHandoffCaptureStats {
|
|
326
|
+
base_head_oid: string;
|
|
327
|
+
/** `HEAD`'s symref name (`refs/heads/<branch>`, stripped) — `null` on a detached HEAD. */
|
|
328
|
+
branch: string | null;
|
|
329
|
+
modified_captured: string[];
|
|
330
|
+
untracked_captured: string[];
|
|
331
|
+
sensitive_excluded: string[];
|
|
332
|
+
ignored_not_transferred_count: number;
|
|
333
|
+
}
|
|
334
|
+
export interface GitvaultHandoffCaptureOptions {
|
|
335
|
+
/** The work tree (any directory inside it). */
|
|
336
|
+
dir: string;
|
|
337
|
+
env?: GitConfigDiscoveryEnv;
|
|
338
|
+
/**
|
|
339
|
+
* The outer commit's message (the Handoff Note). A plain string is used
|
|
340
|
+
* verbatim (the caller has already composed and secret-scanned it). A
|
|
341
|
+
* FUNCTION is called with the real capture figures right before the
|
|
342
|
+
* outer `commit-tree` — the one point at which a Handoff Note's
|
|
343
|
+
* `capture` block can be filled with true numbers, since the note (and
|
|
344
|
+
* the commit that carries it) cannot exist before those numbers are
|
|
345
|
+
* known. Throwing inside it (the client-side secret scan) aborts the
|
|
346
|
+
* capture before the outer commit is written; the two throwaway parent
|
|
347
|
+
* commits (index/untracked) are already unreachable garbage at that
|
|
348
|
+
* point, exactly as if the capture had never run.
|
|
349
|
+
*/
|
|
350
|
+
message: string | ((stats: GitvaultHandoffCaptureStats) => string);
|
|
351
|
+
now?: () => Date;
|
|
352
|
+
/** Re-admit named untracked paths the sensitive denylist would otherwise exclude. */
|
|
353
|
+
includeSensitive?: string[];
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* A stash-shaped checkpoint (design D1): one synthetic commit, ALWAYS
|
|
357
|
+
* created (a clean tree still produces it — there is one shape, one code
|
|
358
|
+
* path). `oid`'s tree is the worktree state of TRACKED paths only; its
|
|
359
|
+
* three parents are `base_head_oid` (parent 1), `index_commit_oid` (parent
|
|
360
|
+
* 2, tree = the real index), and `untracked_commit_oid` (parent 3,
|
|
361
|
+
* parentless, tree = the admitted untracked set — the EMPTY tree when
|
|
362
|
+
* nothing untracked survives the denylist). Restore is `git clone` at
|
|
363
|
+
* `base_head_oid` then `git stash apply --index <oid>`.
|
|
364
|
+
*/
|
|
365
|
+
export interface GitvaultHandoffSnapshot {
|
|
366
|
+
oid: string;
|
|
367
|
+
tree_oid: string;
|
|
368
|
+
base_head_oid: string;
|
|
369
|
+
index_commit_oid: string;
|
|
370
|
+
untracked_commit_oid: string;
|
|
371
|
+
head: GitvaultHeadTarget;
|
|
372
|
+
top_level: string;
|
|
373
|
+
/** Tracked paths whose on-disk content differs from `base_head_oid`'s tree (staged, unstaged, or both) and are present in `tree_oid`. */
|
|
374
|
+
modified_captured: string[];
|
|
375
|
+
/** Untracked-not-ignored paths admitted into `untracked_commit_oid`'s tree (denylist already applied). */
|
|
376
|
+
untracked_captured: string[];
|
|
377
|
+
/** Untracked-not-ignored paths excluded by the sensitive denylist (before any `includeSensitive` re-admission). */
|
|
378
|
+
sensitive_excluded: string[];
|
|
379
|
+
/** Ignored (gitignore/exclude) files present on disk — never transferred, counted only. */
|
|
380
|
+
ignored_not_transferred_count: number;
|
|
381
|
+
captured: GitvaultCapturedFile[];
|
|
382
|
+
captured_digest: string;
|
|
383
|
+
global_excludes_path: string | null;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Capture a stash-shaped handoff checkpoint. Reuses every hardened-execution
|
|
387
|
+
* guarantee `captureSnapshot` already provides (filter-free hashing, frozen
|
|
388
|
+
* ignore authority, refusal-by-name for conflicted/linked/submodule/sparse/
|
|
389
|
+
* shallow/LFS layouts) via {@link inspectRepository} + {@link
|
|
390
|
+
* detectActiveFilters}; the shape below is the ONLY thing new.
|
|
391
|
+
*/
|
|
392
|
+
export declare function captureHandoffSnapshot(options: GitvaultHandoffCaptureOptions): Promise<GitvaultHandoffSnapshot>;
|
|
306
393
|
/**
|
|
307
394
|
* Check out `oid`'s tree into `targetDir` through a temporary index
|
|
308
395
|
* (`read-tree` + `checkout-index`) — filter-free, hook-free, and isolated
|