githolon 0.5.0 → 0.6.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.
Files changed (2) hide show
  1. package/dist/cli.mjs +199 -38
  2. package/package.json +2 -2
package/dist/cli.mjs CHANGED
@@ -460,13 +460,13 @@ async function sha256hex(t) {
460
460
  function osEntropyBuffer(n) {
461
461
  const bytes = new Uint8Array(n * 8);
462
462
  for (let o = 0; o < bytes.length; o += 65536) crypto.getRandomValues(bytes.subarray(o, Math.min(o + 65536, bytes.length)));
463
- const out9 = new Array(n), T = 2 ** 53;
463
+ const out10 = new Array(n), T = 2 ** 53;
464
464
  for (let i = 0; i < n; i++) {
465
465
  let z = 0n;
466
466
  for (let b = 7; b >= 0; b--) z = z << 8n | BigInt(bytes[i * 8 + b]);
467
- out9[i] = Number(z >> 11n) / T;
467
+ out10[i] = Number(z >> 11n) / T;
468
468
  }
469
- return out9;
469
+ return out10;
470
470
  }
471
471
  function stringifyBig(o) {
472
472
  return JSON.stringify(o, (_k, v) => typeof v === "bigint" ? `@@B:${v}@@` : v).replace(/"@@B:(\d+)@@"/g, "$1");
@@ -599,7 +599,7 @@ function applyIntentBytes(eng, ws, bytes) {
599
599
  function verifyChainLocal(eng, ws) {
600
600
  return JSON.parse(call(eng.ex, "verify_chain", { repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH }, eng.STDERR));
601
601
  }
602
- var enc2, dec2, BRANCH, repoArgOf, gitdirOf, unpack, installPayload, qById, query, count, sum;
602
+ var enc2, dec2, BRANCH, repoArgOf, gitdirOf, unpack, installPayload, qById, query, cryptoUnwrapKey, count, sum;
603
603
  var init_engine = __esm({
604
604
  "vendor/engine/engine.mjs"() {
605
605
  "use strict";
@@ -615,8 +615,9 @@ var init_engine = __esm({
615
615
  return { ptr: Number(v >> 32n), len: Number(v & 0xffffffffn) };
616
616
  };
617
617
  installPayload = (hash, usda, installedBy, dispositions) => ({ domainHash: hash, packageUsda: usda, installedBy, authorityScope: "workspace/root", dependencies: [], finalizers: [], ...dispositions ? { dispositions } : {} });
618
- qById = (eng, ws, id) => JSON.parse(call(eng.ex, "query_by_id", { repoArg: repoArgOf(ws), workspace: ws, aggregateId: id, branch: BRANCH }, eng.STDERR));
619
- query = (eng, ws, queryId, paramsJson) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryId, paramsJson, branch: BRANCH }, eng.STDERR));
618
+ qById = (eng, ws, id, principal = "", keys = []) => JSON.parse(call(eng.ex, "query_by_id", { repoArg: repoArgOf(ws), workspace: ws, aggregateId: id, principal, keys, branch: BRANCH }, eng.STDERR));
619
+ query = (eng, ws, queryId, paramsJson, principal = "", keys = []) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryId, paramsJson, principal, keys, branch: BRANCH }, eng.STDERR));
620
+ cryptoUnwrapKey = (eng, { secret, hpkeEpk, ct }) => JSON.parse(call(eng.ex, "crypto_unwrap_key", { secret, hpkeEpk, ct }, eng.STDERR)).scopeKey;
620
621
  count = (eng, ws, countId, groupKey) => JSON.parse(call(eng.ex, "count", { repoArg: repoArgOf(ws), workspace: ws, countId, groupKey, branch: BRANCH }, eng.STDERR));
621
622
  sum = (eng, ws, sumId, groupKey) => JSON.parse(call(eng.ex, "sum", { repoArg: repoArgOf(ws), workspace: ws, sumId, groupKey, branch: BRANCH }, eng.STDERR));
622
623
  }
@@ -644,6 +645,13 @@ async function fetchRuntime(cloud) {
644
645
  const cache = join4(configDir(), "runtime");
645
646
  let wasmBytes;
646
647
  const wasmCache = join4(cache, "holon.wasm");
648
+ const localWasm = process.env["NOMOS_LOCAL_WASM"];
649
+ if (localWasm) {
650
+ const bytes = readFileSync2(localWasm);
651
+ const manifests2 = await fetchJsonCached(`${cloud}/v1/runtime/manifests`, join4(cache, "manifests.json"));
652
+ const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`, join4(cache, "packages.json"));
653
+ return { wasmBytes: bytes, manifests: manifests2, packages: packages2 };
654
+ }
647
655
  try {
648
656
  const r = await fetch(`${cloud}/v1/runtime/holon.wasm`);
649
657
  if (!r.ok) throw new Error(`runtime wasm \u2192 ${r.status}`);
@@ -832,14 +840,28 @@ function runOfflineLegs(eng, ws, lawHash, legs) {
832
840
  }
833
841
  return done(true, lines);
834
842
  }
835
- async function runOfflineProofStandalone(proofPath, cloud) {
843
+ async function runOfflineProofStandalone(proofPath, cloud, domain) {
836
844
  const src = readFileSync3(proofPath, "utf8");
837
- const legs = parseOfflineLegs(src);
838
845
  const packageName = basename(proofPath).replace(/\.proof\.mts$/, "");
839
846
  const deployFile = join6(dirname3(proofPath), `${packageName}.deploy.json`);
840
847
  if (!existsSync5(deployFile)) {
841
848
  throw new Error(`missing ${deployFile} \u2014 run \`githolon compile\` (the proof and the deploy body are built together)`);
842
849
  }
850
+ let legs;
851
+ const legsFile = join6(dirname3(proofPath), `${packageName}.proof-legs.json`);
852
+ if (existsSync5(legsFile)) {
853
+ const index = JSON.parse(readFileSync3(legsFile, "utf8"));
854
+ const keys = Object.keys(index.domains);
855
+ const chosen = domain ?? index.default;
856
+ if (index.domains[chosen] === void 0) {
857
+ throw new Error(`no provable domain '${chosen}' in this package \u2014 it proves: ${keys.join(", ")} (pick one: githolon proof --domain <key>)`);
858
+ }
859
+ legs = index.domains[chosen];
860
+ if (keys.length > 1) console.log(`githolon proof \u2014 domain '${chosen}' (of ${keys.length}: ${keys.join(", ")}; --domain <key> to switch)`);
861
+ } else {
862
+ if (domain !== void 0) throw new Error(`--domain needs a per-domain legs index (build/${packageName}.proof-legs.json) \u2014 recompile with \`githolon compile\` to emit it`);
863
+ legs = parseOfflineLegs(src);
864
+ }
843
865
  const deployBody = JSON.parse(readFileSync3(deployFile, "utf8"));
844
866
  const lawHash = await sha256hex(deployBody.packageUsda);
845
867
  console.log(`githolon proof \u2014 OFFLINE legs on a local holon (the cloud loop: githolon proof --live)`);
@@ -1744,9 +1766,9 @@ var HELP = {
1744
1766
  examples: ["githolon compile", "githolon compile nomos.package.mjs --layered"]
1745
1767
  },
1746
1768
  proof: {
1747
- usage: "githolon proof [build/<name>.proof.mts] [--live] [--keep]",
1748
- what: "Run the proof GENERATED from your law. DEFAULT: the OFFLINE legs on a LOCAL holon \u2014 the\nsame engine plane the cloud edge runs; no cloud workspace is touched (develop/play/understand\nhere, deploy with confidence after). --live runs the full cloud loop (throwaway workspace \u2192\ndeploy \u2192 offline write \u2192 admission \u2192 cloud reads \u2192 convergence), RETIRED on every exit;\n--keep keeps it and prints the secret once. ALL GREEN or it names the jam. The offline legs\nalso rerun on every save in `githolon dev`.",
1749
- examples: ["githolon proof", "githolon proof --live", "githolon proof --live --keep"]
1769
+ usage: "githolon proof [build/<name>.proof.mts] [--domain <key>] [--live] [--keep]",
1770
+ what: "Run the proof GENERATED from your law. DEFAULT: the OFFLINE legs on a LOCAL holon \u2014 the\nsame engine plane the cloud edge runs; no cloud workspace is touched (develop/play/understand\nhere, deploy with confidence after). --domain <key> proves a SPECIFIC domain of a multi-domain\npackage (offline; the default is the first). --live runs the full cloud loop (throwaway\nworkspace \u2192 deploy \u2192 offline write \u2192 admission \u2192 cloud reads \u2192 convergence), RETIRED on every\nexit; --keep keeps it and prints the secret once. ALL GREEN or it names the jam. The offline\nlegs also rerun on every save in `githolon dev`.",
1771
+ examples: ["githolon proof", "githolon proof --domain co2_platform", "githolon proof --live", "githolon proof --live --keep"]
1750
1772
  },
1751
1773
  dev: {
1752
1774
  usage: "githolon dev [--port <n>] [--cloud <url>] [--once]",
@@ -1983,9 +2005,9 @@ function capJsonStrings(v, max = 2048) {
1983
2005
  if (typeof v === "string") return v.length > max ? `${v.slice(0, max)}\u2026(${v.length} chars)` : v;
1984
2006
  if (Array.isArray(v)) return v.map((x) => capJsonStrings(x, max));
1985
2007
  if (typeof v === "object" && v !== null) {
1986
- const out9 = {};
1987
- for (const [k, x] of Object.entries(v)) out9[k] = capJsonStrings(x, max);
1988
- return out9;
2008
+ const out10 = {};
2009
+ for (const [k, x] of Object.entries(v)) out10[k] = capJsonStrings(x, max);
2010
+ return out10;
1989
2011
  }
1990
2012
  return v;
1991
2013
  }
@@ -2147,35 +2169,114 @@ stopped at intent ${i + 1}/${chain.length} \u2014 the verify verdict below cover
2147
2169
  return printVerdict(verdict) ? 0 : 1;
2148
2170
  }
2149
2171
 
2172
+ // src/decrypt.ts
2173
+ init_local_holon();
2174
+ init_cloud();
2175
+ init_engine();
2176
+ var SOURCE2 = "source";
2177
+ var out8 = (s) => {
2178
+ process.stdout.write(s + "\n");
2179
+ };
2180
+ var err8 = (s) => {
2181
+ process.stderr.write(`error: ${s}
2182
+ `);
2183
+ };
2184
+ async function decrypt(ws, opts) {
2185
+ const cloud = cloudBase(opts.cloud);
2186
+ if (!opts.as) {
2187
+ err8("--as <principal> is required (who to decrypt as)");
2188
+ return 1;
2189
+ }
2190
+ if (!opts.secret) {
2191
+ err8("--secret <base64 X25519 device secret> is required");
2192
+ return 1;
2193
+ }
2194
+ if (!opts.query) {
2195
+ err8("--query <queryId> is required (the read to decrypt)");
2196
+ return 1;
2197
+ }
2198
+ let eng;
2199
+ try {
2200
+ ({ eng } = await holonEngine(cloud, opts.overlay, "githolon-decrypt"));
2201
+ } catch (e) {
2202
+ err8(`cannot boot the local holon: ${String(e.message ?? e)}`);
2203
+ return 1;
2204
+ }
2205
+ const m = await mountWorkspace(eng, SOURCE2, {
2206
+ remote: `${cloud}/v1/workspaces/${ws}/git`,
2207
+ headers: { "x-nomos-principal": opts.as }
2208
+ });
2209
+ if (m.restored !== true) {
2210
+ err8(`workspace '${ws}' has no main on ${cloud}, or its clone was refused for '${opts.as}'` + (m.restoreError ? ` (${String(m.restoreError).split(" | ")[0]})` : ""));
2211
+ return 1;
2212
+ }
2213
+ const wraps = query(eng, SOURCE2, "wrappedKeysByRecipient", JSON.stringify({ recipientPrincipal: opts.as }), opts.as);
2214
+ const keys = [];
2215
+ if (Array.isArray(wraps)) {
2216
+ for (const w of wraps) {
2217
+ const d = w.data ?? {};
2218
+ try {
2219
+ const key = cryptoUnwrapKey(eng, { secret: opts.secret, hpkeEpk: d.hpkeEpk, ct: d.ct });
2220
+ keys.push({ scope: d.scope, epoch: Number(d.epoch), key });
2221
+ } catch {
2222
+ }
2223
+ }
2224
+ }
2225
+ if (opts.json !== true) out8(`# resolved ${keys.length} scope key(s) for '${opts.as}': ${keys.map((k) => `${k.scope}@${k.epoch}`).join(", ") || "(none)"}`);
2226
+ const rows = query(eng, SOURCE2, opts.query, JSON.stringify(opts.params ?? {}), opts.as, keys);
2227
+ if (rows && !Array.isArray(rows) && rows.ok === false) {
2228
+ err8(`the read was refused: ${rows.error}` + (String(rows.error).startsWith("read-forbidden") ? `
2229
+ '${opts.as}' is not granted this scope's read capability` : ""));
2230
+ return 1;
2231
+ }
2232
+ out8(JSON.stringify(rows, null, opts.json === true ? 0 : 2));
2233
+ return 0;
2234
+ }
2235
+
2150
2236
  // src/status.ts
2151
2237
  init_engine();
2152
2238
  init_cloud();
2153
2239
  import { readFileSync as readFileSync8 } from "node:fs";
2154
- var out8 = (s) => void process.stdout.write(s + "\n");
2155
- var err8 = (s) => void process.stderr.write("error: " + s + "\n");
2240
+ var out9 = (s) => void process.stdout.write(s + "\n");
2241
+ var err9 = (s) => void process.stderr.write("error: " + s + "\n");
2156
2242
  function lawDiffVerdict(localHash, installed, ws) {
2157
2243
  const active = installed.filter((d) => d.phase === "Active" && typeof d.domainHash === "string");
2158
- const match = active.find((d) => d.domainHash === localHash);
2159
- if (match !== void 0) {
2160
- return { inSync: true, lines: [`\u2713 in sync \u2014 the deployed law IS your local build (${localHash.slice(0, 16)}\u2026)`] };
2161
- }
2244
+ const currents = active.filter((d) => d.current === true);
2245
+ const priors = active.filter((d) => d.current !== true);
2246
+ const localActive = active.find((d) => d.domainHash === localHash);
2247
+ const localIsCurrent = currents.some((d) => d.domainHash === localHash);
2162
2248
  const lines = [];
2249
+ if (localIsCurrent || currents.length === 0 && localActive !== void 0) {
2250
+ lines.push(`\u2713 in sync \u2014 the deployed law IS your local build (${localHash.slice(0, 16)}\u2026)`);
2251
+ if (priors.length > 0) lines.push(` (${priors.length} prior deploy(s) remain Active under install-beside; yours is the current one resolution serves)`);
2252
+ return { inSync: true, lines };
2253
+ }
2163
2254
  if (active.length === 0) {
2164
2255
  lines.push(`\u2717 workspace '${ws}' has NO active tenant law \u2014 your local build is not deployed`);
2256
+ } else if (localActive !== void 0) {
2257
+ lines.push(`~ your build (${localHash.slice(0, 16)}\u2026) is an ACTIVE install on '${ws}', but SUPERSEDED \u2014 a newer deploy is current:`);
2258
+ for (const c of currents) lines.push(` current ${c.domainHash.slice(0, 16)}\u2026 (${c.installedBy ?? "?"}) \u2190 resolution serves this`);
2259
+ lines.push(` redeploy to make your build current: githolon deploy ${ws}`);
2260
+ return { inSync: false, lines };
2261
+ } else if (currents.length > 0) {
2262
+ lines.push(`\u2717 local law differs from the current install${currents.length > 1 ? "s" : ""} on '${ws}':`);
2263
+ for (const c of currents) lines.push(` current ${c.domainHash.slice(0, 16)}\u2026 (${c.installedBy ?? "?"}) \u2190 resolution serves this`);
2264
+ if (priors.length > 0) lines.push(` + ${priors.length} prior active install(s) (install-beside \u2014 historical, not served)`);
2165
2265
  } else {
2166
- lines.push(`\u2717 local law differs from every active installation on '${ws}':`);
2266
+ lines.push(`\u2717 local law differs from every active installation on '${ws}' (${active.length}):`);
2167
2267
  for (const d of active) lines.push(` deployed ${d.domainHash.slice(0, 16)}\u2026 (${d.installedBy ?? "?"})`);
2168
2268
  }
2169
- lines.push(` remedy: githolon deploy ${ws} (installs ${localHash.slice(0, 16)}\u2026)`);
2269
+ lines.push(` remedy: githolon deploy ${ws} (installs ${localHash.slice(0, 16)}\u2026 and makes it current)`);
2170
2270
  return { inSync: false, lines };
2171
2271
  }
2272
+ var CONTROL_PLANE_KEYS = ["nomos", "bootstrap", "workspaces"];
2172
2273
  async function status(wsArg, opts) {
2173
2274
  const cloud = cloudBase(opts.cloud);
2174
2275
  let ws;
2175
2276
  try {
2176
2277
  ws = await resolveWorkspace(wsArg, process.cwd(), opts.target, "githolon status <ws>");
2177
2278
  } catch (e) {
2178
- err8(e.message);
2279
+ err9(e.message);
2179
2280
  return 1;
2180
2281
  }
2181
2282
  let localHash;
@@ -2187,28 +2288,35 @@ async function status(wsArg, opts) {
2187
2288
  }
2188
2289
  const r = await fetch(`${cloud}/v1/workspaces/${ws}/domains`).catch(() => void 0);
2189
2290
  if (r === void 0) {
2190
- err8(`cannot reach ${cloud} \u2014 githolon status compares against the DEPLOYED law and needs the cloud (local-only: githolon dev)`);
2291
+ err9(`cannot reach ${cloud} \u2014 githolon status compares against the DEPLOYED law and needs the cloud (local-only: githolon dev)`);
2191
2292
  return 1;
2192
2293
  }
2193
2294
  const d = await r.json().catch(() => void 0);
2194
2295
  if (!r.ok || d?.ok !== true) {
2195
- err8(`status '${ws}' failed (${r.status}): ${d ? JSON.stringify(d) : "no body"}
2296
+ err9(`status '${ws}' failed (${r.status}): ${d ? JSON.stringify(d) : "no body"}
2196
2297
  is the workspace born? githolon ws create ${ws}`);
2197
2298
  return 1;
2198
2299
  }
2199
- out8(`workspace ${ws} on ${cloud}`);
2200
- const domains = d.domains ?? [];
2201
- if (domains.length === 0) out8(`installed (none \u2014 not even the controller; the workspace may be unborn)`);
2300
+ out9(`workspace ${ws} on ${cloud}`);
2301
+ const allDomains = d.domains ?? [];
2302
+ const controlPlaneHashes = new Set(CONTROL_PLANE_KEYS.map((k) => d.currentLaw?.[k]).filter(Boolean));
2303
+ const domains = allDomains.filter((dm) => !controlPlaneHashes.has(dm.domainHash));
2304
+ const controllerCount = allDomains.length - domains.length;
2305
+ if (allDomains.length === 0) out9(`installed (none \u2014 not even the controller; the workspace may be unborn)`);
2202
2306
  for (const dom of domains) {
2203
- out8(`installed ${(dom.domainHash ?? "?").slice(0, 16)}\u2026 ${dom.phase ?? "?"} by ${dom.installedBy ?? "?"}`);
2307
+ const mark = dom.current === true ? " \u2190 current (the holon resolves dispatch here)" : "";
2308
+ out9(`installed ${(dom.domainHash ?? "?").slice(0, 16)}\u2026 ${dom.phase ?? "?"} by ${dom.installedBy ?? "?"}${mark}`);
2204
2309
  }
2310
+ if (controllerCount > 0) out9(` (+ ${controllerCount} control-plane install(s) \u2014 the nomos lifecycle controller; not tenant law)`);
2311
+ const tenantActive = domains.filter((dm) => dm.phase === "Active").length;
2312
+ if (tenantActive > 1) out9(` (${tenantActive} active tenant installs \u2014 install-beside keeps every prior deploy Active; the holon serves the current one per domain)`);
2205
2313
  if (localHash === void 0) {
2206
- out8(`local (no build/*.deploy.json here \u2014 run \`githolon compile\` to build the law this project authors)`);
2314
+ out9(`local (no build/*.deploy.json here \u2014 run \`githolon compile\` to build the law this project authors)`);
2207
2315
  return 0;
2208
2316
  }
2209
- out8(`local ${localHash.slice(0, 16)}\u2026 (build/*.deploy.json)`);
2317
+ out9(`local ${localHash.slice(0, 16)}\u2026 (build/*.deploy.json)`);
2210
2318
  const verdict = lawDiffVerdict(localHash, domains, ws);
2211
- for (const line of verdict.lines) out8(line);
2319
+ for (const line of verdict.lines) out9(line);
2212
2320
  return verdict.inSync ? 0 : 2;
2213
2321
  }
2214
2322
 
@@ -2224,6 +2332,8 @@ The inner loop:
2224
2332
  githolon status [<ws>] local law hash vs the DEPLOYED law, remedy named
2225
2333
  githolon replay <ws|dir> the ledger as film: step the chain intent-by-
2226
2334
  intent; finale = the verify_chain verdict
2335
+ githolon decrypt <ws> --as <p> --secret <b64> clone + decrypt as a principal: unwrap their scope
2336
+ --query <id> [--param k=v] keys from the chain, read private fields in cleartext
2227
2337
 
2228
2338
  Authoring:
2229
2339
  githolon compile [compiler args] compile the package by ./nomos.package.mjs
@@ -2381,7 +2491,20 @@ async function runProof(args) {
2381
2491
  const live = args.includes("--live");
2382
2492
  const keep = args.includes("--keep");
2383
2493
  if (keep && !live) return refuse("--keep only applies to --live (the offline proof creates no cloud workspace to keep)");
2384
- const explicit = args.find((a) => !a.startsWith("--"));
2494
+ let domain;
2495
+ let domainValueIdx = -1;
2496
+ const di = args.findIndex((a) => a === "--domain" || a.startsWith("--domain="));
2497
+ if (di >= 0) {
2498
+ const a = args[di];
2499
+ if (a.includes("=")) domain = a.slice(a.indexOf("=") + 1);
2500
+ else {
2501
+ domain = args[di + 1];
2502
+ domainValueIdx = di + 1;
2503
+ }
2504
+ if (domain === void 0 || domain === "" || domain.startsWith("--")) return refuse("--domain needs a domain key: githolon proof --domain <key>");
2505
+ }
2506
+ if (domain !== void 0 && live) return refuse("--domain is an OFFLINE-lane selector (the --live proof runs the package's primary domain end-to-end); drop --live or drop --domain");
2507
+ const explicit = args.find((a, i) => !a.startsWith("--") && i !== domainValueIdx);
2385
2508
  let proofPath;
2386
2509
  if (explicit !== void 0) {
2387
2510
  proofPath = resolve2(process.cwd(), explicit);
@@ -2404,7 +2527,7 @@ async function runProof(args) {
2404
2527
  try {
2405
2528
  const { runOfflineProofStandalone: runOfflineProofStandalone2 } = await Promise.resolve().then(() => (init_proof_offline(), proof_offline_exports));
2406
2529
  const { cloudBase: cloudBase2 } = await Promise.resolve().then(() => (init_cloud(), cloud_exports));
2407
- return await runOfflineProofStandalone2(proofPath, cloudBase2());
2530
+ return await runOfflineProofStandalone2(proofPath, cloudBase2(), domain);
2408
2531
  } catch (e) {
2409
2532
  return refuse(`${e.message ?? e}`);
2410
2533
  }
@@ -2561,6 +2684,44 @@ ${commandHelp("replay")}`);
2561
2684
  }
2562
2685
  return replay(target, { ...opts, ...step !== void 0 ? { step } : {}, ...json ? { json: true } : {} });
2563
2686
  }
2687
+ if (argv[0] === "decrypt") {
2688
+ const rest = argv.slice(1);
2689
+ const pull = (flag) => {
2690
+ const at = rest.indexOf(flag);
2691
+ return at >= 0 ? rest[at + 1] : void 0;
2692
+ };
2693
+ const as = pull("--as"), secret = pull("--secret"), q = pull("--query");
2694
+ const json = rest.includes("--json");
2695
+ const params = {};
2696
+ rest.forEach((a, i) => {
2697
+ if (a === "--param" && rest[i + 1]) {
2698
+ const [k, ...v] = rest[i + 1].split("=");
2699
+ params[k] = v.join("=");
2700
+ }
2701
+ });
2702
+ const consumed = /* @__PURE__ */ new Set();
2703
+ rest.forEach((a, i) => {
2704
+ if (["--as", "--secret", "--query", "--param"].includes(a)) {
2705
+ consumed.add(i);
2706
+ consumed.add(i + 1);
2707
+ } else if (a === "--json") consumed.add(i);
2708
+ });
2709
+ const cleaned = rest.filter((_, i) => !consumed.has(i));
2710
+ const { pos, opts, bad } = cloudArgs(cleaned);
2711
+ if (bad !== void 0) {
2712
+ process.stderr.write(`error: ${bad}
2713
+
2714
+ ${commandHelp("decrypt") ?? ""}`);
2715
+ return 1;
2716
+ }
2717
+ const ws = pos[0];
2718
+ if (ws === void 0 || as === void 0 || secret === void 0 || q === void 0) {
2719
+ process.stderr.write(`error: usage: githolon decrypt <ws> --as <principal> --secret <b64> --query <id> [--param k=v ...]
2720
+ `);
2721
+ return 1;
2722
+ }
2723
+ return decrypt(ws, { ...opts, as, secret, query: q, params, ...json ? { json: true } : {} });
2724
+ }
2564
2725
  if (argv[0] === "status") {
2565
2726
  const { pos, opts, bad } = cloudArgs(argv.slice(1));
2566
2727
  if (bad !== void 0) {
@@ -2633,8 +2794,8 @@ ${USAGE}`);
2633
2794
  let parsed;
2634
2795
  try {
2635
2796
  parsed = parseArgs(argv);
2636
- } catch (err9) {
2637
- process.stderr.write(`error: ${err9.message}
2797
+ } catch (err10) {
2798
+ process.stderr.write(`error: ${err10.message}
2638
2799
 
2639
2800
  ${USAGE}`);
2640
2801
  return 1;
@@ -2653,8 +2814,8 @@ ${USAGE}`);
2653
2814
  process.stdout.write(`created ${path}
2654
2815
  `);
2655
2816
  return 0;
2656
- } catch (err9) {
2657
- process.stderr.write(`error: ${err9.message}
2817
+ } catch (err10) {
2818
+ process.stderr.write(`error: ${err10.message}
2658
2819
  `);
2659
2820
  return 1;
2660
2821
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@bjorn3/browser_wasi_shim": "0.4.2",
30
- "@githolon/dsl": "^0.5.0",
30
+ "@githolon/dsl": "^0.6.0",
31
31
  "isomorphic-git": "^1.38.4"
32
32
  },
33
33
  "devDependencies": {