midsummer-sol 0.2.0 → 0.2.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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/sol-secret-mcp.js +8 -7
  3. package/sol.js +536 -168
package/sol.js CHANGED
@@ -2034,6 +2034,52 @@ var init_seal_audience = __esm(() => {
2034
2034
  init_identity_store();
2035
2035
  });
2036
2036
 
2037
+ // src/bin/keyring-at-rest.ts
2038
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes4, scryptSync as scryptSync3 } from "node:crypto";
2039
+ function deriveWrapKey2(recoveryCode, accountId, salt) {
2040
+ return scryptSync3(recoveryCode.normalize("NFKD"), Buffer.concat([Buffer.from(`sol/keyring/v2\x00${accountId}\x00`), salt]), 32, KDF);
2041
+ }
2042
+ function isEnvelope(parsed) {
2043
+ return !!parsed && typeof parsed === "object" && parsed.v === 2 && parsed.enc === "scrypt-aes-256-gcm";
2044
+ }
2045
+ function wrapContext() {
2046
+ const id = loadIdentity();
2047
+ const recoveryCode = process.env.SOL_RECOVERY_CODE;
2048
+ if (!id || !recoveryCode)
2049
+ return;
2050
+ return { accountId: id.accountId, recoveryCode };
2051
+ }
2052
+ function encryptKeyRing(serialized) {
2053
+ const ctx = wrapContext();
2054
+ if (!ctx)
2055
+ return;
2056
+ const salt = randomBytes4(16);
2057
+ const key = deriveWrapKey2(ctx.recoveryCode, ctx.accountId, salt);
2058
+ const iv = randomBytes4(12);
2059
+ const c = createCipheriv3("aes-256-gcm", key, iv);
2060
+ const ct = Buffer.concat([c.update(Buffer.from(JSON.stringify(serialized), "utf8")), c.final()]);
2061
+ return { v: 2, enc: "scrypt-aes-256-gcm", accountId: ctx.accountId, salt: salt.toString("base64"), iv: iv.toString("base64"), ct: ct.toString("base64"), tag: c.getAuthTag().toString("base64") };
2062
+ }
2063
+ function decryptKeyRing(env) {
2064
+ const recoveryCode = process.env.SOL_RECOVERY_CODE;
2065
+ if (!recoveryCode)
2066
+ throw new Error("keys.json is encrypted at rest but SOL_RECOVERY_CODE is unset — set it to unlock the local keyring.");
2067
+ const key = deriveWrapKey2(recoveryCode, env.accountId, Buffer.from(env.salt, "base64"));
2068
+ const d = createDecipheriv3("aes-256-gcm", key, Buffer.from(env.iv, "base64"));
2069
+ d.setAuthTag(Buffer.from(env.tag, "base64"));
2070
+ try {
2071
+ const pt = Buffer.concat([d.update(Buffer.from(env.ct, "base64")), d.final()]).toString("utf8");
2072
+ return JSON.parse(pt);
2073
+ } catch {
2074
+ throw new Error("failed to decrypt keys.json — wrong SOL_RECOVERY_CODE for this keyring, or the file was tampered.");
2075
+ }
2076
+ }
2077
+ var KDF;
2078
+ var init_keyring_at_rest = __esm(() => {
2079
+ init_identity_store();
2080
+ KDF = { N: 1 << 15, r: 8, p: 1, maxmem: 64 * 1024 * 1024 };
2081
+ });
2082
+
2037
2083
  // src/bin/lib.ts
2038
2084
  import {
2039
2085
  appendFileSync as appendFileSync2,
@@ -2221,6 +2267,16 @@ async function snapshotTree(repo) {
2221
2267
  if (!onDisk.has(t) && lexists(join4(cwd, t)))
2222
2268
  onDisk.add(t);
2223
2269
  const hidden = hiddenPathSet(solDir);
2270
+ const sealedProtected = new Set;
2271
+ for (const t of tracked) {
2272
+ if (lexists(join4(cwd, t)))
2273
+ continue;
2274
+ const leaf = await repo.read(t).catch(() => {
2275
+ return;
2276
+ });
2277
+ if (leaf?.kind === "sealed")
2278
+ sealedProtected.add(t);
2279
+ }
2224
2280
  const changes = [];
2225
2281
  for (const f of onDisk) {
2226
2282
  if (hidden.has(f))
@@ -2229,9 +2285,12 @@ async function snapshotTree(repo) {
2229
2285
  if (c)
2230
2286
  changes.push(c);
2231
2287
  }
2232
- for (const t of tracked)
2233
- if (!hidden.has(t) && !isReservedSegment(t) && !lexists(join4(cwd, t)))
2288
+ for (const t of tracked) {
2289
+ if (hidden.has(t) || isReservedSegment(t) || sealedProtected.has(t))
2290
+ continue;
2291
+ if (!lexists(join4(cwd, t)))
2234
2292
  changes.push({ path: t, delete: true });
2293
+ }
2235
2294
  return repo.applyBatch(changes);
2236
2295
  }
2237
2296
  function sleepSync(ms) {
@@ -3041,12 +3100,15 @@ async function appendCapture(log, root) {
3041
3100
  }
3042
3101
  function loadKeyRing() {
3043
3102
  const ring = new KeyRing;
3044
- if (existsSync4(keysPath()))
3045
- ring.load(JSON.parse(readFileSync4(keysPath(), "utf8")));
3103
+ if (!existsSync4(keysPath()))
3104
+ return ring;
3105
+ const parsed = JSON.parse(readFileSync4(keysPath(), "utf8"));
3106
+ ring.load(isEnvelope(parsed) ? decryptKeyRing(parsed) : parsed);
3046
3107
  return ring;
3047
3108
  }
3048
3109
  function saveKeyRing(ring) {
3049
- writeFileSync4(keysPath(), JSON.stringify(ring.serialize(), null, 2), { mode: 384 });
3110
+ const env = encryptKeyRing(ring.serialize());
3111
+ writeFileSync4(keysPath(), JSON.stringify(env ?? ring.serialize(), null, 2), { mode: 384 });
3050
3112
  try {
3051
3113
  chmodSync3(keysPath(), 384);
3052
3114
  } catch {}
@@ -3066,6 +3128,7 @@ var init_lib = __esm(() => {
3066
3128
  init_struct();
3067
3129
  init_tree();
3068
3130
  init_seal_audience();
3131
+ init_keyring_at_rest();
3069
3132
  procCwd = process.cwd();
3070
3133
  repoRoot = findRepoRoot(procCwd);
3071
3134
  cwd = repoRoot ?? procCwd;
@@ -3499,7 +3562,7 @@ __export(exports_anchor, {
3499
3562
  creatorPinPath: () => creatorPinPath,
3500
3563
  creatorFingerprint: () => creatorFingerprint
3501
3564
  });
3502
- import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
3565
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "node:fs";
3503
3566
  import { join as join9 } from "node:path";
3504
3567
  function repoSolDir(solDir2) {
3505
3568
  return solDir2;
@@ -3690,26 +3753,74 @@ function validateGenesisAnchor(solDir2) {
3690
3753
  }
3691
3754
  return out;
3692
3755
  }
3756
+ function readEnvFiles(solDir2) {
3757
+ const dir = envDir(solDir2);
3758
+ const out = {};
3759
+ if (!existsSync9(dir))
3760
+ return out;
3761
+ for (const name of readdirSync3(dir, { withFileTypes: true })) {
3762
+ if (!name.isFile() || ENVSTATE_SKIP_FILES.has(name.name))
3763
+ continue;
3764
+ try {
3765
+ out[name.name] = readFileSync9(join9(dir, name.name), "utf8");
3766
+ } catch {}
3767
+ }
3768
+ return out;
3769
+ }
3770
+ function readSealStanzas(solDir2) {
3771
+ const dir = sealDir(solDir2);
3772
+ const out = {};
3773
+ if (!existsSync9(dir))
3774
+ return out;
3775
+ for (const name of readdirSync3(dir, { withFileTypes: true })) {
3776
+ if (!name.isFile() || !name.name.endsWith(".stanzas"))
3777
+ continue;
3778
+ try {
3779
+ out[name.name] = readFileSync9(join9(dir, name.name), "utf8");
3780
+ } catch {}
3781
+ }
3782
+ return out;
3783
+ }
3693
3784
  function readEnvStateBundle(solDir2) {
3694
3785
  const journal = readJournal(solDir2);
3695
3786
  const creatorPin = readCreatorPin(solDir2);
3696
- if (!journal.length && !creatorPin)
3787
+ const files = readEnvFiles(solDir2);
3788
+ const seals = readSealStanzas(solDir2);
3789
+ if (!journal.length && !creatorPin && !Object.keys(files).length && !Object.keys(seals).length)
3697
3790
  return;
3698
3791
  const journalHead = journal.length ? journal[journal.length - 1].entryHash : undefined;
3699
- return { v: 1, creatorPin, journal, journalHead, journalLen: journal.length };
3792
+ return { v: 1, creatorPin, journal, journalHead, journalLen: journal.length, files, seals };
3700
3793
  }
3701
3794
  function writeEnvStateBundle(solDir2, bundle) {
3795
+ mkdirSync5(envDir(solDir2), { recursive: true });
3702
3796
  writeJournal(solDir2, bundle.journal);
3703
3797
  if (bundle.creatorPin) {
3704
3798
  writeFileSync9(creatorPinPath(solDir2), JSON.stringify(bundle.creatorPin, null, 2), { mode: 420 });
3705
3799
  }
3800
+ mkdirSync5(envDir(solDir2), { recursive: true });
3801
+ for (const [name, contents] of Object.entries(bundle.files ?? {})) {
3802
+ if (name.includes("/") || name.includes("\\") || name.includes("\x00"))
3803
+ continue;
3804
+ if (ENVSTATE_SKIP_FILES.has(name))
3805
+ continue;
3806
+ writeFileSync9(join9(envDir(solDir2), name), contents, { mode: 420 });
3807
+ }
3808
+ const seals = bundle.seals ?? {};
3809
+ if (Object.keys(seals).length)
3810
+ mkdirSync5(sealDir(solDir2), { recursive: true });
3811
+ for (const [name, box] of Object.entries(seals)) {
3812
+ if (!name.endsWith(".stanzas") || name.includes("/") || name.includes("\\") || name.includes("\x00"))
3813
+ continue;
3814
+ writeFileSync9(join9(sealDir(solDir2), name), box, { mode: 384 });
3815
+ }
3706
3816
  updateHeadPin(solDir2);
3707
3817
  }
3708
- var creatorPinPath = (solDir2) => join9(envDir(solDir2), "creator.pin"), headPinPath = (solDir2) => join9(envDir(solDir2), "head.pin");
3818
+ var creatorPinPath = (solDir2) => join9(envDir(solDir2), "creator.pin"), headPinPath = (solDir2) => join9(envDir(solDir2), "head.pin"), ENVSTATE_SKIP_FILES;
3709
3819
  var init_anchor = __esm(() => {
3710
3820
  init_store2();
3711
3821
  init_journal();
3712
3822
  init_sign();
3823
+ ENVSTATE_SKIP_FILES = new Set(["journal.jsonl", "creator.pin", "head.pin"]);
3713
3824
  });
3714
3825
 
3715
3826
  // src/secret/toml.ts
@@ -4325,7 +4436,7 @@ var init_authz = __esm(() => {
4325
4436
  });
4326
4437
 
4327
4438
  // src/secret/model.ts
4328
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync10, statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
4439
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readdirSync as readdirSync4, readFileSync as readFileSync10, statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
4329
4440
  import { join as join10 } from "node:path";
4330
4441
  function envInitialized(solDir2) {
4331
4442
  return existsSync10(manifestPath(solDir2));
@@ -4362,8 +4473,8 @@ function audienceFor(world, env, entryAud) {
4362
4473
  return world.files[env]?.audience ?? [];
4363
4474
  }
4364
4475
  function ensureEnvDir(solDir2) {
4365
- mkdirSync5(envDir(solDir2), { recursive: true });
4366
- mkdirSync5(sealDir(solDir2), { recursive: true });
4476
+ mkdirSync6(envDir(solDir2), { recursive: true });
4477
+ mkdirSync6(sealDir(solDir2), { recursive: true });
4367
4478
  }
4368
4479
  function writeEnvFile(solDir2, f) {
4369
4480
  ensureEnvDir(solDir2);
@@ -4641,7 +4752,7 @@ function collectStaleStanzas(solDir2) {
4641
4752
  referenced.add(stanzaFileFor(e.newSeal));
4642
4753
  }
4643
4754
  const orphans = [];
4644
- for (const name of readdirSync3(dir)) {
4755
+ for (const name of readdirSync4(dir)) {
4645
4756
  if (!name.endsWith(".stanzas"))
4646
4757
  continue;
4647
4758
  if (!referenced.has(name))
@@ -5015,6 +5126,201 @@ var init_sealed_client = __esm(() => {
5015
5126
  init_crypto();
5016
5127
  });
5017
5128
 
5129
+ // src/bin/secret-scrub.ts
5130
+ var exports_secret_scrub = {};
5131
+ __export(exports_secret_scrub, {
5132
+ scrubHistory: () => scrubHistory,
5133
+ pendingScrubPaths: () => pendingScrubPaths,
5134
+ historyHasCleartext: () => historyHasCleartext,
5135
+ gcAfterScrub: () => gcAfterScrub,
5136
+ clearPendingScrub: () => clearPendingScrub,
5137
+ addPendingScrub: () => addPendingScrub
5138
+ });
5139
+ import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "node:fs";
5140
+ import { join as join11 } from "node:path";
5141
+ function pendingScrubPaths(solDir2) {
5142
+ const p = pendingPath(solDir2);
5143
+ if (!existsSync11(p))
5144
+ return [];
5145
+ try {
5146
+ const v = JSON.parse(readFileSync11(p, "utf8"));
5147
+ return Array.isArray(v) ? v : [];
5148
+ } catch {
5149
+ return [];
5150
+ }
5151
+ }
5152
+ function addPendingScrub(solDir2, path) {
5153
+ const set = new Set(pendingScrubPaths(solDir2));
5154
+ set.add(path);
5155
+ writeFileSync11(pendingPath(solDir2), JSON.stringify([...set], null, 2), { mode: 384 });
5156
+ }
5157
+ function clearPendingScrub(solDir2) {
5158
+ try {
5159
+ writeFileSync11(pendingPath(solDir2), JSON.stringify([], null, 2), { mode: 384 });
5160
+ } catch {}
5161
+ }
5162
+ function historyHasCleartext(solDir2, ops, path) {
5163
+ const store2 = new LazyStore(join11(solDir2, "objects"));
5164
+ for (const op of ops) {
5165
+ try {
5166
+ if (entryKindAt(store2, op.rootAfter, path) === "blob")
5167
+ return true;
5168
+ } catch {}
5169
+ }
5170
+ return false;
5171
+ }
5172
+ function currentSealedBox(store2, head, path) {
5173
+ try {
5174
+ return sealedBoxAt(store2, head, path);
5175
+ } catch {
5176
+ return;
5177
+ }
5178
+ }
5179
+ function replaceWithSealed(store2, treeHash, segs, sealedHash, mode, put) {
5180
+ const tree = store2.getTree(treeHash);
5181
+ const [head, ...rest] = segs;
5182
+ const entry = tree.entries[head];
5183
+ if (!entry)
5184
+ return treeHash;
5185
+ const entries = { ...tree.entries };
5186
+ if (rest.length === 0) {
5187
+ if (entry.kind !== "blob")
5188
+ return treeHash;
5189
+ entries[head] = mode === undefined ? { kind: "sealed", hash: sealedHash } : { kind: "sealed", hash: sealedHash, mode };
5190
+ } else {
5191
+ if (entry.kind !== "tree")
5192
+ return treeHash;
5193
+ const child = replaceWithSealed(store2, entry.hash, rest, sealedHash, mode, put);
5194
+ if (child === entry.hash)
5195
+ return treeHash;
5196
+ entries[head] = { kind: "tree", hash: child };
5197
+ }
5198
+ return put({ kind: "tree", entries });
5199
+ }
5200
+ async function scrubHistory(solDir2, ops, paths) {
5201
+ const objDir = join11(solDir2, "objects");
5202
+ const store2 = new LazyStore(objDir);
5203
+ const put = (n) => {
5204
+ const h = hashNode(n);
5205
+ store2.objects.set(h, n);
5206
+ writeFileSync11(join11(objDir, h), encodeObject(n));
5207
+ return h;
5208
+ };
5209
+ const head = (() => {
5210
+ const hp = join11(solDir2, "HEAD");
5211
+ return existsSync11(hp) ? JSON.parse(readFileSync11(hp, "utf8")).head : undefined;
5212
+ })();
5213
+ const sealedHashFor = new Map;
5214
+ for (const p of paths) {
5215
+ const box = head ? currentSealedBox(store2, head, p) : undefined;
5216
+ if (box === undefined)
5217
+ continue;
5218
+ const node = { kind: "sealed", box };
5219
+ const hash = put(node);
5220
+ let mode;
5221
+ try {
5222
+ mode = headMode(store2, head, p);
5223
+ } catch {}
5224
+ sealedHashFor.set(p, { hash, mode });
5225
+ }
5226
+ const rootMap = new Map;
5227
+ const newOps = [];
5228
+ let prevTip;
5229
+ let rewritten = 0;
5230
+ for (const op of ops) {
5231
+ let root = op.rootAfter;
5232
+ for (const [p, s] of sealedHashFor) {
5233
+ const segs = p.split("/").filter(Boolean);
5234
+ const next = replaceWithSealed(store2, root, segs, s.hash, s.mode, put);
5235
+ root = next;
5236
+ }
5237
+ const rootChanged = root !== op.rootAfter;
5238
+ rootMap.set(op.rootAfter, root);
5239
+ const remapped = { ...op, rootAfter: root };
5240
+ if (op.parent !== undefined && rootMap.has(op.parent))
5241
+ remapped.parent = rootMap.get(op.parent);
5242
+ if (op.parent2 !== undefined && rootMap.has(op.parent2))
5243
+ remapped.parent2 = rootMap.get(op.parent2);
5244
+ if (rootChanged) {
5245
+ delete remapped.sig;
5246
+ delete remapped.pub;
5247
+ delete remapped.att;
5248
+ rewritten++;
5249
+ }
5250
+ const { prevHash: _p, entryHash: _e, ...bare } = remapped;
5251
+ const chained = chainOp(prevTip, bare);
5252
+ newOps.push(chained);
5253
+ prevTip = chained.entryHash;
5254
+ }
5255
+ const last = newOps[newOps.length - 1];
5256
+ return {
5257
+ scrubbedPaths: [...sealedHashFor.keys()],
5258
+ rewrittenOps: rewritten,
5259
+ ops: newOps,
5260
+ newHead: last?.rootAfter,
5261
+ newSeq: last?.seq ?? 0,
5262
+ newLogTip: last?.entryHash,
5263
+ rootMap
5264
+ };
5265
+ }
5266
+ function gcAfterScrub(solDir2, ops) {
5267
+ const objDir = join11(solDir2, "objects");
5268
+ if (!existsSync11(objDir))
5269
+ return 0;
5270
+ const store2 = new LazyStore(objDir);
5271
+ const reachable = new Set;
5272
+ const walk = (h) => {
5273
+ if (reachable.has(h))
5274
+ return;
5275
+ const node = store2.get(h);
5276
+ if (!node)
5277
+ return;
5278
+ reachable.add(h);
5279
+ if (node.kind === "tree")
5280
+ for (const e of Object.values(node.entries))
5281
+ walk(e.hash);
5282
+ };
5283
+ for (const op of ops) {
5284
+ walk(op.rootAfter);
5285
+ if (op.prov)
5286
+ walk(op.prov);
5287
+ }
5288
+ let removed = 0;
5289
+ for (const name of readdirSync5(objDir)) {
5290
+ if (name.endsWith(".tmp") || !reachable.has(name)) {
5291
+ try {
5292
+ unlinkSync4(join11(objDir, name));
5293
+ removed++;
5294
+ } catch {}
5295
+ }
5296
+ }
5297
+ return removed;
5298
+ }
5299
+ function headMode(store2, root, path) {
5300
+ const segs = path.split("/").filter(Boolean);
5301
+ let cur = root;
5302
+ for (let i = 0;i < segs.length; i++) {
5303
+ const t = store2.getTree(cur);
5304
+ const e = t.entries[segs[i]];
5305
+ if (!e)
5306
+ return;
5307
+ if (i === segs.length - 1)
5308
+ return e.mode;
5309
+ if (e.kind !== "tree")
5310
+ return;
5311
+ cur = e.hash;
5312
+ }
5313
+ return;
5314
+ }
5315
+ var pendingPath = (solDir2) => join11(solDir2, "scrub-pending.json");
5316
+ var init_secret_scrub = __esm(() => {
5317
+ init_chain();
5318
+ init_file_store();
5319
+ init_store();
5320
+ init_tree();
5321
+ init_lib();
5322
+ });
5323
+
5018
5324
  // src/text-merge.ts
5019
5325
  function lines(s) {
5020
5326
  return s.split(`
@@ -5233,24 +5539,24 @@ __export(exports_local_peer, {
5233
5539
  openPeer: () => openPeer,
5234
5540
  localPeerSolDir: () => localPeerSolDir
5235
5541
  });
5236
- import { existsSync as existsSync11, readFileSync as readFileSync11 } from "node:fs";
5237
- import { join as join11, resolve as resolve2 } from "node:path";
5542
+ import { existsSync as existsSync12, readFileSync as readFileSync12 } from "node:fs";
5543
+ import { join as join12, resolve as resolve2 } from "node:path";
5238
5544
  function localPeerSolDir(arg, base) {
5239
5545
  if (/^https?:\/\//.test(arg))
5240
5546
  return;
5241
5547
  const p = resolve2(base, arg);
5242
- if (existsSync11(join11(p, ".sol")))
5243
- return join11(p, ".sol");
5244
- if (existsSync11(join11(p, "objects")) && existsSync11(join11(p, "HEAD")))
5548
+ if (existsSync12(join12(p, ".sol")))
5549
+ return join12(p, ".sol");
5550
+ if (existsSync12(join12(p, "objects")) && existsSync12(join12(p, "HEAD")))
5245
5551
  return p;
5246
5552
  return;
5247
5553
  }
5248
5554
  function openPeer(peerSolDir) {
5249
- const metaPath = join11(peerSolDir, "view.json");
5250
- if (existsSync11(metaPath)) {
5555
+ const metaPath = join12(peerSolDir, "view.json");
5556
+ if (existsSync12(metaPath)) {
5251
5557
  try {
5252
- const parent = resolve2(peerSolDir, JSON.parse(readFileSync11(metaPath, "utf8")).parent);
5253
- return { store: new FileStore(peerSolDir, join11(parent, "objects")), log: new FileOpLog(peerSolDir) };
5558
+ const parent = resolve2(peerSolDir, JSON.parse(readFileSync12(metaPath, "utf8")).parent);
5559
+ return { store: new FileStore(peerSolDir, join12(parent, "objects")), log: new FileOpLog(peerSolDir) };
5254
5560
  } catch {}
5255
5561
  }
5256
5562
  return { store: new FileStore(peerSolDir), log: new FileOpLog(peerSolDir) };
@@ -5515,9 +5821,9 @@ __export(exports_runtime, {
5515
5821
  hydrate: () => hydrate2,
5516
5822
  capture: () => capture
5517
5823
  });
5518
- import { chmodSync as chmodSync4, existsSync as existsSync12, lstatSync as lstatSync2, mkdirSync as mkdirSync6, readdirSync as readdirSync4, readFileSync as readFileSync12, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "node:fs";
5824
+ import { chmodSync as chmodSync4, existsSync as existsSync13, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readdirSync as readdirSync6, readFileSync as readFileSync13, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
5519
5825
  import { platform } from "node:os";
5520
- import { dirname as dirname3, join as join12, relative as relative2 } from "node:path";
5826
+ import { dirname as dirname3, join as join13, relative as relative2 } from "node:path";
5521
5827
  function isolateCommand(command, scratch) {
5522
5828
  if (platform() === "darwin") {
5523
5829
  const profile = [
@@ -5539,16 +5845,16 @@ function hydrate2(store2, head, dir) {
5539
5845
  const blob = fileAt(store2, head, p);
5540
5846
  if (!blob)
5541
5847
  continue;
5542
- const abs = join12(dir, p);
5543
- mkdirSync6(dirname3(abs), { recursive: true });
5848
+ const abs = join13(dir, p);
5849
+ mkdirSync7(dirname3(abs), { recursive: true });
5544
5850
  const mode = modeAt(store2, head, p);
5545
5851
  if (mode === SYMLINK_MODE2) {
5546
5852
  try {
5547
- unlinkSync4(abs);
5853
+ unlinkSync5(abs);
5548
5854
  } catch {}
5549
5855
  symlinkSync2(blob.content, abs);
5550
5856
  } else {
5551
- writeFileSync11(abs, blob.encoding === "base64" ? Buffer.from(blob.content, "base64") : blob.content);
5857
+ writeFileSync12(abs, blob.encoding === "base64" ? Buffer.from(blob.content, "base64") : blob.content);
5552
5858
  if (mode === EXEC_MODE2) {
5553
5859
  try {
5554
5860
  chmodSync4(abs, EXEC_MODE2);
@@ -5560,8 +5866,8 @@ function hydrate2(store2, head, dir) {
5560
5866
  return n;
5561
5867
  }
5562
5868
  function walkDir(dir, base, pats, out = []) {
5563
- for (const name of readdirSync4(dir)) {
5564
- const p = join12(dir, name);
5869
+ for (const name of readdirSync6(dir)) {
5870
+ const p = join13(dir, name);
5565
5871
  const rel = relative2(base, p);
5566
5872
  if (isIgnored(rel, pats))
5567
5873
  continue;
@@ -5579,11 +5885,11 @@ async function capture(repo, dir, keep = []) {
5579
5885
  const pats = ignorePatterns();
5580
5886
  const files = new Set(walkDir(dir, dir, pats));
5581
5887
  for (const k of keep)
5582
- if (existsSync12(join12(dir, k)))
5888
+ if (existsSync13(join13(dir, k)))
5583
5889
  files.add(k);
5584
5890
  const written = [];
5585
5891
  for (const f of files) {
5586
- const abs = join12(dir, f);
5892
+ const abs = join13(dir, f);
5587
5893
  const st = lstatSync2(abs);
5588
5894
  if (st.isSymbolicLink()) {
5589
5895
  const target = readlinkSync2(abs);
@@ -5594,7 +5900,7 @@ async function capture(repo, dir, keep = []) {
5594
5900
  }
5595
5901
  continue;
5596
5902
  }
5597
- const buf = readFileSync12(abs);
5903
+ const buf = readFileSync13(abs);
5598
5904
  if (buf.includes(0)) {
5599
5905
  const cur = await repo.readBytes(f);
5600
5906
  if (cur === undefined || cur === SEALED || !Buffer.from(cur).equals(buf)) {
@@ -5611,7 +5917,7 @@ async function capture(repo, dir, keep = []) {
5611
5917
  }
5612
5918
  const deleted = [];
5613
5919
  for (const t of await repo.list()) {
5614
- if (!existsSync12(join12(dir, t))) {
5920
+ if (!existsSync13(join13(dir, t))) {
5615
5921
  await repo.deleteFile(t);
5616
5922
  deleted.push(t);
5617
5923
  }
@@ -5725,8 +6031,8 @@ __export(exports_git_adapter, {
5725
6031
  exportHistoryToGit: () => exportHistoryToGit
5726
6032
  });
5727
6033
  import { execFileSync } from "node:child_process";
5728
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync13, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
5729
- import { join as join13 } from "node:path";
6034
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync14, unlinkSync as unlinkSync6, writeFileSync as writeFileSync13 } from "node:fs";
6035
+ import { join as join14 } from "node:path";
5730
6036
  import { deflateSync } from "node:zlib";
5731
6037
  async function importGitHead(gitPath, ws) {
5732
6038
  const listing = git(gitPath, "ls-tree", "-r", "-z", "HEAD").toString();
@@ -5794,9 +6100,9 @@ async function applyGitFile(repo, path, mode, content) {
5794
6100
  await repo.chmod(path, exec ? 493 : 420);
5795
6101
  }
5796
6102
  function setHead(fdir, head) {
5797
- const hf = join13(fdir, "HEAD");
5798
- const cur = existsSync13(hf) ? JSON.parse(readFileSync13(hf, "utf8")) : { seq: 0 };
5799
- writeFileSync12(hf, JSON.stringify({ ...cur, head }));
6103
+ const hf = join14(fdir, "HEAD");
6104
+ const cur = existsSync14(hf) ? JSON.parse(readFileSync14(hf, "utf8")) : { seq: 0 };
6105
+ writeFileSync13(hf, JSON.stringify({ ...cur, head }));
5800
6106
  }
5801
6107
  async function importGitRepo(gitPath, fdir) {
5802
6108
  const store2 = new FileStore(fdir);
@@ -5850,7 +6156,7 @@ function exportToGit(store2, head, gitPath, message) {
5850
6156
  for (const f of tracked) {
5851
6157
  if (!want.has(f)) {
5852
6158
  try {
5853
- unlinkSync5(join13(gitPath, f));
6159
+ unlinkSync6(join14(gitPath, f));
5854
6160
  } catch {}
5855
6161
  deleted++;
5856
6162
  }
@@ -5861,20 +6167,20 @@ function exportToGit(store2, head, gitPath, message) {
5861
6167
  return { written, deleted };
5862
6168
  }
5863
6169
  function gitObjectsDir(gitPath) {
5864
- for (const c of [join13(gitPath, ".git", "objects"), join13(gitPath, "objects")])
5865
- if (existsSync13(c))
6170
+ for (const c of [join14(gitPath, ".git", "objects"), join14(gitPath, "objects")])
6171
+ if (existsSync14(c))
5866
6172
  return c;
5867
6173
  return;
5868
6174
  }
5869
6175
  function writeLooseObject(objectsDir2, o) {
5870
- const dir = join13(objectsDir2, o.oid.slice(0, 2));
5871
- const file = join13(dir, o.oid.slice(2));
5872
- if (existsSync13(file))
6176
+ const dir = join14(objectsDir2, o.oid.slice(0, 2));
6177
+ const file = join14(dir, o.oid.slice(2));
6178
+ if (existsSync14(file))
5873
6179
  return;
5874
6180
  const header = Buffer.from(`${o.type} ${o.content.length}\x00`);
5875
6181
  const framed = Buffer.concat([header, Buffer.from(o.content)]);
5876
- mkdirSync7(dir, { recursive: true });
5877
- writeFileSync12(file, deflateSync(framed));
6182
+ mkdirSync8(dir, { recursive: true });
6183
+ writeFileSync13(file, deflateSync(framed));
5878
6184
  }
5879
6185
  function exportAncestry(ops) {
5880
6186
  const parents = new Map;
@@ -5986,31 +6292,31 @@ __export(exports_views, {
5986
6292
  loadViewsRegistry: () => loadViewsRegistry,
5987
6293
  createView: () => createView
5988
6294
  });
5989
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync14, rmSync, writeFileSync as writeFileSync13 } from "node:fs";
5990
- import { join as join14, relative as relative3, resolve as resolve3 } from "node:path";
6295
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync15, rmSync, writeFileSync as writeFileSync14 } from "node:fs";
6296
+ import { join as join15, relative as relative3, resolve as resolve3 } from "node:path";
5991
6297
  function loadViewsRegistry(parentSol) {
5992
6298
  const p = viewsRegistryPath(parentSol);
5993
- if (!existsSync14(p))
6299
+ if (!existsSync15(p))
5994
6300
  return { views: [] };
5995
6301
  try {
5996
- return JSON.parse(readFileSync14(p, "utf8"));
6302
+ return JSON.parse(readFileSync15(p, "utf8"));
5997
6303
  } catch {
5998
6304
  return { views: [] };
5999
6305
  }
6000
6306
  }
6001
6307
  function saveViewsRegistry(parentSol, reg) {
6002
- writeFileSync13(viewsRegistryPath(parentSol), JSON.stringify(reg, null, 2));
6308
+ writeFileSync14(viewsRegistryPath(parentSol), JSON.stringify(reg, null, 2));
6003
6309
  }
6004
6310
  function createView(opts) {
6005
6311
  const { parentSol, viewDir, name, branch, actor: actor2, startHead } = opts;
6006
- const viewSol = join14(viewDir, ".sol");
6007
- mkdirSync8(viewSol, { recursive: true });
6312
+ const viewSol = join15(viewDir, ".sol");
6313
+ mkdirSync9(viewSol, { recursive: true });
6008
6314
  const meta = { parent: relative3(viewSol, parentSol), name, branch, actor: actor2, startHead, createdAt: Date.now() };
6009
- writeFileSync13(join14(viewSol, "view.json"), JSON.stringify(meta, null, 2));
6010
- writeFileSync13(join14(viewSol, "HEAD"), JSON.stringify({ head: startHead, seq: 0 }));
6315
+ writeFileSync14(join15(viewSol, "view.json"), JSON.stringify(meta, null, 2));
6316
+ writeFileSync14(join15(viewSol, "HEAD"), JSON.stringify({ head: startHead, seq: 0 }));
6011
6317
  const refs = { current: branch, branches: { [branch]: { head: startHead, base: startHead } }, tags: {} };
6012
- writeFileSync13(join14(viewSol, "refs.json"), JSON.stringify(refs, null, 2));
6013
- const store2 = new LazyStore(join14(parentSol, "objects"));
6318
+ writeFileSync14(join15(viewSol, "refs.json"), JSON.stringify(refs, null, 2));
6319
+ const store2 = new LazyStore(join15(parentSol, "objects"));
6014
6320
  const paths = (startHead ? listAll(store2, startHead) : []).filter((p) => !p.split("/").some(isReservedKey));
6015
6321
  for (const f of paths)
6016
6322
  materializeInto(store2, startHead, viewDir, f);
@@ -6025,8 +6331,8 @@ async function viewStatuses(parentSol) {
6025
6331
  const reg = loadViewsRegistry(parentSol);
6026
6332
  const out = [];
6027
6333
  for (const v of reg.views) {
6028
- const viewSol = join14(v.dir, ".sol");
6029
- const exists = existsSync14(join14(viewSol, "view.json"));
6334
+ const viewSol = join15(v.dir, ".sol");
6335
+ const exists = existsSync15(join15(viewSol, "view.json"));
6030
6336
  let head;
6031
6337
  if (exists) {
6032
6338
  head = await new FileOpLog(viewSol).head();
@@ -6050,7 +6356,7 @@ function pruneViews(parentSol, opts = {}) {
6050
6356
  const reg = loadViewsRegistry(parentSol);
6051
6357
  const removed = [];
6052
6358
  reg.views = reg.views.filter((v) => {
6053
- const present = existsSync14(join14(v.dir, ".sol", "view.json"));
6359
+ const present = existsSync15(join15(v.dir, ".sol", "view.json"));
6054
6360
  const target = opts.name ? v.name === opts.name : !present;
6055
6361
  if (!target)
6056
6362
  return true;
@@ -6066,12 +6372,12 @@ function pruneViews(parentSol, opts = {}) {
6066
6372
  return removed;
6067
6373
  }
6068
6374
  function sharedObjectCount(parentSol) {
6069
- const dir = join14(parentSol, "objects");
6070
- if (!existsSync14(dir))
6375
+ const dir = join15(parentSol, "objects");
6376
+ if (!existsSync15(dir))
6071
6377
  return 0;
6072
- return readdirSync5(dir).filter((n) => !n.endsWith(".tmp")).length;
6378
+ return readdirSync7(dir).filter((n) => !n.endsWith(".tmp")).length;
6073
6379
  }
6074
- var viewsRegistryPath = (parentSol) => join14(parentSol, "views.json");
6380
+ var viewsRegistryPath = (parentSol) => join15(parentSol, "views.json");
6075
6381
  var init_views = __esm(() => {
6076
6382
  init_file_store();
6077
6383
  init_struct();
@@ -6511,7 +6817,7 @@ __export(exports_secret2, {
6511
6817
  runEnv: () => runEnv,
6512
6818
  resolveReference: () => resolveReference
6513
6819
  });
6514
- import { readFileSync as readFileSync15, readSync, writeSync } from "node:fs";
6820
+ import { readFileSync as readFileSync16, readSync, writeSync } from "node:fs";
6515
6821
  import { spawnSync as spawnSync2 } from "node:child_process";
6516
6822
  function flag(args, name) {
6517
6823
  const i = args.indexOf(name);
@@ -6883,7 +7189,7 @@ async function envValidate(ctx, args, json) {
6883
7189
  }
6884
7190
  function readSchemaText(solDir2) {
6885
7191
  try {
6886
- return readFileSync15(schemaLockPath(solDir2), "utf8");
7192
+ return readFileSync16(schemaLockPath(solDir2), "utf8");
6887
7193
  } catch {
6888
7194
  return;
6889
7195
  }
@@ -7558,14 +7864,14 @@ var exports_sol_secret_mcp = {};
7558
7864
  __export(exports_sol_secret_mcp, {
7559
7865
  startSecretMcp: () => startSecretMcp
7560
7866
  });
7561
- import { existsSync as existsSync15 } from "node:fs";
7562
- import { join as join15 } from "node:path";
7867
+ import { existsSync as existsSync16 } from "node:fs";
7868
+ import { join as join16 } from "node:path";
7563
7869
  async function startSecretMcp(opts = {}) {
7564
7870
  const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
7565
7871
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
7566
7872
  const { CallToolRequestSchema, ListToolsRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
7567
- const solDir2 = opts.solDir || process.env.SOL_DIR || join15(process.cwd(), ".sol");
7568
- if (!existsSync15(solDir2)) {
7873
+ const solDir2 = opts.solDir || process.env.SOL_DIR || join16(process.cwd(), ".sol");
7874
+ if (!existsSync16(solDir2)) {
7569
7875
  process.stderr.write(`sol-secret-mcp: no .sol at ${solDir2} — run \`sol init\` first (or set SOL_DIR)
7570
7876
  `);
7571
7877
  process.exit(1);
@@ -7719,8 +8025,8 @@ var exports_sol_mcp = {};
7719
8025
  __export(exports_sol_mcp, {
7720
8026
  startWorkspaceMcp: () => startWorkspaceMcp
7721
8027
  });
7722
- import { mkdirSync as mkdirSync9 } from "node:fs";
7723
- import { join as join16 } from "node:path";
8028
+ import { mkdirSync as mkdirSync10 } from "node:fs";
8029
+ import { join as join17 } from "node:path";
7724
8030
  async function handle(ws, name, a) {
7725
8031
  switch (name) {
7726
8032
  case "sol_write":
@@ -7762,8 +8068,8 @@ async function startWorkspaceMcp(opts = {}) {
7762
8068
  const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
7763
8069
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
7764
8070
  const { CallToolRequestSchema, ListToolsRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
7765
- const solDir2 = opts.solDir || process.env.SOL_DIR || join16(process.cwd(), ".sol");
7766
- mkdirSync9(solDir2, { recursive: true });
8071
+ const solDir2 = opts.solDir || process.env.SOL_DIR || join17(process.cwd(), ".sol");
8072
+ mkdirSync10(solDir2, { recursive: true });
7767
8073
  const ws = new SolWorkspace(new FileStore(solDir2), new FileOpLog(solDir2), process.env.SOL_ACTOR || "agent");
7768
8074
  const server = new Server({ name: "sol", version: "0.1.0" }, { capabilities: { tools: {} } });
7769
8075
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
@@ -7800,9 +8106,9 @@ __export(exports_dispatch, {
7800
8106
  dispatch: () => dispatch
7801
8107
  });
7802
8108
  import { execFileSync as execFileSync2 } from "node:child_process";
7803
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync16, rmSync as rmSync2, unlinkSync as unlinkSync6, watch, writeFileSync as writeFileSync14 } from "node:fs";
8109
+ import { existsSync as existsSync17, mkdirSync as mkdirSync11, mkdtempSync, readdirSync as readdirSync8, readFileSync as readFileSync17, rmSync as rmSync2, unlinkSync as unlinkSync7, watch, writeFileSync as writeFileSync15 } from "node:fs";
7804
8110
  import { homedir as homedir2, hostname, platform as platform2, tmpdir } from "node:os";
7805
- import { basename, dirname as dirname4, join as join17, resolve as resolve4, sep as sep2 } from "node:path";
8111
+ import { basename, dirname as dirname4, join as join18, resolve as resolve4, sep as sep2 } from "node:path";
7806
8112
  function globCovers(pattern, path) {
7807
8113
  let re = "";
7808
8114
  for (let i = 0;i < pattern.length; i++) {
@@ -7830,11 +8136,11 @@ function tokenClaims(token) {
7830
8136
  }
7831
8137
  }
7832
8138
  async function loadStoredToken() {
7833
- if (!existsSync16(CRED_PATH))
8139
+ if (!existsSync17(CRED_PATH))
7834
8140
  return;
7835
8141
  let creds;
7836
8142
  try {
7837
- creds = JSON.parse(readFileSync16(CRED_PATH, "utf8"));
8143
+ creds = JSON.parse(readFileSync17(CRED_PATH, "utf8"));
7838
8144
  } catch {
7839
8145
  return;
7840
8146
  }
@@ -7849,7 +8155,7 @@ async function loadStoredToken() {
7849
8155
  if (res.ok) {
7850
8156
  const r = await res.json();
7851
8157
  if (r.accessToken) {
7852
- writeFileSync14(CRED_PATH, JSON.stringify({ ...creds, accessToken: r.accessToken, refreshToken: r.refreshToken ?? creds.refreshToken }, null, 2), { mode: 384 });
8158
+ writeFileSync15(CRED_PATH, JSON.stringify({ ...creds, accessToken: r.accessToken, refreshToken: r.refreshToken ?? creds.refreshToken }, null, 2), { mode: 384 });
7853
8159
  return r.accessToken;
7854
8160
  }
7855
8161
  }
@@ -7870,7 +8176,7 @@ function authHost() {
7870
8176
  if (process.env.SOL_AUTH)
7871
8177
  return process.env.SOL_AUTH.replace(/\/+$/, "");
7872
8178
  try {
7873
- const w = JSON.parse(readFileSync16(CRED_PATH, "utf8")).webUrl;
8179
+ const w = JSON.parse(readFileSync17(CRED_PATH, "utf8")).webUrl;
7874
8180
  if (w)
7875
8181
  return w.replace(/\/+$/, "");
7876
8182
  } catch {}
@@ -7931,7 +8237,7 @@ function cliVersion() {
7931
8237
  if (typeof __SOL_COMPILED_VERSION__ === "string" && __SOL_COMPILED_VERSION__)
7932
8238
  return __SOL_COMPILED_VERSION__;
7933
8239
  try {
7934
- return JSON.parse(readFileSync16(new URL("./package.json", import.meta.url), "utf8")).version || "dev";
8240
+ return JSON.parse(readFileSync17(new URL("./package.json", import.meta.url), "utf8")).version || "dev";
7935
8241
  } catch {
7936
8242
  return "dev";
7937
8243
  }
@@ -8461,7 +8767,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8461
8767
  try {
8462
8768
  const { loadSelfIdentity: loadSelfIdentity2 } = await Promise.resolve().then(() => (init_seal_audience(), exports_seal_audience));
8463
8769
  const { openContent: openContent2 } = await Promise.resolve().then(() => (init_crypto(), exports_crypto));
8464
- const ring = existsSync16(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
8770
+ const ring = existsSync17(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
8465
8771
  const self = loadSelfIdentity2();
8466
8772
  setSealedDecryptor((boxStr) => {
8467
8773
  const box = JSON.parse(boxStr);
@@ -8471,19 +8777,19 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8471
8777
  } catch {}
8472
8778
  }
8473
8779
  const servesMcp = cmd === "mcp" || cmd === "secret" && args[0] === "mcp";
8474
- const release = !servesMcp && new Set(["add", "track", "commit", "checkpoint", "rm", "gc", "branch", "tag", "switch", "merge", "undo", "revert", "pull", "push", "restore", "checkout", "run", "seal", "view", "env", "secret"]).has(cmd) && existsSync16(solDir) ? acquireLock() : undefined;
8780
+ const release = !servesMcp && new Set(["add", "track", "commit", "checkpoint", "rm", "gc", "branch", "tag", "switch", "merge", "undo", "revert", "pull", "push", "restore", "checkout", "run", "seal", "view", "env", "secret"]).has(cmd) && existsSync17(solDir) ? acquireLock() : undefined;
8475
8781
  try {
8476
8782
  switch (cmd) {
8477
8783
  case "init": {
8478
- const here = join17(procCwd, ".sol");
8479
- if (existsSync16(here))
8784
+ const here = join18(procCwd, ".sol");
8785
+ if (existsSync17(here))
8480
8786
  die("already a sol repo: " + procCwd);
8481
8787
  if (repoRoot && repoRoot !== procCwd && !args.includes("--force")) {
8482
8788
  die(`already inside a Sol repo at ${repoRoot}
8483
8789
  -> just commit into it: \`sol commit ...\` works from here (sol walks up to find the repo)
8484
8790
  -> to nest a NEW repo here anyway: \`sol init --force\``);
8485
8791
  }
8486
- mkdirSync10(here, { recursive: true });
8792
+ mkdirSync11(here, { recursive: true });
8487
8793
  new FileStore(here);
8488
8794
  console.log(`initialized empty sol repo in ${here}`);
8489
8795
  break;
@@ -8599,7 +8905,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8599
8905
  if (sub === "import") {
8600
8906
  const passphrase = process.env.SOL_KEYSTORE_PASSPHRASE || die("set SOL_KEYSTORE_PASSPHRASE to decrypt the bundle");
8601
8907
  const file = args[1] || die("usage: sol keys import <bundle.json> (set SOL_KEYSTORE_PASSPHRASE)");
8602
- const bundle = JSON.parse(readFileSync16(file, "utf8"));
8908
+ const bundle = JSON.parse(readFileSync17(file, "utf8"));
8603
8909
  let recovered;
8604
8910
  try {
8605
8911
  recovered = importBundle2(bundle, passphrase);
@@ -8630,7 +8936,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8630
8936
  break;
8631
8937
  }
8632
8938
  case "trust": {
8633
- if (!existsSync16(solDir))
8939
+ if (!existsSync17(solDir))
8634
8940
  die("not a sol repo — run `sol init` first");
8635
8941
  const map = loadTrust();
8636
8942
  if (args[0] === "--remove" || args[0] === "-r") {
@@ -8677,7 +8983,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8677
8983
  }
8678
8984
  case "track":
8679
8985
  case "add": {
8680
- if (!existsSync16(solDir))
8986
+ if (!existsSync17(solDir))
8681
8987
  die("not a sol repo — run `sol init` first");
8682
8988
  const files = args.filter((a) => a !== "." && !a.startsWith("-"));
8683
8989
  if (!files.length) {
@@ -8688,7 +8994,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8688
8994
  let n = 0;
8689
8995
  for (const f of files) {
8690
8996
  const rf = repoRel(f);
8691
- if (!existsSync16(join17(cwd, rf))) {
8997
+ if (!existsSync17(join18(cwd, rf))) {
8692
8998
  console.error("skip (not on disk): " + f);
8693
8999
  continue;
8694
9000
  }
@@ -8717,14 +9023,14 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8717
9023
  if (!message)
8718
9024
  die('commit needs a message: sol commit "what you did" (scoped: sol commit -m "msg" file1 file2)');
8719
9025
  const parentHead = await repo.head();
8720
- const mergeHeadPath = join17(solDir, "MERGE_HEAD");
8721
- const parent2 = existsSync16(mergeHeadPath) ? readFileSync16(mergeHeadPath, "utf8").trim() || undefined : undefined;
9026
+ const mergeHeadPath = join18(solDir, "MERGE_HEAD");
9027
+ const parent2 = existsSync17(mergeHeadPath) ? readFileSync17(mergeHeadPath, "utf8").trim() || undefined : undefined;
8722
9028
  let changed = 0;
8723
9029
  let commitRoot = parentHead;
8724
9030
  if (paths.length) {
8725
9031
  for (const p of paths) {
8726
9032
  const rp = repoRel(p);
8727
- if (existsSync16(join17(cwd, rp))) {
9033
+ if (existsSync17(join18(cwd, rp))) {
8728
9034
  if (await snapshotFile(repo, rp))
8729
9035
  changed++;
8730
9036
  } else if ((await repo.list()).includes(rp)) {
@@ -8766,7 +9072,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8766
9072
  await appendCommit(log, commitRoot, message, parentHead, parent2);
8767
9073
  if (parent2) {
8768
9074
  try {
8769
- unlinkSync6(mergeHeadPath);
9075
+ unlinkSync7(mergeHeadPath);
8770
9076
  } catch {}
8771
9077
  }
8772
9078
  const refs = await loadRefs(log);
@@ -8779,7 +9085,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8779
9085
  }
8780
9086
  case "status": {
8781
9087
  const { repo, log } = open();
8782
- const refs = existsSync16(refsPath()) ? await loadRefs(log) : undefined;
9088
+ const refs = existsSync17(refsPath()) ? await loadRefs(log) : undefined;
8783
9089
  const head = await repo.head();
8784
9090
  const headOp = head ? [...await log.history()].reverse().find((o) => o.rootAfter === head) : undefined;
8785
9091
  const headBy = headOp?.by ?? "?";
@@ -8869,7 +9175,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8869
9175
  const { listAll: listAll3 } = await Promise.resolve().then(() => (init_tree(), exports_tree));
8870
9176
  const { loadSelfIdentity: loadSelfIdentity2 } = await Promise.resolve().then(() => (init_seal_audience(), exports_seal_audience));
8871
9177
  const { openContent: openContent2, UNREADABLE: UNREADABLE2 } = await Promise.resolve().then(() => (init_crypto(), exports_crypto));
8872
- const ring = existsSync16(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
9178
+ const ring = existsSync17(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
8873
9179
  const self = loadSelfIdentity2();
8874
9180
  const decrypt = (boxStr) => {
8875
9181
  try {
@@ -8917,7 +9223,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
8917
9223
  const { readFile: readTree, entryKindAt: kindAt } = await Promise.resolve().then(() => (init_tree(), exports_tree));
8918
9224
  const { loadSelfIdentity: loadSelfIdentity2 } = await Promise.resolve().then(() => (init_seal_audience(), exports_seal_audience));
8919
9225
  const { openContent: openContent2, UNREADABLE: UNREADABLE2, KeyRing: KeyRing3 } = await Promise.resolve().then(() => (init_crypto(), exports_crypto));
8920
- const ring = existsSync16(solDir) ? loadKeyRing() : new KeyRing3;
9226
+ const ring = existsSync17(solDir) ? loadKeyRing() : new KeyRing3;
8921
9227
  const self = loadSelfIdentity2();
8922
9228
  const decrypt = (boxStr) => {
8923
9229
  try {
@@ -9016,7 +9322,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9016
9322
  };
9017
9323
  const live = await log.head() ?? "";
9018
9324
  const refArg = args.find((a) => !a.startsWith("-"));
9019
- const lrefs = existsSync16(refsPath()) ? JSON.parse(readFileSync16(refsPath(), "utf8")) : null;
9325
+ const lrefs = existsSync17(refsPath()) ? JSON.parse(readFileSync17(refsPath(), "utf8")) : null;
9020
9326
  let tipRoot = live;
9021
9327
  if (refArg) {
9022
9328
  tipRoot = lrefs?.branches[refArg]?.head ?? refArg;
@@ -9069,7 +9375,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9069
9375
  const path = args[0] || die("rm needs a path");
9070
9376
  let onDisk = false;
9071
9377
  try {
9072
- unlinkSync6(join17(cwd, path));
9378
+ unlinkSync7(join18(cwd, path));
9073
9379
  onDisk = true;
9074
9380
  } catch {}
9075
9381
  if (onDisk) {
@@ -9297,16 +9603,16 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9297
9603
  if (op.prov)
9298
9604
  walk(op.prov);
9299
9605
  }
9300
- const objDir = join17(solDir, "objects");
9606
+ const objDir = join18(solDir, "objects");
9301
9607
  let removed = 0;
9302
- for (const name of readdirSync6(objDir)) {
9608
+ for (const name of readdirSync8(objDir)) {
9303
9609
  if (name.endsWith(".tmp") || !reachable.has(name)) {
9304
- unlinkSync6(join17(objDir, name));
9610
+ unlinkSync7(join18(objDir, name));
9305
9611
  removed++;
9306
9612
  }
9307
9613
  }
9308
9614
  console.log(`gc: kept ${reachable.size} object(s), removed ${removed} unreachable`);
9309
- if (existsSync16(join17(solDir, "env", "seal"))) {
9615
+ if (existsSync17(join18(solDir, "env", "seal"))) {
9310
9616
  const { gcStaleStanzas: gcStaleStanzas2 } = await Promise.resolve().then(() => (init_secret(), exports_secret));
9311
9617
  const st = gcStaleStanzas2(solDir);
9312
9618
  if (st.removed)
@@ -9321,8 +9627,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9321
9627
  console.log(p);
9322
9628
  break;
9323
9629
  }
9324
- const f = join17(cwd, ".solignore");
9325
- const lead = existsSync16(f) && !readFileSync16(f, "utf8").endsWith(`
9630
+ const f = join18(cwd, ".solignore");
9631
+ const lead = existsSync17(f) && !readFileSync17(f, "utf8").endsWith(`
9326
9632
  `) ? `
9327
9633
  ` : "";
9328
9634
  appendFileSync2(f, lead + pat + `
@@ -9423,6 +9729,48 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9423
9729
  const wantJson = args.includes("--json");
9424
9730
  const reapply = args.includes("--reapply");
9425
9731
  const positional = args.filter((a) => !a.startsWith("-"));
9732
+ if (args.includes("--scrub-history")) {
9733
+ const { pendingScrubPaths: pendingScrubPaths2, historyHasCleartext: historyHasCleartext2, scrubHistory: scrubHistory2, clearPendingScrub: clearPendingScrub2, gcAfterScrub: gcAfterScrub2 } = await Promise.resolve().then(() => (init_secret_scrub(), exports_secret_scrub));
9734
+ const ops = await log.history();
9735
+ const only = positional[0];
9736
+ const targets = (only ? [only] : pendingScrubPaths2(solDir)).filter((p) => historyHasCleartext2(solDir, ops, p));
9737
+ if (!targets.length) {
9738
+ if (only)
9739
+ die(`no pre-seal cleartext in history for "${only}" — nothing to scrub (it was never committed in the clear, or is already scrubbed).`);
9740
+ clearPendingScrub2(solDir);
9741
+ console.log(wantJson ? JSON.stringify({ scrubbed: [], rewrittenOps: 0 }) : "no paths with recoverable pre-seal cleartext — nothing to scrub.");
9742
+ break;
9743
+ }
9744
+ let removed = 0;
9745
+ {
9746
+ const res = await scrubHistory2(solDir, ops, targets);
9747
+ writeFileSync15(join18(solDir, "ops.jsonl"), res.ops.map((o) => JSON.stringify(o)).join(`
9748
+ `) + (res.ops.length ? `
9749
+ ` : ""));
9750
+ writeFileSync15(join18(solDir, "HEAD"), JSON.stringify({ head: res.newHead, seq: res.newSeq, logTip: res.newLogTip }));
9751
+ if (existsSync17(refsPath())) {
9752
+ const refs = JSON.parse(readFileSync17(refsPath(), "utf8"));
9753
+ for (const b of Object.values(refs.branches)) {
9754
+ if (b.head && res.rootMap.has(b.head))
9755
+ b.head = res.rootMap.get(b.head);
9756
+ if (b.base && res.rootMap.has(b.base))
9757
+ b.base = res.rootMap.get(b.base);
9758
+ if (b.remote && res.rootMap.has(b.remote))
9759
+ b.remote = res.rootMap.get(b.remote);
9760
+ }
9761
+ saveRefs(refs);
9762
+ }
9763
+ removed = gcAfterScrub2(solDir, res.ops);
9764
+ clearPendingScrub2(solDir);
9765
+ }
9766
+ if (wantJson) {
9767
+ console.log(JSON.stringify({ scrubbed: targets, removedObjects: removed }));
9768
+ break;
9769
+ }
9770
+ console.log(`scrubbed pre-seal cleartext from history for: ${targets.join(", ")} — the op-log was rewritten and ${removed} orphaned cleartext object(s) dropped (\`sol restore\` can no longer recover them); push is unblocked.`);
9771
+ console.log(" NOTE: this is a DESTRUCTIVE local history rewrite. collaborators who already pulled the old history must re-clone.");
9772
+ break;
9773
+ }
9426
9774
  if (reapply) {
9427
9775
  const cfg = resolveRemote(solDir) || die("no remote — the policy lives on the repo; `sol remote <url> <repo>` first");
9428
9776
  const token = process.env.SOL_TOKEN || authExpired();
@@ -9559,10 +9907,10 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9559
9907
  if (content === SEALED && !args.includes("--hide-names"))
9560
9908
  die("already sealed: " + path);
9561
9909
  if (content === undefined) {
9562
- const abs = join17(cwd, path);
9563
- if (!existsSync16(abs))
9910
+ const abs = join18(cwd, path);
9911
+ if (!existsSync17(abs))
9564
9912
  die("no such file: " + path);
9565
- content = readFileSync16(abs, "utf8");
9913
+ content = readFileSync17(abs, "utf8");
9566
9914
  }
9567
9915
  const ring = loadKeyRing();
9568
9916
  const { SealedClient: SealedClient2 } = await Promise.resolve().then(() => (init_sealed_client(), exports_sealed_client));
@@ -9744,6 +10092,18 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9744
10092
  recordAudience2(solDir, { path, epoch: 1, at: Date.now(), accounts: [], local: [...localRecipients] });
9745
10093
  }
9746
10094
  saveKeyRing(ring);
10095
+ if (onTree !== undefined && onTree !== SEALED) {
10096
+ const { historyHasCleartext: historyHasCleartext2, addPendingScrub: addPendingScrub2 } = await Promise.resolve().then(() => (init_secret_scrub(), exports_secret_scrub));
10097
+ if (historyHasCleartext2(solDir, await log.history(), path)) {
10098
+ addPendingScrub2(solDir, path);
10099
+ if (!wantJson) {
10100
+ console.error(`
10101
+ WARNING: "${path}" was committed as PLAINTEXT before this seal — the pre-seal cleartext is STILL recoverable from history (\`sol restore\`) and would ship to every clone on push.`);
10102
+ console.error(` push is now BLOCKED for safety. run \`sol seal ${path} --scrub-history\` to rewrite it out of history, then push.
10103
+ `);
10104
+ }
10105
+ }
10106
+ }
9747
10107
  }
9748
10108
  if (wantHideName) {
9749
10109
  const { slotForPath: slotForPath2, recordNameSlot: recordNameSlot2, recordHiddenPath: recordHiddenPath2 } = await Promise.resolve().then(() => (init_seal_audience(), exports_seal_audience));
@@ -9843,7 +10203,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
9843
10203
  const { openContent: openContent2, UNREADABLE: UNREADABLE2 } = await Promise.resolve().then(() => (init_crypto(), exports_crypto));
9844
10204
  const { parseStruct: parseStruct2 } = await Promise.resolve().then(() => (init_struct(), exports_struct));
9845
10205
  const audiences = loadAudiences2(solDir);
9846
- const ring = existsSync16(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
10206
+ const ring = existsSync17(solDir) ? loadKeyRing() : new (await Promise.resolve().then(() => (init_crypto(), exports_crypto))).KeyRing;
9847
10207
  const self = loadSelfIdentity2();
9848
10208
  const levelOf = (boxStr) => {
9849
10209
  try {
@@ -10038,7 +10398,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10038
10398
  const result = merge2({ store: store2 }, other.base, ours, other.head);
10039
10399
  if (result.conflicts.length) {
10040
10400
  materializeTree(store2, result.head);
10041
- writeFileSync14(join17(solDir, "MERGE_HEAD"), other.head);
10401
+ writeFileSync15(join18(solDir, "MERGE_HEAD"), other.head);
10042
10402
  saveMergeConflicts(solDir, result.conflicts);
10043
10403
  console.log(`merge ${name} -> ${result.conflicts.length} conflict(s), left in your working tree (uncommitted):`);
10044
10404
  for (const c of result.conflicts)
@@ -10139,7 +10499,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10139
10499
  break;
10140
10500
  }
10141
10501
  case "remote": {
10142
- if (!existsSync16(solDir))
10502
+ if (!existsSync17(solDir))
10143
10503
  die("not a sol repo");
10144
10504
  if (args[0]) {
10145
10505
  const repoName = args[1] || die("usage: sol remote <url> <repo>");
@@ -10185,16 +10545,16 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10185
10545
  }
10186
10546
  if (!tokens)
10187
10547
  die("timed out waiting for approval");
10188
- mkdirSync10(dirname4(CRED_PATH), { recursive: true });
10189
- writeFileSync14(CRED_PATH, JSON.stringify({ webUrl, ...tokens }, null, 2), { mode: 384 });
10548
+ mkdirSync11(dirname4(CRED_PATH), { recursive: true });
10549
+ writeFileSync15(CRED_PATH, JSON.stringify({ webUrl, ...tokens }, null, 2), { mode: 384 });
10190
10550
  const c = tokenClaims(tokens.accessToken);
10191
10551
  console.log(`
10192
10552
  Logged in as ${c.handle ? `@${c.handle}` : c.email || "user"}.`);
10193
10553
  if (!c.handle)
10194
10554
  console.log(" (no handle yet — set one in the web app to get your <handle>/<repo> namespace)");
10195
10555
  } else if (sub === "logout") {
10196
- if (existsSync16(CRED_PATH))
10197
- unlinkSync6(CRED_PATH);
10556
+ if (existsSync17(CRED_PATH))
10557
+ unlinkSync7(CRED_PATH);
10198
10558
  console.log("logged out");
10199
10559
  } else if (sub === "status" || !sub) {
10200
10560
  if (process.env.SOL_TOKEN) {
@@ -10202,11 +10562,11 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10202
10562
  console.log(`authenticated via SOL_TOKEN (env)${c2.handle ? ` as @${c2.handle}` : ""}`);
10203
10563
  break;
10204
10564
  }
10205
- if (!existsSync16(CRED_PATH)) {
10565
+ if (!existsSync17(CRED_PATH)) {
10206
10566
  console.log("not logged in — run `sol auth login` (or set SOL_TOKEN)");
10207
10567
  break;
10208
10568
  }
10209
- const creds = JSON.parse(readFileSync16(CRED_PATH, "utf8"));
10569
+ const creds = JSON.parse(readFileSync17(CRED_PATH, "utf8"));
10210
10570
  const c = tokenClaims(creds.accessToken || "");
10211
10571
  const stale = typeof c.exp === "number" && c.exp * 1000 < Date.now();
10212
10572
  console.log(`logged in as ${c.handle ? `@${c.handle}` : c.email || "user"} via ${creds.webUrl}${stale ? " (token stale — refreshes on next use)" : ""}`);
@@ -10256,9 +10616,9 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10256
10616
  console.log("heads-up: changing your handle re-namespaces your repos under the new <handle>/<repo>.");
10257
10617
  console.log(`handle set to @${out.handle}`);
10258
10618
  } else if (sub === "pat") {
10259
- if (!existsSync16(CRED_PATH))
10619
+ if (!existsSync17(CRED_PATH))
10260
10620
  die("run `sol auth login` first");
10261
- const creds = JSON.parse(readFileSync16(CRED_PATH, "utf8"));
10621
+ const creds = JSON.parse(readFileSync17(CRED_PATH, "utf8"));
10262
10622
  const token = await loadStoredToken();
10263
10623
  if (!token || !creds.webUrl)
10264
10624
  die("run `sol auth login` first");
@@ -10317,10 +10677,10 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10317
10677
  const peer = openPeer2(localSrc);
10318
10678
  const peerHead = await peer.log.head();
10319
10679
  const dest = resolve4(procCwd, args[1] || (args[0].replace(/\/+$/, "").split("/").pop() || "clone") + "-clone");
10320
- const ddir = join17(dest, ".sol");
10321
- if (existsSync16(ddir))
10680
+ const ddir = join18(dest, ".sol");
10681
+ if (existsSync17(ddir))
10322
10682
  die("already a sol repo: " + dest);
10323
- mkdirSync10(ddir, { recursive: true });
10683
+ mkdirSync11(ddir, { recursive: true });
10324
10684
  const peerOps = await peer.log.history();
10325
10685
  const res = await converge2({ store: new FileStore(ddir), log: new FileOpLog(ddir) }, { nodes: await peerNodes2(peer, peerHead, peerOps), ops: peerOps, incomingHead: peerHead, actor });
10326
10686
  const dstore = new Store;
@@ -10330,7 +10690,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10330
10690
  const files = (res.head ? listAll(dstore, res.head) : []).filter((f) => !f.split("/").some(isReservedKey2));
10331
10691
  for (const f of files)
10332
10692
  materializeInto(dstore, res.head, dest, f);
10333
- writeFileSync14(join17(ddir, "refs.json"), JSON.stringify({ current: "main", branches: { main: { head: res.head, base: res.head, remote: res.head } }, tags: {} }, null, 2));
10693
+ writeFileSync15(join18(ddir, "refs.json"), JSON.stringify({ current: "main", branches: { main: { head: res.head, base: res.head, remote: res.head } }, tags: {} }, null, 2));
10334
10694
  writeWorkingIndexAt(ddir, dest, files);
10335
10695
  console.log(`cloned local peer ${args[0]} -> ${dest} (${(await peer.log.history()).length} ops, ${files.length} files)`);
10336
10696
  break;
@@ -10339,12 +10699,12 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10339
10699
  const repoName = rest[0] || die("usage: sol clone [<url>] <owner>/<repo> [dir]");
10340
10700
  const token = process.env.SOL_TOKEN || die("set SOL_TOKEN to the backend bearer token");
10341
10701
  const target = resolve4(cwd, rest[1] || repoName.split("/").pop() || repoName);
10342
- const fdir = join17(target, ".sol");
10343
- if (existsSync16(fdir))
10702
+ const fdir = join18(target, ".sol");
10703
+ if (existsSync17(fdir))
10344
10704
  die("already a sol repo: " + target);
10345
10705
  const cfg = { url, repo: repoName };
10346
10706
  const bundle = await remoteExport(cfg, token);
10347
- mkdirSync10(fdir, { recursive: true });
10707
+ mkdirSync11(fdir, { recursive: true });
10348
10708
  await writeBundle(fdir, bundle, 0);
10349
10709
  saveRemote(fdir, cfg);
10350
10710
  await pullEnvState(fdir, cfg, token);
@@ -10357,8 +10717,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10357
10717
  cloneBranches[name] = { head: h, base: h, remote: h };
10358
10718
  if (!cloneBranches[onBranch])
10359
10719
  cloneBranches[onBranch] = { head: checkoutHead, base: checkoutHead, remote: checkoutHead };
10360
- writeFileSync14(join17(fdir, "refs.json"), JSON.stringify({ current: onBranch, branches: cloneBranches, tags: {} }, null, 2));
10361
- writeFileSync14(join17(fdir, "HEAD"), JSON.stringify({ head: checkoutHead, seq: bundle.seq, logTip: bundle.tip }));
10720
+ writeFileSync15(join18(fdir, "refs.json"), JSON.stringify({ current: onBranch, branches: cloneBranches, tags: {} }, null, 2));
10721
+ writeFileSync15(join18(fdir, "HEAD"), JSON.stringify({ head: checkoutHead, seq: bundle.seq, logTip: bundle.tip }));
10362
10722
  const store2 = new Store;
10363
10723
  for (const node of bundle.nodes)
10364
10724
  store2.put(node);
@@ -10384,12 +10744,20 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10384
10744
  }
10385
10745
  }
10386
10746
  const cfg = resolveRemote(solDir) || die("no remote — set one with `sol remote <url> <repo>`, or `sol push <repo>` to use the hosted Sol");
10747
+ {
10748
+ const { pendingScrubPaths: pendingScrubPaths2, historyHasCleartext: historyHasCleartext2 } = await Promise.resolve().then(() => (init_secret_scrub(), exports_secret_scrub));
10749
+ const ops0 = await log.history();
10750
+ const stillLeaking = pendingScrubPaths2(solDir).filter((p) => historyHasCleartext2(solDir, ops0, p));
10751
+ if (stillLeaking.length) {
10752
+ die(`refusing to push — pre-seal CLEARTEXT is still in history for: ${stillLeaking.join(", ")}. the plaintext would ship to every clone (recoverable via \`sol restore\`). run \`sol seal ${stillLeaking[0]} --scrub-history\` (repeat per path, or \`sol seal --scrub-history\` for all) first.`);
10753
+ }
10754
+ }
10387
10755
  const token = process.env.SOL_TOKEN || authExpired();
10388
10756
  const rh = await remoteHead(cfg, token);
10389
10757
  const ops = await log.history();
10390
10758
  const localSeq = ops.length ? ops[ops.length - 1].seq : 0;
10391
10759
  const localTip = await log.logTip();
10392
- const localRefs = existsSync16(refsPath()) ? JSON.parse(readFileSync16(refsPath(), "utf8")) : undefined;
10760
+ const localRefs = existsSync17(refsPath()) ? JSON.parse(readFileSync17(refsPath(), "utf8")) : undefined;
10393
10761
  const branch = localRefs?.current ?? "main";
10394
10762
  const branchHead = await log.head() ?? "";
10395
10763
  const remoteWasEmpty = rh.seq === 0 && !rh.tip;
@@ -10412,8 +10780,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10412
10780
  const prevHead = await log.head() ?? "";
10413
10781
  await writeBundle(solDir, canon, 0);
10414
10782
  const convergedHead = res.head ?? canon.refs?.branches?.[branch] ?? branchHead;
10415
- if (existsSync16(refsPath())) {
10416
- const refs = JSON.parse(readFileSync16(refsPath(), "utf8"));
10783
+ if (existsSync17(refsPath())) {
10784
+ const refs = JSON.parse(readFileSync17(refsPath(), "utf8"));
10417
10785
  if (canon.refs) {
10418
10786
  for (const [name, h] of Object.entries(canon.refs.branches)) {
10419
10787
  refs.branches[name] = { head: refs.branches[name]?.head ?? h, base: refs.branches[name]?.base ?? h, remote: h };
@@ -10477,8 +10845,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10477
10845
  const ownMeta = readViewMeta(solDir);
10478
10846
  const base2 = peerMeta?.startHead ?? ownMeta?.startHead;
10479
10847
  const res = await converge2({ store: new FileStore(solDir, objectsDir()), log }, { nodes: await peerNodes2(peer, peerHead, peerOps), ops: peerOps, incomingHead: peerHead, actor, ...base2 ? { base: base2 } : {} });
10480
- if (existsSync16(refsPath())) {
10481
- const refs = JSON.parse(readFileSync16(refsPath(), "utf8"));
10848
+ if (existsSync17(refsPath())) {
10849
+ const refs = JSON.parse(readFileSync17(refsPath(), "utf8"));
10482
10850
  if (refs.branches[refs.current])
10483
10851
  refs.branches[refs.current].head = res.head;
10484
10852
  saveRefs(refs);
@@ -10509,11 +10877,11 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10509
10877
  const ops = await log.history();
10510
10878
  const localSeq = ops.length ? ops[ops.length - 1].seq : 0;
10511
10879
  const localTip = await log.logTip();
10512
- const curBranch = existsSync16(refsPath()) ? JSON.parse(readFileSync16(refsPath(), "utf8")).current : bundle.refs?.production || "main";
10880
+ const curBranch = existsSync17(refsPath()) ? JSON.parse(readFileSync17(refsPath(), "utf8")).current : bundle.refs?.production || "main";
10513
10881
  const remoteCurHead = bundle.refs?.branches?.[curBranch] ?? bundle.head ?? "";
10514
10882
  if (bundle.seq === localSeq && bundle.tip === localTip) {
10515
- if (bundle.refs && existsSync16(refsPath())) {
10516
- const lr = JSON.parse(readFileSync16(refsPath(), "utf8"));
10883
+ if (bundle.refs && existsSync17(refsPath())) {
10884
+ const lr = JSON.parse(readFileSync17(refsPath(), "utf8"));
10517
10885
  const before = lr.branches[lr.current]?.head;
10518
10886
  for (const [name, h] of Object.entries(bundle.refs.branches))
10519
10887
  lr.branches[name] = { head: h, base: lr.branches[name]?.base ?? h, remote: h };
@@ -10537,9 +10905,9 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10537
10905
  break;
10538
10906
  }
10539
10907
  const syncRefHead = (h) => {
10540
- if (!existsSync16(refsPath()))
10908
+ if (!existsSync17(refsPath()))
10541
10909
  return;
10542
- const refs = JSON.parse(readFileSync16(refsPath(), "utf8"));
10910
+ const refs = JSON.parse(readFileSync17(refsPath(), "utf8"));
10543
10911
  if (refs.branches[refs.current])
10544
10912
  refs.branches[refs.current].head = h;
10545
10913
  saveRefs(refs);
@@ -10557,8 +10925,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10557
10925
  syncRefHead(remoteCurHead);
10558
10926
  setOpLogHead(remoteCurHead);
10559
10927
  materializeTree(loadStore(), remoteCurHead);
10560
- if (bundle.refs && existsSync16(refsPath())) {
10561
- const lr = JSON.parse(readFileSync16(refsPath(), "utf8"));
10928
+ if (bundle.refs && existsSync17(refsPath())) {
10929
+ const lr = JSON.parse(readFileSync17(refsPath(), "utf8"));
10562
10930
  for (const [name, h] of Object.entries(bundle.refs.branches))
10563
10931
  lr.branches[name] = { head: h, base: lr.branches[name]?.base ?? h, remote: h };
10564
10932
  saveRefs(lr);
@@ -10606,9 +10974,9 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10606
10974
  for (const c of result.conflicts) {
10607
10975
  const blob = fileAt(store2, result.head, c.path);
10608
10976
  if (blob)
10609
- writeFileSync14(join17(cwd, c.path), blob.encoding === "base64" ? Buffer.from(blob.content, "base64") : blob.content);
10977
+ writeFileSync15(join18(cwd, c.path), blob.encoding === "base64" ? Buffer.from(blob.content, "base64") : blob.content);
10610
10978
  }
10611
- writeFileSync14(join17(solDir, "MERGE_HEAD"), remoteHead2);
10979
+ writeFileSync15(join18(solDir, "MERGE_HEAD"), remoteHead2);
10612
10980
  saveMergeConflicts(solDir, result.conflicts);
10613
10981
  console.log(`pulled + merged WITH ${result.conflicts.length} conflict(s), left uncommitted in your working tree:`);
10614
10982
  for (const c of result.conflicts)
@@ -10623,11 +10991,11 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10623
10991
  break;
10624
10992
  }
10625
10993
  case "promote": {
10626
- if (!existsSync16(solDir))
10994
+ if (!existsSync17(solDir))
10627
10995
  die("not a sol repo");
10628
10996
  const cfg = resolveRemote(solDir) || die("no remote — set one with `sol remote <url> <repo>`");
10629
10997
  const token = process.env.SOL_TOKEN || authExpired();
10630
- const cur = existsSync16(refsPath()) ? JSON.parse(readFileSync16(refsPath(), "utf8")).current : "main";
10998
+ const cur = existsSync17(refsPath()) ? JSON.parse(readFileSync17(refsPath(), "utf8")).current : "main";
10631
10999
  const branch = args[0] || cur;
10632
11000
  const refs = await remotePromote(cfg, token, branch);
10633
11001
  console.log(`promoted '${branch}' -> production '${refs.production}' now at ${(refs.branches[refs.production] ?? "").slice(0, 12)}`);
@@ -10639,8 +11007,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10639
11007
  const newRepo = frest[1] || die("usage: sol fork [<url>] <parent-repo> <new-repo> [dir]");
10640
11008
  const token = process.env.SOL_TOKEN || authExpired();
10641
11009
  const target = resolve4(cwd, frest[2] || newRepo);
10642
- const fdir = join17(target, ".sol");
10643
- if (existsSync16(fdir))
11010
+ const fdir = join18(target, ".sol");
11011
+ if (existsSync17(fdir))
10644
11012
  die("already a sol repo: " + target);
10645
11013
  const parentCfg = { url, repo: parent };
10646
11014
  const newCfg = { url, repo: newRepo, forkParent: parent };
@@ -10656,7 +11024,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10656
11024
  }
10657
11025
  await forkMeta(newCfg, token, parent);
10658
11026
  const canon = await remoteExport(newCfg, token);
10659
- mkdirSync10(fdir, { recursive: true });
11027
+ mkdirSync11(fdir, { recursive: true });
10660
11028
  await writeBundle(fdir, canon, 0);
10661
11029
  const srvRefs = canon.refs ?? { branches: { main: canon.head ?? "" }, production: "main" };
10662
11030
  const checkout = canon.checkout ?? { branch: srvRefs.production || "main", head: srvRefs.branches[srvRefs.production] ?? canon.head };
@@ -10665,8 +11033,8 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10665
11033
  const cloneBranches = {};
10666
11034
  for (const [name, h] of Object.entries(srvRefs.branches))
10667
11035
  cloneBranches[name] = { head: h, base: h, remote: h };
10668
- writeFileSync14(join17(fdir, "refs.json"), JSON.stringify({ current: onBranch, branches: cloneBranches, tags: {} }, null, 2));
10669
- writeFileSync14(join17(fdir, "HEAD"), JSON.stringify({ head: checkoutHead, seq: canon.seq, logTip: canon.tip }));
11036
+ writeFileSync15(join18(fdir, "refs.json"), JSON.stringify({ current: onBranch, branches: cloneBranches, tags: {} }, null, 2));
11037
+ writeFileSync15(join18(fdir, "HEAD"), JSON.stringify({ head: checkoutHead, seq: canon.seq, logTip: canon.tip }));
10670
11038
  saveRemote(fdir, newCfg);
10671
11039
  const store2 = new Store;
10672
11040
  for (const node of canon.nodes)
@@ -10753,7 +11121,7 @@ refused for a non-recipient (host/agent-blind). a missing or malformed reference
10753
11121
  const token = process.env.SOL_TOKEN || authExpired();
10754
11122
  const { mrSummary: mrSummary2 } = await Promise.resolve().then(() => exports_mr);
10755
11123
  const sub = args[0];
10756
- const localRefs = () => existsSync16(refsPath()) ? JSON.parse(readFileSync16(refsPath(), "utf8")) : { current: "main", branches: {}, tags: {} };
11124
+ const localRefs = () => existsSync17(refsPath()) ? JSON.parse(readFileSync17(refsPath(), "utf8")) : { current: "main", branches: {}, tags: {} };
10757
11125
  const flag2 = (name) => {
10758
11126
  const i = args.indexOf(name);
10759
11127
  return i >= 0 ? args[i + 1] : undefined;
@@ -10931,7 +11299,7 @@ ${mrSummary2(pr)}`);
10931
11299
  die("usage: sol run [--keep <path>] [--isolate] <command...>");
10932
11300
  const { capture: capture3, hydrate: hydrate3, isolateCommand: isolateCommand2 } = await Promise.resolve().then(() => (init_runtime(), exports_runtime));
10933
11301
  const head = await repo.head();
10934
- const dir = mkdtempSync(join17(tmpdir(), "sol-run-"));
11302
+ const dir = mkdtempSync(join18(tmpdir(), "sol-run-"));
10935
11303
  try {
10936
11304
  const hn = hydrate3(loadStore(), head, dir);
10937
11305
  console.log(`hydrated ${hn} file(s) -> sandbox${isolate ? " (isolated: no network, writes confined to the sandbox)" : ""}`);
@@ -10951,8 +11319,8 @@ ${mrSummary2(pr)}`);
10951
11319
  const { written, deleted } = await capture3(repo, dir, keep);
10952
11320
  if (written.length || deleted.length) {
10953
11321
  await appendCommit(log, await repo.head(), `run: ${command.join(" ")}`, head);
10954
- if (existsSync16(refsPath())) {
10955
- const refs = JSON.parse(readFileSync16(refsPath(), "utf8"));
11322
+ if (existsSync17(refsPath())) {
11323
+ const refs = JSON.parse(readFileSync17(refsPath(), "utf8"));
10956
11324
  if (refs.branches[refs.current]) {
10957
11325
  refs.branches[refs.current].head = await repo.head();
10958
11326
  saveRefs(refs);
@@ -10964,7 +11332,7 @@ ${mrSummary2(pr)}`);
10964
11332
  materialize(synced, nh, f);
10965
11333
  for (const f of deleted) {
10966
11334
  try {
10967
- unlinkSync6(join17(cwd, f));
11335
+ unlinkSync7(join18(cwd, f));
10968
11336
  } catch {}
10969
11337
  }
10970
11338
  console.log(`captured ${written.length} written, ${deleted.length} deleted file(s):`);
@@ -10986,10 +11354,10 @@ ${mrSummary2(pr)}`);
10986
11354
  if (sub === "import") {
10987
11355
  const gitPath = resolve4(cwd, args[1] || die("usage: sol git import <git-repo> [dir]"));
10988
11356
  const target = resolve4(cwd, args[2] || basename(gitPath));
10989
- const fdir = join17(target, ".sol");
10990
- if (existsSync16(fdir))
11357
+ const fdir = join18(target, ".sol");
11358
+ if (existsSync17(fdir))
10991
11359
  die("already a sol repo: " + target);
10992
- mkdirSync10(fdir, { recursive: true });
11360
+ mkdirSync11(fdir, { recursive: true });
10993
11361
  const { commits, branches, head, current } = await importGitRepo2(gitPath, fdir);
10994
11362
  const refsBranches = {};
10995
11363
  for (const b of branches)
@@ -10997,13 +11365,13 @@ ${mrSummary2(pr)}`);
10997
11365
  if (!refsBranches[current])
10998
11366
  refsBranches[current] = { head, base: head };
10999
11367
  refsBranches[current].head = head;
11000
- writeFileSync14(join17(fdir, "refs.json"), JSON.stringify({ current, branches: refsBranches, tags: {} }, null, 2));
11368
+ writeFileSync15(join18(fdir, "refs.json"), JSON.stringify({ current, branches: refsBranches, tags: {} }, null, 2));
11001
11369
  const store2 = new Store;
11002
- for (const name of readdirSync6(join17(fdir, "objects"))) {
11370
+ for (const name of readdirSync8(join18(fdir, "objects"))) {
11003
11371
  if (name.endsWith(".tmp"))
11004
11372
  continue;
11005
11373
  try {
11006
- store2.put(decodeObject(readFileSync16(join17(fdir, "objects", name))));
11374
+ store2.put(decodeObject(readFileSync17(join18(fdir, "objects", name))));
11007
11375
  } catch {}
11008
11376
  }
11009
11377
  const onDisk = hydrate3(store2, head, target);
@@ -11035,9 +11403,9 @@ ${mrSummary2(pr)}`);
11035
11403
  die("already inside a view — create views from the parent repo (its `.sol` owns the shared store + op-log).");
11036
11404
  const name = args.find((a) => !a.startsWith("-")) || die("usage: sol view <name> [dir]");
11037
11405
  const rest = args.filter((a) => !a.startsWith("-"));
11038
- const defaultDir = join17(dirname4(cwd), `${basename(cwd)}-${name}`);
11406
+ const defaultDir = join18(dirname4(cwd), `${basename(cwd)}-${name}`);
11039
11407
  const viewDir = rest[1] ? resolve4(procCwd, rest[1]) : defaultDir;
11040
- if (existsSync16(join17(viewDir, ".sol")))
11408
+ if (existsSync17(join18(viewDir, ".sol")))
11041
11409
  die("already a sol repo/view: " + viewDir);
11042
11410
  const branch = `view/${name}`;
11043
11411
  const startHead = await log.head() ?? emptyRoot(loadStore());
@@ -11051,7 +11419,7 @@ ${mrSummary2(pr)}`);
11051
11419
  break;
11052
11420
  }
11053
11421
  case "views": {
11054
- if (!existsSync16(solDir))
11422
+ if (!existsSync17(solDir))
11055
11423
  die("not a sol repo");
11056
11424
  const parentSol = parentSolDir(solDir) ?? solDir;
11057
11425
  const { pruneViews: pruneViews2, viewStatuses: viewStatuses2, sharedObjectCount: sharedObjectCount2 } = await Promise.resolve().then(() => (init_views(), exports_views));
@@ -11145,7 +11513,7 @@ ${mrSummary2(pr)}`);
11145
11513
  await startSecretMcp2({ solDir });
11146
11514
  break;
11147
11515
  }
11148
- if (!existsSync16(solDir))
11516
+ if (!existsSync17(solDir))
11149
11517
  die("not a sol repo — run `sol init` first");
11150
11518
  const { runEnv: runEnv2, runSecret: runSecret2, resolveReference: resolveReference2 } = await Promise.resolve().then(() => (init_secret2(), exports_secret2));
11151
11519
  const { loadSelfIdentity: loadSelfIdentity2, loadManageIdentity: loadManageIdentity2, fetchKey: fetchKey2 } = await Promise.resolve().then(() => (init_seal_audience(), exports_seal_audience));
@@ -11318,18 +11686,18 @@ var init_dispatch = __esm(() => {
11318
11686
  init_remote();
11319
11687
  init_lib();
11320
11688
  init_test_gate();
11321
- CRED_PATH = join17(homedir2(), ".sol", "credentials");
11689
+ CRED_PATH = join18(homedir2(), ".sol", "credentials");
11322
11690
  DEFAULT_REMOTE_URL = (process.env.SOL_REMOTE || "https://sol.midsummer.new").replace(/\/+$/, "");
11323
11691
  ATTEST_KEY = process.env.SOL_ATTEST_KEY || undefined;
11324
11692
  });
11325
11693
 
11326
11694
  // src/bin/sol.ts
11327
- import { readFileSync as readFileSync17 } from "fs";
11695
+ import { readFileSync as readFileSync18 } from "fs";
11328
11696
  function cliVersion2() {
11329
11697
  if (typeof __SOL_COMPILED_VERSION__ === "string" && __SOL_COMPILED_VERSION__)
11330
11698
  return __SOL_COMPILED_VERSION__;
11331
11699
  try {
11332
- return JSON.parse(readFileSync17(new URL("./package.json", import.meta.url), "utf8")).version || "dev";
11700
+ return JSON.parse(readFileSync18(new URL("./package.json", import.meta.url), "utf8")).version || "dev";
11333
11701
  } catch {
11334
11702
  return "dev";
11335
11703
  }