@amalgm/shell 0.1.17 → 0.1.19
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/PURPOSE.md +47 -7
- package/dist/filesystem.d.ts +6 -0
- package/dist/filesystem.js +46 -2
- package/dist/filesystem.js.map +1 -1
- package/dist/git-command.d.ts +8 -0
- package/dist/git-command.js +68 -0
- package/dist/git-command.js.map +1 -0
- package/dist/git-registration-host.d.ts +18 -0
- package/dist/git-registration-host.js +107 -0
- package/dist/git-registration-host.js.map +1 -0
- package/dist/git-repository-host.d.ts +28 -9
- package/dist/git-repository-host.js +254 -102
- package/dist/git-repository-host.js.map +1 -1
- package/dist/materialized-graph.d.ts +18 -0
- package/dist/materialized-graph.js +113 -0
- package/dist/materialized-graph.js.map +1 -0
- package/dist/user-ground-host.d.ts +1 -0
- package/dist/user-ground-host.js +470 -250
- package/dist/user-ground-host.js.map +1 -1
- package/dist/wire-binary.d.ts +8 -0
- package/dist/wire-binary.js +31 -0
- package/dist/wire-binary.js.map +1 -0
- package/dist/wire-client.d.ts +3 -0
- package/dist/wire-client.js +22 -3
- package/dist/wire-client.js.map +1 -1
- package/package.json +2 -2
package/PURPOSE.md
CHANGED
|
@@ -93,6 +93,11 @@ shell only assembles.
|
|
|
93
93
|
an in-flight registration. A gateway response belongs to the exact wire
|
|
94
94
|
that delivered its request; if that source closes first, the late response
|
|
95
95
|
is discarded cleanly rather than sent through a replacement or closed wire.
|
|
96
|
+
Closing is a one-way lifecycle boundary: a rescan that was already in
|
|
97
|
+
flight may finish its durable work, but it can never recreate watcher
|
|
98
|
+
handles afterward. Each tracked root owns one recursive Node watcher, not
|
|
99
|
+
one handle per descendant directory; the Node version floor supplies this
|
|
100
|
+
primitive on macOS, Linux, and Windows.
|
|
96
101
|
|
|
97
102
|
17. **Independent content may travel concurrently; authority remains atomic.**
|
|
98
103
|
The host bounds parallel uploads for small immutable objects and processes
|
|
@@ -100,13 +105,48 @@ shell only assembles.
|
|
|
100
105
|
memory. The registry head advances only after every referenced object is
|
|
101
106
|
durably acknowledged.
|
|
102
107
|
|
|
103
|
-
18. **A Git repository travels
|
|
104
|
-
|
|
105
|
-
`.git` is transport metadata rather than entity
|
|
106
|
-
keep their UUID rows locally and ride
|
|
107
|
-
while the cloud registry carries the one
|
|
108
|
-
boundary travels
|
|
109
|
-
|
|
108
|
+
18. **A Git repository travels through Git.** The host asks Git to pack the
|
|
109
|
+
declared refs against the authority's known object frontier and asks Git
|
|
110
|
+
to index received packs. `.git` is transport metadata rather than entity
|
|
111
|
+
ground; worktree children keep their UUID rows locally and ride in the
|
|
112
|
+
repository state metadata, while the cloud registry carries the one
|
|
113
|
+
`repo.git` record. A shallow boundary travels with that metadata and is
|
|
114
|
+
installed before Git reads the imported objects.
|
|
115
|
+
|
|
116
|
+
19. **Live owns transfer; Shell owns transfer effects.** `@amalgm/live`
|
|
117
|
+
decides which entity types have artifacts, which chunks are missing, when
|
|
118
|
+
an upload manifest may commit, and when a download is verified. The Shell
|
|
119
|
+
adapter supplies seekable immutable-cache reads, the authority inventory
|
|
120
|
+
probe, bounded R2 requests, and a machine-local content-addressed chunk
|
|
121
|
+
cache; it never scans, registers, materializes, or publishes inside those
|
|
122
|
+
operations.
|
|
123
|
+
Control and integrity metadata remains JSON, while immutable block and Git
|
|
124
|
+
parcel bytes use the authenticated binary WebSocket rail without base64.
|
|
125
|
+
|
|
126
|
+
20. **Git is the repository-transfer performance gate.** On the same source,
|
|
127
|
+
destination inventory, machine, and network path, cold upload sends the
|
|
128
|
+
same Git object pack as a native push and incremental upload sends only the
|
|
129
|
+
newly missing objects. Timing comparisons use repeated runs because wall
|
|
130
|
+
clocks are noisy; byte-work parity is exact and any fixed Amalgm metadata
|
|
131
|
+
overhead is reported separately.
|
|
132
|
+
|
|
133
|
+
21. **Watch events preserve suspicion until proof.** A named filesystem event
|
|
134
|
+
scopes registration evidence to that path and its ancestors; a nameless
|
|
135
|
+
event, index-wide Git change, enrollment-policy change, watcher restart,
|
|
136
|
+
or command-end catch-up scopes the complete covered root. A scan settles
|
|
137
|
+
only the generations it observed, so an event received during that scan
|
|
138
|
+
remains pending.
|
|
139
|
+
|
|
140
|
+
22. **Git supplies clean repository evidence.** Registration obtains clean
|
|
141
|
+
tracked leaf identity and text/binary classification from Git's index,
|
|
142
|
+
attributes, and object database. It reads worktree bytes only for dirty or
|
|
143
|
+
untracked leaves. Git ignore never becomes Amalgm enrollment policy.
|
|
144
|
+
|
|
145
|
+
23. **Cold add never rereads a repository graph.** Download verifies and
|
|
146
|
+
assembles each content-addressed transport to a file, streams its Git pack
|
|
147
|
+
range directly into `index-pack`, and derives local SQLite rows from the
|
|
148
|
+
transported UUID/type/payload identity map plus filesystem stats. It does
|
|
149
|
+
not buffer the complete repository parcel or reclassify checked-out files.
|
|
110
150
|
|
|
111
151
|
## Relationship to amalgm-engine
|
|
112
152
|
|
package/dist/filesystem.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export declare function ensurePrivateDir(directory: string): void;
|
|
2
2
|
export declare function atomicWrite(file: string, bytes: string | Uint8Array, mode?: number): void;
|
|
3
|
+
export declare function atomicCopy(source: string, destination: string, mode?: number): void;
|
|
4
|
+
/** Assemble verified chunk files without holding the complete artifact in RAM. */
|
|
5
|
+
export declare function atomicAssemble(destination: string, sources: readonly string[]): Promise<{
|
|
6
|
+
readonly bytes: number;
|
|
7
|
+
readonly sha256: string;
|
|
8
|
+
}>;
|
|
3
9
|
export declare function readJson<T>(file: string): T | null;
|
|
4
10
|
export declare function atomicJson(file: string, value: unknown): void;
|
|
5
11
|
/** Commit related JSON documents without ever leaving a split public/secret
|
package/dist/filesystem.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { chmodSync, copyFileSync, createReadStream, createWriteStream, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
|
+
import { once } from "node:events";
|
|
4
5
|
export function ensurePrivateDir(directory) {
|
|
5
6
|
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
6
7
|
chmodSync(directory, 0o700);
|
|
@@ -17,6 +18,49 @@ export function atomicWrite(file, bytes, mode = 0o600) {
|
|
|
17
18
|
rmSync(temporary, { force: true });
|
|
18
19
|
}
|
|
19
20
|
}
|
|
21
|
+
export function atomicCopy(source, destination, mode = 0o600) {
|
|
22
|
+
ensurePrivateDir(dirname(destination));
|
|
23
|
+
const temporary = `${destination}.${randomUUID()}.tmp`;
|
|
24
|
+
try {
|
|
25
|
+
copyFileSync(source, temporary);
|
|
26
|
+
chmodSync(temporary, mode);
|
|
27
|
+
renameSync(temporary, destination);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
rmSync(temporary, { force: true });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Assemble verified chunk files without holding the complete artifact in RAM. */
|
|
34
|
+
export async function atomicAssemble(destination, sources) {
|
|
35
|
+
ensurePrivateDir(dirname(destination));
|
|
36
|
+
const temporary = `${destination}.${randomUUID()}.tmp`;
|
|
37
|
+
const output = createWriteStream(temporary, { flags: "wx", mode: 0o600 });
|
|
38
|
+
const hash = createHash("sha256");
|
|
39
|
+
let bytes = 0;
|
|
40
|
+
try {
|
|
41
|
+
for (const source of sources) {
|
|
42
|
+
for await (const chunk of createReadStream(source)) {
|
|
43
|
+
const value = chunk;
|
|
44
|
+
hash.update(value);
|
|
45
|
+
bytes += value.byteLength;
|
|
46
|
+
if (!output.write(value))
|
|
47
|
+
await once(output, "drain");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
output.end();
|
|
51
|
+
await once(output, "close");
|
|
52
|
+
renameSync(temporary, destination);
|
|
53
|
+
chmodSync(destination, 0o600);
|
|
54
|
+
return { bytes, sha256: hash.digest("hex") };
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
output.destroy();
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
rmSync(temporary, { force: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
20
64
|
export function readJson(file) {
|
|
21
65
|
try {
|
|
22
66
|
return JSON.parse(readFileSync(file, "utf8"));
|
package/dist/filesystem.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../src/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function runGit(cwd: string, args: readonly string[], input?: Uint8Array): Buffer;
|
|
2
|
+
/** Git grep uses exit 1 to mean a valid search with no matches. */
|
|
3
|
+
export declare function runGitSearch(cwd: string, args: readonly string[]): Buffer;
|
|
4
|
+
/** Stream a potentially large Git result directly to a private destination. */
|
|
5
|
+
export declare function runGitToFile(cwd: string, args: readonly string[], input: Uint8Array, file: string): void;
|
|
6
|
+
export declare function tryGit(cwd: string, args: readonly string[]): Buffer | null;
|
|
7
|
+
export declare const gitText: (cwd: string, args: readonly string[]) => string;
|
|
8
|
+
export declare function tryGitText(cwd: string, args: readonly string[]): string | null;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { closeSync, openSync } from "node:fs";
|
|
3
|
+
const MAX_GIT_BUFFER = 512 * 1024 * 1024;
|
|
4
|
+
function explainGitFailure(error, args) {
|
|
5
|
+
const failure = error;
|
|
6
|
+
const stderr = failure.stderr?.toString("utf8").trim();
|
|
7
|
+
failure.message = `git ${args.join(" ")} failed${stderr ? `: ${stderr}` : ""}`;
|
|
8
|
+
throw failure;
|
|
9
|
+
}
|
|
10
|
+
export function runGit(cwd, args, input) {
|
|
11
|
+
try {
|
|
12
|
+
return execFileSync("git", [...args], {
|
|
13
|
+
cwd,
|
|
14
|
+
input,
|
|
15
|
+
maxBuffer: MAX_GIT_BUFFER,
|
|
16
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
explainGitFailure(error, args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Git grep uses exit 1 to mean a valid search with no matches. */
|
|
25
|
+
export function runGitSearch(cwd, args) {
|
|
26
|
+
try {
|
|
27
|
+
return runGit(cwd, args);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const failure = error;
|
|
31
|
+
if (failure.status === 1)
|
|
32
|
+
return failure.stdout ?? Buffer.alloc(0);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Stream a potentially large Git result directly to a private destination. */
|
|
37
|
+
export function runGitToFile(cwd, args, input, file) {
|
|
38
|
+
const descriptor = openSync(file, "wx", 0o600);
|
|
39
|
+
try {
|
|
40
|
+
execFileSync("git", [...args], {
|
|
41
|
+
cwd,
|
|
42
|
+
input,
|
|
43
|
+
maxBuffer: MAX_GIT_BUFFER,
|
|
44
|
+
stdio: ["pipe", descriptor, "pipe"],
|
|
45
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
explainGitFailure(error, args);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
closeSync(descriptor);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function tryGit(cwd, args) {
|
|
56
|
+
try {
|
|
57
|
+
return runGit(cwd, args);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export const gitText = (cwd, args) => runGit(cwd, args).toString("utf8").trim();
|
|
64
|
+
export function tryGitText(cwd, args) {
|
|
65
|
+
const value = tryGit(cwd, args);
|
|
66
|
+
return value === null ? null : value.toString("utf8").trim();
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=git-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-command.js","sourceRoot":"","sources":["../src/git-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type EntityType } from "@amalgm/live";
|
|
2
|
+
export interface GitRegisteredLeaf {
|
|
3
|
+
readonly type: Extract<EntityType, "file.text" | "file.binary" | "link">;
|
|
4
|
+
/** Git's indexed blob is the content witness; Shell does not hash it again. */
|
|
5
|
+
readonly payloadVersion: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GitRegistrationEvidence {
|
|
8
|
+
/** Present only while the worktree path still agrees with the indexed blob. */
|
|
9
|
+
readonly cleanLeaves: ReadonlyMap<string, GitRegisteredLeaf>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Obtain registration evidence from Git's index and object database.
|
|
13
|
+
*
|
|
14
|
+
* Git is authoritative only for stage-zero paths whose worktree stat/content
|
|
15
|
+
* still agrees with the index. Dirty and untracked paths are deliberately
|
|
16
|
+
* absent so the ordinary scanner must read their current worktree bytes.
|
|
17
|
+
*/
|
|
18
|
+
export declare function inspectGitRegistration(repository: string, paths?: readonly string[] | null): GitRegistrationEvidence;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { classifyFile } from "@amalgm/live";
|
|
2
|
+
import { gitText, runGit, runGitSearch, tryGitText } from "./git-command.js";
|
|
3
|
+
const zeroFields = (bytes) => Buffer.from(bytes).toString("utf8").split("\0").filter((field) => field.length > 0);
|
|
4
|
+
const literalPathspecs = (paths) => paths.map((path) => {
|
|
5
|
+
const segments = path.split("/");
|
|
6
|
+
if (!path || path.startsWith("/") || segments.some((segment) => segment === "..")) {
|
|
7
|
+
throw new Error(`Git registration path is unsafe: ${path}`);
|
|
8
|
+
}
|
|
9
|
+
return `:(literal)${path}`;
|
|
10
|
+
});
|
|
11
|
+
function indexedBlobs(repository, paths) {
|
|
12
|
+
if (paths?.length === 0)
|
|
13
|
+
return new Map();
|
|
14
|
+
const fields = zeroFields(runGit(repository, [
|
|
15
|
+
"ls-files", "--stage", "-z",
|
|
16
|
+
...(paths ? ["--", ...literalPathspecs(paths)] : []),
|
|
17
|
+
]));
|
|
18
|
+
const entries = new Map();
|
|
19
|
+
for (const field of fields) {
|
|
20
|
+
const separator = field.indexOf("\t");
|
|
21
|
+
if (separator < 0)
|
|
22
|
+
throw new Error("Git returned an invalid index entry");
|
|
23
|
+
const [mode, objectId, stage] = field.slice(0, separator).split(" ");
|
|
24
|
+
const path = field.slice(separator + 1);
|
|
25
|
+
if (!mode || !objectId || !stage || !path)
|
|
26
|
+
throw new Error("Git returned an invalid index entry");
|
|
27
|
+
if (stage !== "0")
|
|
28
|
+
throw new Error(`repository index has unresolved entry: ${path}`);
|
|
29
|
+
entries.set(path, { mode, objectId });
|
|
30
|
+
}
|
|
31
|
+
return entries;
|
|
32
|
+
}
|
|
33
|
+
function blobSizes(repository, blobs) {
|
|
34
|
+
const objectIds = [...new Set([...blobs.values()]
|
|
35
|
+
.filter((blob) => blob.mode !== "160000")
|
|
36
|
+
.map((blob) => blob.objectId))];
|
|
37
|
+
if (objectIds.length === 0)
|
|
38
|
+
return new Map();
|
|
39
|
+
const output = runGit(repository, ["cat-file", "--batch-check=%(objectname) %(objectsize)"], Buffer.from(`${objectIds.join("\n")}\n`, "utf8")).toString("utf8");
|
|
40
|
+
const result = new Map();
|
|
41
|
+
for (const line of output.split("\n").filter(Boolean)) {
|
|
42
|
+
const separator = line.lastIndexOf(" ");
|
|
43
|
+
const objectId = line.slice(0, separator);
|
|
44
|
+
const size = Number(line.slice(separator + 1));
|
|
45
|
+
if (!objectId || !Number.isSafeInteger(size) || size < 0) {
|
|
46
|
+
throw new Error("Git returned invalid indexed blob metadata");
|
|
47
|
+
}
|
|
48
|
+
result.set(objectId, size);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
function diffAttributes(repository, paths) {
|
|
53
|
+
if (paths.length === 0)
|
|
54
|
+
return new Map();
|
|
55
|
+
const output = zeroFields(runGit(repository, ["check-attr", "--cached", "-z", "--stdin", "diff"], Buffer.from(`${paths.join("\0")}\0`, "utf8")));
|
|
56
|
+
if (output.length !== paths.length * 3)
|
|
57
|
+
throw new Error("Git returned invalid diff attributes");
|
|
58
|
+
const result = new Map();
|
|
59
|
+
for (let index = 0; index < output.length; index += 3) {
|
|
60
|
+
if (output[index + 1] !== "diff")
|
|
61
|
+
throw new Error("Git returned the wrong requested attribute");
|
|
62
|
+
result.set(output[index], output[index + 2]);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
function binaryDrivers(repository, attributes) {
|
|
67
|
+
const drivers = new Set([...attributes.values()].filter((value) => !["set", "unset", "unspecified"].includes(value)));
|
|
68
|
+
return new Set([...drivers].filter((driver) => tryGitText(repository, ["config", "--bool", "--get", `diff.${driver}.binary`]) === "true"));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Obtain registration evidence from Git's index and object database.
|
|
72
|
+
*
|
|
73
|
+
* Git is authoritative only for stage-zero paths whose worktree stat/content
|
|
74
|
+
* still agrees with the index. Dirty and untracked paths are deliberately
|
|
75
|
+
* absent so the ordinary scanner must read their current worktree bytes.
|
|
76
|
+
*/
|
|
77
|
+
export function inspectGitRegistration(repository, paths = null) {
|
|
78
|
+
const blobs = indexedBlobs(repository, paths);
|
|
79
|
+
if (blobs.size === 0)
|
|
80
|
+
return { cleanLeaves: new Map() };
|
|
81
|
+
const pathspecs = paths ? literalPathspecs(paths) : [];
|
|
82
|
+
const dirty = new Set(zeroFields(runGit(repository, [
|
|
83
|
+
"diff-files", "--name-only", "-z", "--", ...pathspecs,
|
|
84
|
+
])));
|
|
85
|
+
const text = new Set(zeroFields(runGitSearch(repository, [
|
|
86
|
+
"grep", "--cached", "-I", "-l", "-z", "-e", "", "--", ...pathspecs,
|
|
87
|
+
])).filter((path) => blobs.has(path)));
|
|
88
|
+
const blobPaths = [...blobs.keys()];
|
|
89
|
+
const sizes = blobSizes(repository, blobs);
|
|
90
|
+
const attributes = diffAttributes(repository, blobPaths);
|
|
91
|
+
const forcedBinaryDrivers = binaryDrivers(repository, attributes);
|
|
92
|
+
const objectFormat = gitText(repository, ["rev-parse", "--show-object-format"]);
|
|
93
|
+
const cleanLeaves = new Map();
|
|
94
|
+
for (const [path, blob] of blobs) {
|
|
95
|
+
if (dirty.has(path) || blob.mode === "160000")
|
|
96
|
+
continue;
|
|
97
|
+
const attribute = attributes.get(path) ?? "unspecified";
|
|
98
|
+
const forcedBinary = attribute === "unset" || forcedBinaryDrivers.has(attribute);
|
|
99
|
+
const binary = forcedBinary || (!text.has(path) && (sizes.get(blob.objectId) ?? 0) > 0);
|
|
100
|
+
cleanLeaves.set(path, {
|
|
101
|
+
type: blob.mode === "120000" ? "link" : classifyFile({ binary }),
|
|
102
|
+
payloadVersion: `git:${objectFormat}:${blob.objectId}`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return { cleanLeaves };
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=git-registration-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-registration-host.js","sourceRoot":"","sources":["../src/git-registration-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type RepoIdentityEntry, type RepoState, type RepositoryTransportLayout } from "@amalgm/live";
|
|
2
2
|
/** A `.git` directory or linked-worktree file is evidence only when Git says
|
|
3
3
|
* this exact directory is the worktree root. Stale marker files remain
|
|
4
4
|
* ordinary folder ground. */
|
|
@@ -6,15 +6,34 @@ export declare function isRepository(directory: string): boolean;
|
|
|
6
6
|
export interface PriorRepositoryTransport {
|
|
7
7
|
readonly stateId: string;
|
|
8
8
|
readonly transportVersion: string;
|
|
9
|
-
readonly
|
|
9
|
+
readonly card: RepoState["card"];
|
|
10
|
+
readonly identityHash: string;
|
|
10
11
|
}
|
|
11
12
|
export interface CapturedRepositoryTransport extends PriorRepositoryTransport {
|
|
12
13
|
readonly state: RepoState;
|
|
14
|
+
/** null means the prior immutable transport is already the exact result. */
|
|
15
|
+
readonly bytes: Uint8Array | null;
|
|
13
16
|
}
|
|
14
|
-
/** Capture one semantic repository state.
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
/** Capture one semantic repository state. A chainable capture packs only Git
|
|
18
|
+
* objects absent from its parent and only changed identity-map paths. */
|
|
19
|
+
export declare function captureRepository(repository: string, identity: readonly RepoIdentityEntry[], prior: PriorRepositoryTransport | null, previousIdentity?: readonly RepoIdentityEntry[] | null): CapturedRepositoryTransport;
|
|
20
|
+
export interface AppliedRepositoryState {
|
|
21
|
+
readonly stateId: string;
|
|
22
|
+
readonly cardId: string;
|
|
23
|
+
readonly checkpointId: string;
|
|
24
|
+
readonly card: RepoState["card"];
|
|
25
|
+
readonly transportVersion: string;
|
|
26
|
+
readonly identity: readonly RepoIdentityEntry[];
|
|
27
|
+
}
|
|
28
|
+
/** Materialize a complete transport chain and then re-derive its semantic
|
|
29
|
+
* state. The oldest node must be self-contained; every later node must name
|
|
30
|
+
* the exact predecessor whose Git objects and identity map it extends. */
|
|
31
|
+
export declare function applyRepository(repository: string, chain: readonly Uint8Array[]): AppliedRepositoryState;
|
|
32
|
+
export interface SealedRepositoryTransport {
|
|
33
|
+
readonly file: string;
|
|
34
|
+
readonly transportVersion: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function inspectRepositoryTransportFile(file: string): RepositoryTransportLayout;
|
|
37
|
+
/** Apply sealed repository artifacts by streaming each Git range directly
|
|
38
|
+
* into index-pack. Download already verified each complete transport hash. */
|
|
39
|
+
export declare function applyRepositoryFiles(repository: string, chain: readonly SealedRepositoryTransport[]): Promise<AppliedRepositoryState>;
|