@jbarket/loomai 0.13.0 → 0.13.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/CHANGELOG.md CHANGED
@@ -12,6 +12,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [0.13.1] - 2026-10-24
16
+
17
+ ### Changed
18
+
19
+ - **Bundles are gzipped** before they're encrypted, which makes a real
20
+ household about a third of the size (40 MB down to about 13 MB). `loom restore`
21
+ still reads the uncompressed bundles that 0.12 and 0.13 wrote.
22
+
15
23
  ## [0.13.0] - 2026-10-24
16
24
 
17
25
  ### Added
@@ -771,7 +779,8 @@ Initial public release.
771
779
  stack and all added external-service dependencies or operational
772
780
  overhead.
773
781
 
774
- [Unreleased]: https://github.com/sleepunit-agents/loom/compare/v0.13.0...HEAD
782
+ [Unreleased]: https://github.com/sleepunit-agents/loom/compare/v0.13.1...HEAD
783
+ [0.13.1]: https://github.com/sleepunit-agents/loom/compare/v0.13.0...v0.13.1
775
784
  [0.13.0]: https://github.com/sleepunit-agents/loom/compare/v0.12.0...v0.13.0
776
785
  [0.12.0]: https://github.com/sleepunit-agents/loom/compare/v0.11.0...v0.12.0
777
786
  [0.11.0]: https://github.com/sleepunit-agents/loom/compare/v0.10.0...v0.11.0
package/dist/bundle.js CHANGED
@@ -8,7 +8,7 @@
8
8
  * loom restore <file> --identity <key> --drill restore into a throwaway dir and
9
9
  * compare with the live household
10
10
  *
11
- * Inside (a tar, then age-encrypted): manifest.json, household.json, the token
11
+ * Inside (a gzipped tar, then age-encrypted): manifest.json, household.json, the token
12
12
  * files, the commons, every agent's directory (SQLite through the backup API,
13
13
  * never a raw copy of a live file), and each installed piece's own part, which
14
14
  * the piece encrypts itself (`loom-<piece> bundle export`): core never sees inside
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import { spawn, spawnSync } from 'node:child_process';
21
21
  import { createHash } from 'node:crypto';
22
- import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, readlinkSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs';
22
+ import { chmodSync, closeSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readdirSync, readFileSync, readlinkSync, readSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs';
23
23
  import { tmpdir } from 'node:os';
24
24
  import { basename, delimiter, join, resolve } from 'node:path';
25
25
  import BetterSqlite3 from 'better-sqlite3';
@@ -198,9 +198,9 @@ export async function exportBundle(opts) {
198
198
  household: { agents: h.agents, default: h.default, ...(h.owner ? { owner: h.owner } : {}) }, pieces,
199
199
  };
200
200
  writeFileSync(join(stage, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n', { mode: 0o600 });
201
- // tar, then encrypt; only the encrypted file leaves the temp dir.
202
- const plain = join(work, 'household.tar');
203
- run(tar, ['-C', stage, '-cf', plain, '.'], 'tar');
201
+ // tar and gzip, then encrypt; only the encrypted file leaves the temp dir.
202
+ const plain = join(work, 'household.tar.gz');
203
+ run(tar, ['-C', stage, '-czf', plain, '.'], 'tar');
204
204
  const out = resolve(opts.to);
205
205
  const tmpOut = `${out}.${process.pid}.tmp`;
206
206
  run(age, ['-e', ...opts.recipients.flatMap((r) => ['-r', r]), '-o', tmpOut, plain], 'age');
@@ -228,7 +228,17 @@ function unpack(fileIn, identityIn, dir, env) {
228
228
  run(age, ['-d', '-i', identity, '-o', plain, file], 'age (decrypt: is this the right key?)');
229
229
  mkdirSync(dir, { recursive: true, mode: 0o700 });
230
230
  // Members are ours (we wrote them), but never let one land outside dir.
231
- run(tar, ['-C', dir, '--no-same-owner', '-xf', plain], 'tar');
231
+ // Bundles from 0.12 and 0.13 are a plain tar; later ones are gzipped.
232
+ const head = Buffer.alloc(2);
233
+ const fd = openSync(plain, 'r');
234
+ try {
235
+ readSync(fd, head, 0, 2, 0);
236
+ }
237
+ finally {
238
+ closeSync(fd);
239
+ }
240
+ const gz = head[0] === 0x1f && head[1] === 0x8b;
241
+ run(tar, ['-C', dir, '--no-same-owner', gz ? '-xzf' : '-xf', plain], 'tar');
232
242
  const m = JSON.parse(readFileSync(join(dir, 'manifest.json'), 'utf-8'));
233
243
  if (m.v !== 1)
234
244
  throw new BundleError(`this bundle is format v${String(m.v)}; this loom reads v1`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbarket/loomai",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "MCP server for persistent AI agent identity and memory. Single-file sqlite-vec + local ONNX embeddings; zero external services.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",