@aerol-ai/aerolvm-sdk 0.8.0 → 0.8.2

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,14 @@
1
+ /** One archive member. Names use "/" and are relative to the folder. */
2
+ export interface TarEntry {
3
+ name: string;
4
+ type: "file" | "dir" | "symlink";
5
+ mode: number;
6
+ /** Seconds since the epoch. */
7
+ mtime: number;
8
+ data?: Uint8Array;
9
+ linkname?: string;
10
+ }
11
+ /** A PAX record: "<length> <key>=<value>\n", the length counting itself. */
12
+ export declare function paxRecord(key: string, value: string): Uint8Array;
13
+ /** The entries as one uncompressed tar archive. */
14
+ export declare function tarArchive(entries: TarEntry[]): Uint8Array;
@@ -0,0 +1,79 @@
1
+ // A minimal tar writer for uploadDir (plans/agent-sandbox-feature-parity.md,
2
+ // F3). Node has no tar module, and the SDK takes no dependencies. It writes
3
+ // ustar headers, with a PAX record for a name or link target longer than
4
+ // ustar's 100 bytes, which Go's archive/tar (toolboxd) reads.
5
+ const BLOCK = 512;
6
+ const encoder = new TextEncoder();
7
+ function putString(block, offset, length, value) {
8
+ const bytes = typeof value === "string" ? encoder.encode(value) : value;
9
+ block.set(bytes.subarray(0, length), offset);
10
+ }
11
+ function putOctal(block, offset, length, value) {
12
+ putString(block, offset, length - 1, Math.floor(value).toString(8).padStart(length - 1, "0"));
13
+ }
14
+ function header(name, typeflag, mode, size, mtime, linkname) {
15
+ const block = new Uint8Array(BLOCK);
16
+ putString(block, 0, 100, name);
17
+ putOctal(block, 100, 8, mode & 0o7777);
18
+ putOctal(block, 108, 8, 0);
19
+ putOctal(block, 116, 8, 0);
20
+ putOctal(block, 124, 12, size);
21
+ putOctal(block, 136, 12, mtime);
22
+ block.fill(0x20, 148, 156);
23
+ putString(block, 156, 1, typeflag);
24
+ putString(block, 157, 100, linkname);
25
+ putString(block, 257, 6, "ustar\0");
26
+ putString(block, 263, 2, "00");
27
+ let sum = 0;
28
+ for (const byte of block)
29
+ sum += byte;
30
+ putString(block, 148, 8, `${sum.toString(8).padStart(6, "0")}\0 `);
31
+ return block;
32
+ }
33
+ /** A PAX record: "<length> <key>=<value>\n", the length counting itself. */
34
+ export function paxRecord(key, value) {
35
+ const body = encoder.encode(` ${key}=${value}\n`);
36
+ let length = body.length + String(body.length).length;
37
+ if (String(length).length !== String(body.length).length) {
38
+ // Adding the digits made the number one digit longer (98 -> 100).
39
+ length = body.length + String(length).length;
40
+ }
41
+ return encoder.encode(`${length} ${key}=${value}\n`);
42
+ }
43
+ function padded(data) {
44
+ const rest = data.length % BLOCK;
45
+ return rest === 0 ? [data] : [data, new Uint8Array(BLOCK - rest)];
46
+ }
47
+ /** The entries as one uncompressed tar archive. */
48
+ export function tarArchive(entries) {
49
+ const chunks = [];
50
+ for (const entry of entries) {
51
+ const name = encoder.encode(entry.type === "dir" && !entry.name.endsWith("/") ? `${entry.name}/` : entry.name);
52
+ const linkname = encoder.encode(entry.linkname ?? "");
53
+ const records = [];
54
+ if (name.length > 100)
55
+ records.push(paxRecord("path", new TextDecoder().decode(name)));
56
+ if (linkname.length > 100)
57
+ records.push(paxRecord("linkpath", entry.linkname ?? ""));
58
+ if (records.length > 0) {
59
+ const pax = concat(records);
60
+ chunks.push(header(encoder.encode("PaxHeader"), "x", 0o644, pax.length, entry.mtime, new Uint8Array()), ...padded(pax));
61
+ }
62
+ const data = entry.type === "file" ? entry.data ?? new Uint8Array() : new Uint8Array();
63
+ const typeflag = entry.type === "file" ? "0" : entry.type === "dir" ? "5" : "2";
64
+ chunks.push(header(name, typeflag, entry.mode, data.length, entry.mtime, linkname));
65
+ if (data.length > 0)
66
+ chunks.push(...padded(data));
67
+ }
68
+ chunks.push(new Uint8Array(BLOCK * 2));
69
+ return concat(chunks);
70
+ }
71
+ function concat(chunks) {
72
+ const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
73
+ let offset = 0;
74
+ for (const chunk of chunks) {
75
+ out.set(chunk, offset);
76
+ offset += chunk.length;
77
+ }
78
+ return out;
79
+ }