githolon 0.24.1 → 0.25.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 +89 -17
  2. package/package.json +3 -3
package/dist/cli.mjs CHANGED
@@ -53,7 +53,7 @@ async function ensureDeviceKey(holon, principal) {
53
53
  return key;
54
54
  }
55
55
  function resolveGovernancePrincipal(opts) {
56
- const principal = opts.principal ?? currentPrincipal();
56
+ const principal = opts.principal ?? activePrincipal();
57
57
  if (principal === void 0) {
58
58
  throw new Error(
59
59
  "signed governance needs a principal \u2014 githolon login --agent (self-onboarding), or pass --principal <your-auth-uid>"
@@ -124,7 +124,7 @@ async function grantOrRevoke(verb, kind, subject, opts) {
124
124
  }
125
125
  async function keyEnroll(opts) {
126
126
  const cloud = cloudBase(opts.cloud);
127
- const principal = opts.principal ?? currentPrincipal();
127
+ const principal = opts.principal ?? activePrincipal();
128
128
  if (principal === void 0) {
129
129
  err("enroll needs a principal \u2014 githolon login --agent first (or --principal <uid>)");
130
130
  return 1;
@@ -155,7 +155,7 @@ async function keyEnroll(opts) {
155
155
  return 0;
156
156
  }
157
157
  async function keyShow(opts) {
158
- const principal = opts.principal ?? currentPrincipal();
158
+ const principal = opts.principal ?? activePrincipal();
159
159
  if (principal === void 0) {
160
160
  out("no principal on file \u2014 githolon login --agent, or pass --principal <uid>");
161
161
  return 0;
@@ -192,7 +192,7 @@ function seedFromInput(input, opts) {
192
192
  );
193
193
  }
194
194
  async function keyImport(opts) {
195
- const principal = opts.principal ?? currentPrincipal();
195
+ const principal = opts.principal ?? activePrincipal();
196
196
  if (principal === void 0) {
197
197
  err("key import needs --principal <uid> (the auth-uid this key authors as)");
198
198
  return 1;
@@ -221,7 +221,7 @@ async function keyImport(opts) {
221
221
  return 0;
222
222
  }
223
223
  async function keyExport(opts) {
224
- const principal = opts.principal ?? currentPrincipal();
224
+ const principal = opts.principal ?? activePrincipal();
225
225
  if (principal === void 0) {
226
226
  err("key export needs --principal <uid>");
227
227
  return 1;
@@ -351,6 +351,9 @@ var init_governance = __esm({
351
351
  // src/cloud.ts
352
352
  var cloud_exports = {};
353
353
  __export(cloud_exports, {
354
+ activePrincipal: () => activePrincipal,
355
+ authUse: () => authUse,
356
+ clearActAs: () => clearActAs,
354
357
  cloudBase: () => cloudBase,
355
358
  configDir: () => configDir,
356
359
  currentPrincipal: () => currentPrincipal,
@@ -366,6 +369,7 @@ __export(cloud_exports, {
366
369
  secretRotate: () => secretRotate,
367
370
  secretSet: () => secretSet,
368
371
  sessionToken: () => sessionToken,
372
+ setActAs: () => setActAs,
369
373
  setDeviceKey: () => setDeviceKey,
370
374
  setPrincipal: () => setPrincipal,
371
375
  setSecret: () => setSecret,
@@ -420,6 +424,43 @@ function currentPrincipal() {
420
424
  const c = loadCreds();
421
425
  return c.session?.uid ?? c.principal;
422
426
  }
427
+ function activePrincipal() {
428
+ return loadCreds().actAs ?? currentPrincipal();
429
+ }
430
+ function setActAs(principal) {
431
+ const c = loadCreds();
432
+ c.actAs = principal;
433
+ saveCreds(c);
434
+ }
435
+ function clearActAs() {
436
+ const c = loadCreds();
437
+ delete c.actAs;
438
+ saveCreds(c);
439
+ }
440
+ async function authUse(principal, opts = {}) {
441
+ if (opts.clear === true) {
442
+ clearActAs();
443
+ out2("\u2713 cleared the active signing principal \u2014 signed lanes fall back to the session / bare default");
444
+ return 0;
445
+ }
446
+ if (principal === void 0) {
447
+ const c = loadCreds();
448
+ const active = c.actAs;
449
+ out2(active !== void 0 ? `acting as ${active}${getDeviceKey(active) ? " (key on file \u2713)" : " \u26A0 no signing key \u2014 githolon key import --principal " + active}` : "no active signing principal set (githolon use <uid>) \u2014 signed lanes use the session / bare default");
450
+ const keyed = Object.keys(c.devices ?? {});
451
+ if (keyed.length > 0) {
452
+ out2(`keys on file:`);
453
+ for (const p of keyed) out2(` ${p}${p === active ? " \u2190 active" : ""}`);
454
+ }
455
+ return 0;
456
+ }
457
+ setActAs(principal);
458
+ out2(`\u2713 now acting as ${principal} (signed deploy/gov/grant/key author as this principal)`);
459
+ if (getDeviceKey(principal) === void 0) {
460
+ out2(` \u26A0 no signing key on file for ${principal} yet \u2014 import it: githolon key import --principal ${principal} --secret <key>`);
461
+ }
462
+ return 0;
463
+ }
423
464
  function getDeviceKey(principal) {
424
465
  return loadCreds().devices?.[principal];
425
466
  }
@@ -510,13 +551,21 @@ async function whoami() {
510
551
  const c = loadCreds();
511
552
  if (c.session !== void 0) {
512
553
  out2(`session: ${c.session.anonymous ? "anonymous agent" : "account"} uid ${c.session.uid} (auth ${c.session.url})`);
513
- return 0;
514
- }
515
- if (c.principal !== void 0) {
554
+ } else if (c.principal !== void 0) {
516
555
  out2(`bare principal (transitional, unverified): ${c.principal}`);
517
- return 0;
556
+ } else {
557
+ out2("not logged in \u2014 githolon login --agent, or pass --principal <uid> per birth");
558
+ }
559
+ const active = activePrincipal();
560
+ if (c.actAs !== void 0) {
561
+ out2(`acting as: ${c.actAs}${getDeviceKey(c.actAs) ? " (key on file \u2713)" : " \u26A0 no signing key"} [githolon use <uid> to switch]`);
562
+ } else if (active !== void 0) {
563
+ out2(`signed lanes act as: ${active} (the session/bare default \u2014 githolon use <uid> to switch)`);
564
+ }
565
+ const keyed = Object.keys(c.devices ?? {});
566
+ if (keyed.length > 0) {
567
+ out2(`signing keys on file: ${keyed.map((p) => p === active ? `${p} \u2190active` : p).join(", ")}`);
518
568
  }
519
- out2("not logged in \u2014 githolon login --agent, or pass --principal <uid> per birth");
520
569
  return 0;
521
570
  }
522
571
  async function logout() {
@@ -657,7 +706,7 @@ async function deploy(ws, opts) {
657
706
  }
658
707
  const fileName = file.split("/").pop();
659
708
  const before = await fetch(`${cloud}/v2/workspaces/${ws}/domains`).then((br) => br.json()).then((bd) => bd.ok === true ? bd.domains ?? [] : []).catch(() => []);
660
- const principal = opts.principal ?? currentPrincipal();
709
+ const principal = opts.principal ?? activePrincipal();
661
710
  const signed = opts.principal !== void 0 || principal !== void 0 && getDeviceKey(principal) !== void 0;
662
711
  let phaseSuffix = "";
663
712
  let deployedHash;
@@ -2418,7 +2467,16 @@ var HELP = {
2418
2467
  },
2419
2468
  whoami: {
2420
2469
  usage: "githolon whoami",
2421
- what: "Show the principal births will ride (session uid, or the transitional bare uid)."
2470
+ what: "Show the principal births will ride (session uid, or the transitional bare uid), the ACTIVE\nsigning principal (githolon use), and the signing keys on file."
2471
+ },
2472
+ use: {
2473
+ usage: "githolon use [<uid>] [--clear]",
2474
+ what: "Set, show, or clear the ACTIVE signing principal \u2014 the one the signed lanes (deploy, gov, grant,\nkey) author as by DEFAULT, without an explicit --as. Pair with `githolon key import` to hold an\nenrolled key per principal (a platform admin key, your own uid, \u2026) and switch which one acts with\none command. `--as`/`--principal` still overrides per-command. No argument shows the active\nprincipal + keys on file; `--clear` falls back to the session/bare default. Stored in ~/.holon.",
2475
+ flags: [
2476
+ ["<uid>", "the auth-uid to act as (must have a signing key \u2014 githolon key import)"],
2477
+ ["--clear", "clear the active principal (signed lanes use the session/bare default)"]
2478
+ ],
2479
+ examples: ["githolon use d205ca94-...", "githolon use", "githolon use --clear"]
2422
2480
  },
2423
2481
  logout: {
2424
2482
  usage: "githolon logout",
@@ -2494,14 +2552,15 @@ var HELP = {
2494
2552
  examples: ["githolon revoke creation 32c7100e-\u2026", "githolon revoke admin 32c7100e-\u2026"]
2495
2553
  },
2496
2554
  deploy: {
2497
- usage: "githolon deploy [<ws>] [--file <deploy.json>] [--cloud <url>] [--target <name>]",
2498
- what: "POST build/*.deploy.json on the OPEN deploy lane (kernel-gated \u2014 no host secret). Prints what\nMOVED (old \u2192 new law hash). With no <ws>, the project's `workspace` binding in nomos.package.mjs\nresolves it.",
2555
+ usage: "githolon deploy [<ws>] [--as <uid>] [--file <deploy.json>] [--cloud <url>] [--target <name>]",
2556
+ what: "Deploy build/*.deploy.json \u2014 kernel-gated, no host secret. TWO lanes, picked automatically:\n\u2022 SIGNED (a WARRANTED ws, or when --as / the active `githolon use` principal has a signing key on\n file): signs a `nomos/installDomain` offer with that key and relays it; the kernel re-verifies the\n signature + judges the installDomain relation. Required for warranted platforms (co2, tbx) \u2014 an\n unsigned install is refused there.\n\u2022 OPEN (unwarranted ws / no key): the open POST /domains, still kernel-judged.\nAfter the POST it re-reads the workspace and CONFIRMS the deployed hash is the CURRENT serving law\n(exit 2 if committed-but-not-current). Prints what MOVED (old \u2192 new law hash). With no <ws>, the\nproject's `workspace` binding in nomos.package.mjs resolves it.",
2499
2557
  flags: [
2558
+ ["--as <uid>", "deploy as this principal via the SIGNED lane (needs its key \u2014 githolon key import; else githolon use)"],
2500
2559
  ["--file <path>", "an explicit deploy body (default: the one build/*.deploy.json)"],
2501
2560
  ["--target <name>", "pick among named targets (workspace: { dev: \u2026, prod: \u2026 })"],
2502
2561
  ["--cloud <url>", "target cloud"]
2503
2562
  ],
2504
- examples: ["githolon deploy", "githolon deploy my-guestbook", "githolon deploy --target prod"]
2563
+ examples: ["githolon deploy", "githolon deploy my-guestbook", "githolon use <admin-uid> && githolon deploy co2-platform", "githolon deploy tbx --as <admin-uid>"]
2505
2564
  },
2506
2565
  secret: {
2507
2566
  usage: "githolon secret <set <ws> <push-password> | rotate <ws>> [--cloud <url>]",
@@ -2988,7 +3047,9 @@ Authoring:
2988
3047
  Identity (~/.holon/credentials.json \u2014 sessions auto-refresh):
2989
3048
  githolon login --agent anonymous sign-in: a verified self-onboarded identity
2990
3049
  githolon login --token <refresh_token> adopt an existing captain app session
2991
- githolon whoami show the principal births will ride
3050
+ githolon whoami show the principal births will ride + keys on file
3051
+ githolon use [<uid>] [--clear] set/show/clear the ACTIVE signing principal: the one
3052
+ deploy/gov/grant/key author as (--as overrides per-cmd)
2992
3053
  githolon logout clear the session (workspace secrets kept)
2993
3054
  githolon key enroll [--principal <uid>] [--parent <ws>] mint a signing device key + enroll it on-chain
2994
3055
  (secret stays local; warrants SIGNED governance)
@@ -3044,12 +3105,13 @@ function cloudArgs(rest) {
3044
3105
  const pos = [];
3045
3106
  const opts = {};
3046
3107
  const VALUE_FLAGS = ["--cloud", "--principal", "--as", "--file", "--target", "--parent", "--via", "--max", "--label", "--secret", "--payload", "--payload-file", "--save", "--format"];
3047
- const BOOL_FLAGS = ["--sha256", "--stamp", "--yes"];
3108
+ const BOOL_FLAGS = ["--sha256", "--stamp", "--yes", "--clear"];
3048
3109
  for (let i = 0; i < rest.length; i++) {
3049
3110
  const a = rest[i];
3050
3111
  if (BOOL_FLAGS.includes(a)) {
3051
3112
  if (a === "--sha256") opts.sha256 = true;
3052
3113
  else if (a === "--stamp") opts.stamp = true;
3114
+ else if (a === "--clear") opts.clear = true;
3053
3115
  else opts.yes = true;
3054
3116
  } else if (VALUE_FLAGS.includes(a)) {
3055
3117
  const v = rest[++i];
@@ -3453,6 +3515,16 @@ ${USAGE}`);
3453
3515
  }
3454
3516
  if (argv[0] === "whoami") return whoami();
3455
3517
  if (argv[0] === "logout") return logout();
3518
+ if (argv[0] === "use") {
3519
+ const { pos, opts, bad } = cloudArgs(argv.slice(1));
3520
+ if (bad !== void 0) {
3521
+ process.stderr.write(`error: ${bad}
3522
+
3523
+ ${USAGE}`);
3524
+ return 1;
3525
+ }
3526
+ return authUse(pos[0], { clear: opts.clear === true });
3527
+ }
3456
3528
  if (argv[0] === "ledger") {
3457
3529
  const { pos, opts, bad } = cloudArgs(argv.slice(1));
3458
3530
  if (bad !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.24.1",
3
+ "version": "0.25.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",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@bjorn3/browser_wasi_shim": "0.4.2",
32
- "@githolon/client": "^0.24.1",
33
- "@githolon/dsl": "^0.24.1",
32
+ "@githolon/client": "^0.25.0",
33
+ "@githolon/dsl": "^0.25.0",
34
34
  "isomorphic-git": "^1.38.4"
35
35
  },
36
36
  "devDependencies": {