@staix/agent-mem 0.13.0 → 0.14.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.
@@ -0,0 +1,87 @@
1
+ /** Bounded selected-path acquisition only. Transport admission and receiving binding stay with the caller. */
2
+ import { createHash } from "node:crypto";
3
+ import { PUBLIC_PRUNE_GRAPH_MAX_BYTES, PUBLIC_PRUNE_GRAPH_MAX_OBJECTS, PUBLIC_PRUNE_INPUT_MAX_BYTES, PublicPruneInputError, type PublicPruneObject } from "./public-prune-inputs.ts";
4
+ import { decodeShardDescriptor, decodeShardManifest, SHARD_PACK_MAX_BYTES, type ShardSyncRealm } from "./shard-sync-format.ts";
5
+ import { PUBLIC_PRUNE_MAX_PACKS, PUBLIC_PRUNE_MAX_WITNESSES, verifyPublicPruneWitness } from "./public-prune-witness.ts";
6
+
7
+ type ObjectType = "commit" | "tree" | "blob";
8
+ export interface PublicPruneGitGraphOptions {
9
+ commit: string; manifestPath: string; manifestBlob: string; realm: ShardSyncRealm;
10
+ readObject: (oid: string) => Promise<{ type: ObjectType; body: Uint8Array }>;
11
+ }
12
+ const hex = (v: unknown, n: number): v is string => typeof v === "string" && v.length === n && /^[a-f0-9]+$/.test(v);
13
+ const object = (v: unknown): v is Record<string, unknown> => !!v && typeof v === "object" && !Array.isArray(v);
14
+ function guard(ok: unknown, resource = false): asserts ok { if (!ok) throw new PublicPruneInputError(resource ? "resource" : "unavailable"); }
15
+ interface TreeEntry { mode: "40000" | "100644"; oid: string }
16
+ function parseTree(body: Buffer): Map<string, TreeEntry> {
17
+ const entries = new Map<string, TreeEntry>();
18
+ for (let offset = 0; offset < body.length;) {
19
+ const space = body.indexOf(32, offset); guard(space > offset);
20
+ const end = body.indexOf(0, space + 1); guard(end > space + 1 && end + 21 <= body.length);
21
+ const modeBytes = body.subarray(offset, space), mode = modeBytes.toString("ascii");
22
+ guard((mode === "40000" || mode === "100644") && modeBytes.equals(Buffer.from(mode)));
23
+ const rawName = body.subarray(space + 1, end), name = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(rawName);
24
+ guard(name.length > 0 && name !== "." && name !== ".." && !name.includes("/") && !entries.has(name));
25
+ entries.set(name, { mode, oid: body.subarray(end + 1, end + 21).toString("hex") }); offset = end + 21;
26
+ }
27
+ return entries;
28
+ }
29
+
30
+ /** Complete raw object graph for one manifest. Unsupported lineage still returns its complete verified public proof. */
31
+ export async function collectPublicPruneGitGraph(options: PublicPruneGitGraphOptions): Promise<PublicPruneObject[]> {
32
+ try {
33
+ const { commit, manifestPath, manifestBlob, readObject } = options, realm = structuredClone(options.realm);
34
+ guard(hex(commit, 40) && hex(manifestBlob, 40));
35
+ guard(typeof manifestPath === "string" && manifestPath.length === 85 && /^prune-witnesses\/[a-f0-9]{64}\.json$/.test(manifestPath));
36
+ const objects = new Map<string, { type: ObjectType; body: Buffer; bytes: Buffer }>(), trees = new Map<string, Map<string, TreeEntry>>(); let total = 0;
37
+ const get = async (oid: string, type: ObjectType) => {
38
+ guard(hex(oid, 40)); let found = objects.get(oid);
39
+ if (!found) {
40
+ guard(objects.size < PUBLIC_PRUNE_GRAPH_MAX_OBJECTS, true);
41
+ const value = await readObject(oid);
42
+ guard(value && ["commit", "tree", "blob"].includes(value.type) && value.body instanceof Uint8Array);
43
+ guard(value.body.byteLength <= (value.type === "commit" ? PUBLIC_PRUNE_INPUT_MAX_BYTES : SHARD_PACK_MAX_BYTES), true);
44
+ const header = Buffer.from(`${value.type} ${value.body.byteLength}\0`);
45
+ guard(header.length + value.body.byteLength <= SHARD_PACK_MAX_BYTES + 64 && total + header.length + value.body.byteLength <= PUBLIC_PRUNE_GRAPH_MAX_BYTES, true);
46
+ const body = Buffer.from(value.body), bytes = Buffer.concat([header, body]);
47
+ guard(createHash("sha1").update(bytes).digest("hex") === oid);
48
+ found = { type: value.type, body, bytes }; total += bytes.length; objects.set(oid, found);
49
+ }
50
+ guard(found.type === type); return found;
51
+ };
52
+ const commitBody = (await get(commit, "commit")).body, lf = commitBody.indexOf(10);
53
+ // Only the ASCII tree header is interpreted; arbitrary commit message bytes remain exact.
54
+ guard(lf === 45 && commitBody.subarray(0, 5).equals(Buffer.from("tree ")));
55
+ const rootBytes = commitBody.subarray(5, lf), root = rootBytes.toString("ascii");
56
+ guard(hex(root, 40) && rootBytes.equals(Buffer.from(root)));
57
+ const path = async (name: string) => {
58
+ const parts = name.split("/"); guard(parts.length > 0 && parts.every(part => part && part !== "." && part !== ".."));
59
+ let oid = root;
60
+ for (let i = 0; i < parts.length; i++) {
61
+ let entries = trees.get(oid);
62
+ if (!entries) { entries = parseTree((await get(oid, "tree")).body); trees.set(oid, entries); }
63
+ const entry = entries.get(parts[i]!); guard(entry && entry.mode === (i === parts.length - 1 ? "100644" : "40000")); oid = entry.oid;
64
+ }
65
+ const value = await get(oid, "blob"); return { oid, body: value.body };
66
+ };
67
+ guard(decodeShardDescriptor((await path("shard.json")).body, realm) === "v2");
68
+ const manifest = await path(manifestPath); guard(manifest.oid === manifestBlob);
69
+ const raw = decodeShardManifest(manifestPath, manifest.body);
70
+ guard(object(raw) && object(raw.pruneOccurrence) && Array.isArray(raw.witnesses));
71
+ guard(raw.witnesses.length <= PUBLIC_PRUNE_MAX_WITNESSES, true);
72
+ const packs = new Map<string, { pack: string; blob: string; bytes: Buffer }>();
73
+ for (const ref of [raw.pruneOccurrence, ...raw.witnesses]) {
74
+ guard(object(ref) && typeof ref.pack === "string" && ref.pack.length === 140 && /^rows\/[a-f0-9]{64}\/[a-f0-9]{64}\.jsonl$/.test(ref.pack) && hex(ref.blob, 40));
75
+ const previous = packs.get(ref.pack);
76
+ if (previous) { guard(previous.blob === ref.blob); continue; }
77
+ guard(packs.size < PUBLIC_PRUNE_MAX_PACKS, true);
78
+ const found = await path(ref.pack); guard(found.oid === ref.blob && found.body.length <= SHARD_PACK_MAX_BYTES);
79
+ packs.set(ref.pack, { pack: ref.pack, blob: ref.blob, bytes: found.body });
80
+ }
81
+ const proof = verifyPublicPruneWitness(raw, { realm, packs: [...packs.values()] }); guard(proof.status !== "invalid");
82
+ return [...objects].map(([oid, item]) => ({ oid, bytes: item.bytes }));
83
+ } catch (error) {
84
+ if (error instanceof PublicPruneInputError) throw error;
85
+ throw new PublicPruneInputError();
86
+ }
87
+ }