@astrale-os/cli 0.8.1-alpha.4 → 0.8.1-alpha.6

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/astrale.js +827 -575
  3. package/dist/public/connect-core.js +22 -16
  4. package/dist/public/keys/index.js +3 -10
  5. package/dist/public/paths/index.js +3 -10
  6. package/dist/types/lib/instance-target.d.ts +2 -0
  7. package/dist/types/lib/invocation.d.ts +3 -0
  8. package/dist/types/lib/log.d.ts +6 -5
  9. package/dist/types/lib/output.d.ts +6 -2
  10. package/package.json +1 -1
  11. package/src/commands/__tests__/introspect-parse.test.ts +21 -0
  12. package/src/commands/__tests__/logs.test.ts +5 -0
  13. package/src/commands/__tests__/read-commands.test.ts +11 -1
  14. package/src/commands/__tests__/token-ttl.test.ts +21 -0
  15. package/src/commands/auth/token.ts +19 -7
  16. package/src/commands/call.ts +18 -43
  17. package/src/commands/get.ts +23 -5
  18. package/src/commands/identity/create.ts +11 -2
  19. package/src/commands/identity/delete.ts +8 -2
  20. package/src/commands/identity/export.ts +8 -2
  21. package/src/commands/identity/import.ts +11 -2
  22. package/src/commands/identity/sync.ts +8 -2
  23. package/src/commands/identity/unsync.ts +12 -2
  24. package/src/commands/identity/use.ts +8 -2
  25. package/src/commands/identity/whoami.ts +1 -1
  26. package/src/commands/introspect.ts +117 -0
  27. package/src/commands/logs.ts +50 -6
  28. package/src/commands/mutate.ts +2 -3
  29. package/src/commands/query.ts +3 -5
  30. package/src/commands/token.ts +35 -8
  31. package/src/commands/update.ts +30 -9
  32. package/src/commands/view.ts +5 -3
  33. package/src/connection/__tests__/credential.test.ts +10 -0
  34. package/src/connection/__tests__/errors.test.ts +20 -0
  35. package/src/connection/credential.ts +3 -0
  36. package/src/connection/errors.ts +74 -12
  37. package/src/connection/session.ts +9 -0
  38. package/src/connection/target.ts +1 -0
  39. package/src/graph/__tests__/mutation.test.ts +6 -0
  40. package/src/graph/mutation.ts +13 -0
  41. package/src/identity/__tests__/registry.test.ts +1 -1
  42. package/src/identity/registry.ts +12 -5
  43. package/src/lib/__tests__/command-dx.test.ts +47 -15
  44. package/src/lib/__tests__/instance-target.test.ts +17 -0
  45. package/src/lib/__tests__/output.test.ts +12 -0
  46. package/src/lib/command-dx.ts +41 -23
  47. package/src/lib/instance-target.ts +18 -2
  48. package/src/lib/invocation.ts +11 -0
  49. package/src/lib/log.ts +17 -9
  50. package/src/lib/output.ts +20 -4
  51. package/src/program/__tests__/program.test.ts +4 -2
  52. package/src/program/build.ts +3 -9
  53. package/src/program/options.ts +2 -1
  54. package/src/state/__tests__/identities.test.ts +2 -2
  55. package/src/state/identities.ts +3 -10
  56. package/src/commands/describe.ts +0 -86
package/dist/astrale.js CHANGED
@@ -2571,127 +2571,6 @@ var init_source = __esm(() => {
2571
2571
  source_default = chalk;
2572
2572
  });
2573
2573
 
2574
- // package.json
2575
- var package_default;
2576
- var init_package = __esm(() => {
2577
- package_default = {
2578
- name: "@astrale-os/cli",
2579
- version: "0.8.1-alpha.4",
2580
- description: "Astrale CLI — connect to existing Astrale kernels",
2581
- keywords: [
2582
- "astrale",
2583
- "cli"
2584
- ],
2585
- license: "Apache-2.0",
2586
- author: "Astrale",
2587
- repository: {
2588
- type: "git",
2589
- url: "git+https://github.com/astrale-os/cli.git"
2590
- },
2591
- bin: {
2592
- astrale: "./dist/astrale.js"
2593
- },
2594
- files: [
2595
- "dist",
2596
- "src",
2597
- "tsconfig.json",
2598
- ".check-workspace.cjs",
2599
- "studio/server",
2600
- "studio/shared",
2601
- "studio/client/dist",
2602
- "studio/package.json",
2603
- "viewer/dist",
2604
- "THIRD-PARTY-NOTICES.md"
2605
- ],
2606
- type: "module",
2607
- exports: {
2608
- "./connect-core": {
2609
- types: "./dist/types/connect-core.d.ts",
2610
- import: "./dist/public/connect-core.js",
2611
- default: "./dist/public/connect-core.js"
2612
- },
2613
- "./keys": {
2614
- types: "./dist/types/keys/index.d.ts",
2615
- import: "./dist/public/keys/index.js",
2616
- default: "./dist/public/keys/index.js"
2617
- },
2618
- "./paths": {
2619
- types: "./dist/types/paths/index.d.ts",
2620
- import: "./dist/public/paths/index.js",
2621
- default: "./dist/public/paths/index.js"
2622
- },
2623
- "./identity-export-v1.schema.json": "./src/identity/.spec/schemas/identity-export-v1.schema.json"
2624
- },
2625
- publishConfig: {
2626
- access: "public",
2627
- registry: "https://registry.npmjs.org"
2628
- },
2629
- scripts: {
2630
- preinstall: "node .check-workspace.cjs",
2631
- prepare: "husky",
2632
- build: "bun scripts/build.ts",
2633
- prepack: "pnpm run package:check",
2634
- "package:check": "pnpm run typecheck && pnpm run test && pnpm run build && node scripts/verify-public-exports.mjs",
2635
- typecheck: "tsgo --noEmit && tsgo --noEmit -p tsconfig.tests.json && tsgo --noEmit -p viewer && tsgo --noEmit -p studio",
2636
- lint: "oxlint .",
2637
- "lint:fix": "oxlint --fix .",
2638
- format: "pnpm exec oxfmt --write .",
2639
- "format:check": "pnpm exec oxfmt --check .",
2640
- test: "bun test src",
2641
- "test:watch": "bun test --watch src"
2642
- },
2643
- dependencies: {
2644
- "@inquirer/prompts": "^8.5.2",
2645
- chalk: "^5.6.2",
2646
- chokidar: "^4.0.3",
2647
- commander: ">=13.0.0 <14.0.0",
2648
- jose: "^6.1.3",
2649
- ora: "^9.0.0",
2650
- "ts-morph": "^25.0.1",
2651
- yaml: "^2.8.2",
2652
- zod: "^3.25.0"
2653
- },
2654
- devDependencies: {
2655
- "@astrale-os/kernel-client": "0.6.0-beta.1",
2656
- "@astrale-os/ox": ">=0.1.0 <1.0.0",
2657
- "@astrale-os/sdk": "0.5.0-beta.1",
2658
- "@astrale-os/shell": "0.3.8-beta.1",
2659
- "@astrale/commitlint-config": "jsr:~2.0.1",
2660
- "@commitlint/cli": "~20.3.1",
2661
- "@commitlint/config-conventional": "~20.3.1",
2662
- "@types/bun": "^1.1.16",
2663
- "@types/node": "^22.0.0",
2664
- "@typescript/native-preview": "latest",
2665
- husky: "~9.1.7",
2666
- "lint-staged": "~16.2.7",
2667
- msgpackr: "^1.12.1",
2668
- oxfmt: "0.52.0",
2669
- oxlint: "latest",
2670
- typescript: "~6.0.1-rc"
2671
- },
2672
- "lint-staged": {
2673
- "*.{js,cjs,mjs,ts,tsx}": [
2674
- "oxlint --fix --no-error-on-unmatched-pattern",
2675
- "oxfmt --write"
2676
- ],
2677
- "*.{json,yml,yaml}": [
2678
- "oxfmt --write"
2679
- ]
2680
- },
2681
- devEngines: {
2682
- runtime: {
2683
- name: "node",
2684
- version: ">=24 <25",
2685
- onFail: "error"
2686
- }
2687
- },
2688
- engines: {
2689
- node: ">=22"
2690
- },
2691
- packageManager: "pnpm@11.13.1"
2692
- };
2693
- });
2694
-
2695
2574
  // node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
2696
2575
  var require_identity = __commonJS((exports) => {
2697
2576
  var ALIAS = Symbol.for("yaml.alias");
@@ -9682,6 +9561,12 @@ var init_dist = __esm(() => {
9682
9561
  $visitAsync = visit.visitAsync;
9683
9562
  });
9684
9563
 
9564
+ // src/lib/invocation.ts
9565
+ function invocationWantsMachine() {
9566
+ return argvMachine;
9567
+ }
9568
+ var argvMachine = false;
9569
+
9685
9570
  // src/lib/table.ts
9686
9571
  function visibleWidth(s) {
9687
9572
  return s.replace(ANSI, "").length;
@@ -9720,7 +9605,7 @@ var init_table = __esm(() => {
9720
9605
 
9721
9606
  // src/lib/output.ts
9722
9607
  function isMachine(opts) {
9723
- return !!(opts?.raw || opts?.json) || !(process.stdout.isTTY ?? false);
9608
+ return !!(opts?.raw || opts?.json || opts?.ci) || invocationWantsMachine() || !(process.stdout.isTTY ?? false);
9724
9609
  }
9725
9610
  function output(data, opts) {
9726
9611
  if (data === undefined)
@@ -9768,13 +9653,21 @@ function highlightJson(data) {
9768
9653
  const json = JSON.stringify(data, null, 2);
9769
9654
  return json.replace(/"([^"]+)"(?=\s*:)/g, (_, key) => source_default.cyan(`"${key}"`)).replace(/: "([^"]*)"(?=[,\n\r\]}])/g, (_, val) => `: ${source_default.green(`"${val}"`)}`).replace(/: (-?\d+\.?\d*(?:e[+-]?\d+)?)\b/gi, (_, num) => `: ${source_default.yellow(num)}`).replace(/: (true|false)\b/g, (_, bool) => `: ${source_default.magenta(bool)}`).replace(/: (null)\b/g, () => `: ${source_default.dim("null")}`);
9770
9655
  }
9656
+ function isNoiseKey(key) {
9657
+ if (NOISE_KEYS.has(key))
9658
+ return true;
9659
+ const dot = key.lastIndexOf(".");
9660
+ const colon = key.lastIndexOf(":");
9661
+ const split = Math.max(dot, colon);
9662
+ return split >= 0 && NOISE_KEYS.has(key.slice(split + 1));
9663
+ }
9771
9664
  function denoise(value) {
9772
9665
  if (Array.isArray(value))
9773
9666
  return value.map(denoise);
9774
9667
  if (value && typeof value === "object") {
9775
9668
  const out = {};
9776
9669
  for (const [k, v] of Object.entries(value)) {
9777
- if (NOISE_KEYS.has(k))
9670
+ if (isNoiseKey(k))
9778
9671
  continue;
9779
9672
  out[k] = v && typeof v === "object" ? denoise(v) : v;
9780
9673
  }
@@ -9838,6 +9731,127 @@ var init_output = __esm(() => {
9838
9731
  NOISE_KEYS = new Set(["schema", "icon", "code", "inputSchema", "outputSchema"]);
9839
9732
  });
9840
9733
 
9734
+ // package.json
9735
+ var package_default;
9736
+ var init_package = __esm(() => {
9737
+ package_default = {
9738
+ name: "@astrale-os/cli",
9739
+ version: "0.8.1-alpha.6",
9740
+ description: "Astrale CLI — connect to existing Astrale kernels",
9741
+ keywords: [
9742
+ "astrale",
9743
+ "cli"
9744
+ ],
9745
+ license: "Apache-2.0",
9746
+ author: "Astrale",
9747
+ repository: {
9748
+ type: "git",
9749
+ url: "git+https://github.com/astrale-os/cli.git"
9750
+ },
9751
+ bin: {
9752
+ astrale: "./dist/astrale.js"
9753
+ },
9754
+ files: [
9755
+ "dist",
9756
+ "src",
9757
+ "tsconfig.json",
9758
+ ".check-workspace.cjs",
9759
+ "studio/server",
9760
+ "studio/shared",
9761
+ "studio/client/dist",
9762
+ "studio/package.json",
9763
+ "viewer/dist",
9764
+ "THIRD-PARTY-NOTICES.md"
9765
+ ],
9766
+ type: "module",
9767
+ exports: {
9768
+ "./connect-core": {
9769
+ types: "./dist/types/connect-core.d.ts",
9770
+ import: "./dist/public/connect-core.js",
9771
+ default: "./dist/public/connect-core.js"
9772
+ },
9773
+ "./keys": {
9774
+ types: "./dist/types/keys/index.d.ts",
9775
+ import: "./dist/public/keys/index.js",
9776
+ default: "./dist/public/keys/index.js"
9777
+ },
9778
+ "./paths": {
9779
+ types: "./dist/types/paths/index.d.ts",
9780
+ import: "./dist/public/paths/index.js",
9781
+ default: "./dist/public/paths/index.js"
9782
+ },
9783
+ "./identity-export-v1.schema.json": "./src/identity/.spec/schemas/identity-export-v1.schema.json"
9784
+ },
9785
+ publishConfig: {
9786
+ access: "public",
9787
+ registry: "https://registry.npmjs.org"
9788
+ },
9789
+ scripts: {
9790
+ preinstall: "node .check-workspace.cjs",
9791
+ prepare: "husky",
9792
+ build: "bun scripts/build.ts",
9793
+ prepack: "pnpm run package:check",
9794
+ "package:check": "pnpm run typecheck && pnpm run test && pnpm run build && node scripts/verify-public-exports.mjs",
9795
+ typecheck: "tsgo --noEmit && tsgo --noEmit -p tsconfig.tests.json && tsgo --noEmit -p viewer && tsgo --noEmit -p studio",
9796
+ lint: "oxlint .",
9797
+ "lint:fix": "oxlint --fix .",
9798
+ format: "pnpm exec oxfmt --write .",
9799
+ "format:check": "pnpm exec oxfmt --check .",
9800
+ test: "bun test src",
9801
+ "test:watch": "bun test --watch src"
9802
+ },
9803
+ dependencies: {
9804
+ "@inquirer/prompts": "^8.5.2",
9805
+ chalk: "^5.6.2",
9806
+ chokidar: "^4.0.3",
9807
+ commander: ">=13.0.0 <14.0.0",
9808
+ jose: "^6.1.3",
9809
+ ora: "^9.0.0",
9810
+ "ts-morph": "^25.0.1",
9811
+ yaml: "^2.8.2",
9812
+ zod: "^3.25.0"
9813
+ },
9814
+ devDependencies: {
9815
+ "@astrale-os/kernel-client": "0.6.0-beta.1",
9816
+ "@astrale-os/ox": ">=0.1.0 <1.0.0",
9817
+ "@astrale-os/sdk": "0.5.0-beta.1",
9818
+ "@astrale-os/shell": "0.3.8-beta.1",
9819
+ "@astrale/commitlint-config": "jsr:~2.0.1",
9820
+ "@commitlint/cli": "~20.3.1",
9821
+ "@commitlint/config-conventional": "~20.3.1",
9822
+ "@types/bun": "^1.1.16",
9823
+ "@types/node": "^22.0.0",
9824
+ "@typescript/native-preview": "latest",
9825
+ husky: "~9.1.7",
9826
+ "lint-staged": "~16.2.7",
9827
+ msgpackr: "^1.12.1",
9828
+ oxfmt: "0.52.0",
9829
+ oxlint: "latest",
9830
+ typescript: "~6.0.1-rc"
9831
+ },
9832
+ "lint-staged": {
9833
+ "*.{js,cjs,mjs,ts,tsx}": [
9834
+ "oxlint --fix --no-error-on-unmatched-pattern",
9835
+ "oxfmt --write"
9836
+ ],
9837
+ "*.{json,yml,yaml}": [
9838
+ "oxfmt --write"
9839
+ ]
9840
+ },
9841
+ devEngines: {
9842
+ runtime: {
9843
+ name: "node",
9844
+ version: ">=24 <25",
9845
+ onFail: "error"
9846
+ }
9847
+ },
9848
+ engines: {
9849
+ node: ">=22"
9850
+ },
9851
+ packageManager: "pnpm@11.13.1"
9852
+ };
9853
+ });
9854
+
9841
9855
  // node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/lib/buffer_utils.js
9842
9856
  function concat(...buffers) {
9843
9857
  const size = buffers.reduce((acc, { length }) => acc + length, 0);
@@ -63337,17 +63351,10 @@ async function readDecoded(options) {
63337
63351
  function hasVersion(input) {
63338
63352
  return typeof input === "object" && input !== null && Object.hasOwn(input, "version");
63339
63353
  }
63340
- function seed(now) {
63354
+ function seed(_now) {
63341
63355
  return {
63342
- default: "manager",
63343
- identities: {
63344
- manager: {
63345
- subject: "manager",
63346
- createdAt: now.toISOString(),
63347
- source: "key",
63348
- mode: "local"
63349
- }
63350
- }
63356
+ default: "",
63357
+ identities: {}
63351
63358
  };
63352
63359
  }
63353
63360
  function encodeV1(store) {
@@ -66574,20 +66581,25 @@ function fatal(e, opts) {
66574
66581
  if (e instanceof Error && e.name === "ExitPromptError")
66575
66582
  process.exit(130);
66576
66583
  const msg = e instanceof Error ? e.message : String(e);
66577
- if (opts && isMachine(opts)) {
66578
- const error52 = e instanceof AstraleError ? e.code : e instanceof Error ? e.name : "Error";
66579
- const payload = { error: error52, message: msg };
66584
+ const code = e instanceof AstraleError ? e.code : e instanceof Error ? e.name : "Error";
66585
+ if (isMachine(opts)) {
66586
+ const payload = { error: code, message: msg };
66580
66587
  if (e instanceof AstraleError && e.hint)
66581
66588
  payload.hint = e.hint;
66582
66589
  process.stderr.write(JSON.stringify(payload) + `
66583
66590
  `);
66584
66591
  process.exit(1);
66585
66592
  }
66586
- log.error(msg);
66593
+ log.error(e instanceof AstraleError ? `${code}: ${msg}` : msg);
66587
66594
  if (e instanceof AstraleError && e.hint)
66588
66595
  log.dim(` hint: ${e.hint}`);
66589
66596
  process.exit(1);
66590
66597
  }
66598
+ function failClosed(error52, opts) {
66599
+ if (error52 instanceof AstraleError)
66600
+ fatal(error52, opts);
66601
+ fatal(new AstraleError("INVALID_INPUT", error52 instanceof Error ? error52.message : String(error52)), opts);
66602
+ }
66591
66603
  function fatalNotImplemented(feature, hint) {
66592
66604
  fatal(new NotImplementedError(feature, hint));
66593
66605
  }
@@ -67869,8 +67881,12 @@ async function createIdentity(name, options = {}) {
67869
67881
  kid: generated.kid,
67870
67882
  issuer: options.issuer
67871
67883
  };
67884
+ const hasDefault = store.default !== "" && store.identities[store.default] !== undefined;
67872
67885
  return {
67873
- next: { ...store, identities: { ...store.identities, [name]: identity3 } },
67886
+ next: {
67887
+ default: hasDefault ? store.default : name,
67888
+ identities: { ...store.identities, [name]: identity3 }
67889
+ },
67874
67890
  value: identity3
67875
67891
  };
67876
67892
  });
@@ -67904,10 +67920,10 @@ async function setDefault(name) {
67904
67920
  }
67905
67921
  async function getDefault() {
67906
67922
  const store = await readIdentities();
67907
- const identity3 = store.identities[store.default];
67908
- if (!identity3) {
67909
- throw new Error(`Default identity "${store.default}" not found. Run: astrale identity create ${store.default}`);
67923
+ if (store.default === "" || store.identities[store.default] === undefined) {
67924
+ throw new AstraleError("NO_IDENTITY", "No default identity.", "Run: astrale identity create <name>");
67910
67925
  }
67926
+ const identity3 = store.identities[store.default];
67911
67927
  return { ...identity3, name: store.default };
67912
67928
  }
67913
67929
  async function getIdentity(name) {
@@ -67974,6 +67990,7 @@ async function setIdentityMode(name, mode) {
67974
67990
  });
67975
67991
  }
67976
67992
  var init_registry = __esm(() => {
67993
+ init_errors2();
67977
67994
  init_keys2();
67978
67995
  init_idp();
67979
67996
  init_validation2();
@@ -71523,7 +71540,7 @@ var init_utils2 = __esm(() => {
71523
71540
  });
71524
71541
 
71525
71542
  // node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
71526
- var ANSI_RE, CONTROL_RE, CJKT_WIDE_RE, TAB_RE, EMOJI_RE, LATIN_RE, MODIFIER_RE, NO_TRUNCATION, getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
71543
+ var ANSI_RE2, CONTROL_RE, CJKT_WIDE_RE, TAB_RE, EMOJI_RE, LATIN_RE, MODIFIER_RE, NO_TRUNCATION, getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
71527
71544
  const LIMIT = truncationOptions.limit ?? Infinity;
71528
71545
  const ELLIPSIS = truncationOptions.ellipsis ?? "";
71529
71546
  const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
@@ -71536,7 +71553,7 @@ var ANSI_RE, CONTROL_RE, CJKT_WIDE_RE, TAB_RE, EMOJI_RE, LATIN_RE, MODIFIER_RE,
71536
71553
  const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
71537
71554
  const PARSE_BLOCKS = [
71538
71555
  [LATIN_RE, REGULAR_WIDTH],
71539
- [ANSI_RE, ANSI_WIDTH],
71556
+ [ANSI_RE2, ANSI_WIDTH],
71540
71557
  [CONTROL_RE, CONTROL_WIDTH],
71541
71558
  [TAB_RE, TAB_WIDTH],
71542
71559
  [EMOJI_RE, EMOJI_WIDTH],
@@ -71613,7 +71630,7 @@ var ANSI_RE, CONTROL_RE, CJKT_WIDE_RE, TAB_RE, EMOJI_RE, LATIN_RE, MODIFIER_RE,
71613
71630
  }, dist_default2;
71614
71631
  var init_dist6 = __esm(() => {
71615
71632
  init_utils2();
71616
- ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
71633
+ ANSI_RE2 = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
71617
71634
  CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
71618
71635
  CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
71619
71636
  TAB_RE = /\t{1,1000}/y;
@@ -87405,7 +87422,7 @@ async function formatKernelError(error52, isRaw, urlArg = "", debug = false, opt
87405
87422
  } else {
87406
87423
  console.log(source_default.red(` ${error52.message}`));
87407
87424
  }
87408
- log.dim(" Use `astrale call <path> --describe` to see the expected schema");
87425
+ log.dim(" Use `astrale introspect <path>` to see the expected schema");
87409
87426
  }
87410
87427
  break;
87411
87428
  }
@@ -87426,18 +87443,22 @@ async function formatKernelError(error52, isRaw, urlArg = "", debug = false, opt
87426
87443
  case "ResponseError": {
87427
87444
  const code = error52.code;
87428
87445
  const reason = error52.reason;
87446
+ const reasonCode = reason !== null && typeof reason === "object" && typeof reason.code === "string" ? reason.code : undefined;
87447
+ const hint = reasonCode === "FUNCTION_INPUT_INVALID" ? "Use `astrale introspect <path>` to see the callable input." : undefined;
87429
87448
  if (isRaw) {
87430
87449
  writeRaw({
87431
87450
  error: "RESPONSE_ERROR",
87432
87451
  ...code === undefined ? {} : { code },
87433
87452
  message: error52.message,
87434
- ...reason === undefined ? {} : { reason }
87453
+ ...reason === undefined ? {} : { reason },
87454
+ ...hint === undefined ? {} : { hint }
87435
87455
  });
87436
87456
  } else {
87437
87457
  log.error(`${source_default.bold(code === undefined ? "RESPONSE_ERROR" : `RESPONSE_ERROR(${String(code)})`)}: ${error52.message}`);
87438
- if (reason !== null && typeof reason === "object" && typeof reason.code === "string") {
87439
- log.dim(` reason: ${reason.code}`);
87440
- }
87458
+ if (reasonCode !== undefined)
87459
+ log.dim(` reason: ${reasonCode}`);
87460
+ if (hint !== undefined)
87461
+ log.dim(` ${hint}`);
87441
87462
  }
87442
87463
  break;
87443
87464
  }
@@ -87450,11 +87471,21 @@ async function formatKernelError(error52, isRaw, urlArg = "", debug = false, opt
87450
87471
  log.error(`${source_default.bold(`${type}(${code})`)}: ${error52.message}`);
87451
87472
  break;
87452
87473
  }
87453
- default:
87454
- if (isRaw)
87455
- writeRaw({ error: name || "UNKNOWN", message: error52.message });
87456
- else
87457
- log.error(`${source_default.bold(name || "Error")}: ${error52.message}`);
87474
+ default: {
87475
+ const mapped = mapPublicError(error52);
87476
+ if (isRaw) {
87477
+ writeRaw({
87478
+ error: mapped.code,
87479
+ message: mapped.message,
87480
+ ...mapped.hint === undefined ? {} : { hint: mapped.hint },
87481
+ ...mapped.timeoutMs === undefined ? {} : { timeoutMs: mapped.timeoutMs }
87482
+ });
87483
+ } else {
87484
+ log.error(`${source_default.bold(mapped.code)}: ${mapped.message}`);
87485
+ if (mapped.hint)
87486
+ log.dim(` ${mapped.hint}`);
87487
+ }
87488
+ }
87458
87489
  }
87459
87490
  if (debug)
87460
87491
  printDebug(error52, url3);
@@ -87462,6 +87493,46 @@ async function formatKernelError(error52, isRaw, urlArg = "", debug = false, opt
87462
87493
  function stripMethodSuffix(msg) {
87463
87494
  return msg.replace(/(\/[^"\s:]+)::([a-zA-Z]\w*)/g, "$1");
87464
87495
  }
87496
+ function mapPublicError(error52) {
87497
+ const name = error52.name;
87498
+ if (name === "PathError") {
87499
+ return { code: "PATH_INVALID", message: error52.message };
87500
+ }
87501
+ if (name === "NodeUnavailableError") {
87502
+ return {
87503
+ code: "NODE_UNAVAILABLE",
87504
+ message: error52.message,
87505
+ hint: "If this is a callable Path, use `astrale call` or `astrale introspect`."
87506
+ };
87507
+ }
87508
+ if (name === "AuthValueError") {
87509
+ return { code: "AUTH_VALUE_INVALID", message: error52.message };
87510
+ }
87511
+ if (name === "ClientError" && /timed out/i.test(error52.message)) {
87512
+ const timeoutMs = error52.timeoutMs;
87513
+ return {
87514
+ code: "TIMEOUT",
87515
+ message: error52.message,
87516
+ hint: "Try increasing with --timeout",
87517
+ ...timeoutMs === undefined ? {} : { timeoutMs }
87518
+ };
87519
+ }
87520
+ if (name === "ClientError" && /Publication discovery returned HTTP/i.test(error52.message)) {
87521
+ return {
87522
+ code: "KERNEL_DISCOVERY_FAILED",
87523
+ message: error52.message,
87524
+ hint: "Pass the Kernel issuer URL (no /invoke suffix), e.g. https://host/kernel/host"
87525
+ };
87526
+ }
87527
+ if (name === "Error" && /unable to connect/i.test(error52.message)) {
87528
+ return {
87529
+ code: "CONNECTION_ERROR",
87530
+ message: error52.message,
87531
+ hint: "Check --url / -i and that the Kernel is reachable. Try: astrale status"
87532
+ };
87533
+ }
87534
+ return { code: name && name !== "Error" ? name : "UNKNOWN", message: error52.message };
87535
+ }
87465
87536
  function writeRaw(payload) {
87466
87537
  process.stderr.write(JSON.stringify(payload) + `
87467
87538
  `);
@@ -88498,9 +88569,9 @@ async function resolveNamedInstanceTarget(identifier, opts) {
88498
88569
  try {
88499
88570
  managed = await opts.managed(identifier);
88500
88571
  } catch (e) {
88501
- if (!isManagedInstanceNotFound(e))
88502
- throw e;
88503
- throw notFound;
88572
+ if (isManagedInstanceNotFound(e) || isAdminDiscoveryFailure(e))
88573
+ throw notFound;
88574
+ throw e;
88504
88575
  }
88505
88576
  const url3 = normalizeInstanceKernelUrl(managed.url);
88506
88577
  return {
@@ -88566,6 +88637,9 @@ function adminTargetToInstance(target2) {
88566
88637
  ...target2.caFile ? { caFile: target2.caFile } : {}
88567
88638
  };
88568
88639
  }
88640
+ function isAdminDiscoveryFailure(error52) {
88641
+ return error52 instanceof AstraleError && ADMIN_DISCOVERY_CODES.has(error52.code);
88642
+ }
88569
88643
  function isManagedInstanceNotFound(error52) {
88570
88644
  if (error52 instanceof AstraleError && error52.code === "INSTANCE_NOT_FOUND")
88571
88645
  return true;
@@ -88578,11 +88652,22 @@ function isManagedInstanceNotFound(error52) {
88578
88652
  const data4 = error52.data;
88579
88653
  return error52.name === "KernelError" && !!data4 && typeof data4 === "object" && data4.type === "NotFoundError";
88580
88654
  }
88655
+ var ADMIN_DISCOVERY_CODES;
88581
88656
  var init_instance_target = __esm(() => {
88582
88657
  init_errors2();
88583
88658
  init_admin_target();
88584
88659
  init_instance2();
88585
88660
  init_validation2();
88661
+ ADMIN_DISCOVERY_CODES = new Set([
88662
+ "TOKEN_EXCHANGE_SOURCE_INVALID",
88663
+ "TOKEN_EXCHANGE_SOURCE_EXPIRED",
88664
+ "TOKEN_EXCHANGE_UNSUPPORTED",
88665
+ "TOKEN_EXCHANGE_DISCOVERY_FAILED",
88666
+ "TOKEN_EXCHANGE_PROTOCOL_ERROR",
88667
+ "TOKEN_EXCHANGE_INSECURE",
88668
+ "ADMIN_DOMAIN_ISSUER_MISSING",
88669
+ "ADMIN_INVENTORY_UNAVAILABLE"
88670
+ ]);
88586
88671
  });
88587
88672
 
88588
88673
  // src/connection/target.ts
@@ -88678,6 +88763,9 @@ function createCliCredential(target2, options, config2, fetch2 = globalThis.fetc
88678
88763
  return createConnectionCredential(target2.kernelIssuer, effective);
88679
88764
  }
88680
88765
  function validateCredentialSelection(options) {
88766
+ if (options.as !== undefined && options.creds !== undefined) {
88767
+ throw new AstraleError("INVALID_FLAG", "--as cannot be combined with --creds.");
88768
+ }
88681
88769
  if (options.anonymous !== true)
88682
88770
  return;
88683
88771
  const conflicting = [
@@ -88703,6 +88791,13 @@ var init_credential6 = __esm(() => {
88703
88791
  });
88704
88792
 
88705
88793
  // src/connection/session.ts
88794
+ function warnMissingExplicitTarget(options, target2) {
88795
+ if (options.instance !== undefined || options.url !== undefined)
88796
+ return;
88797
+ if (!isMachine(options))
88798
+ return;
88799
+ log.warn(`No -i/--url; using ${target2.slug ?? target2.url}`);
88800
+ }
88706
88801
  async function withClientSession(options, action) {
88707
88802
  validateCredentialSelection(options);
88708
88803
  const timeoutMs = resolveTimeoutMs(options.timeout);
@@ -88710,6 +88805,7 @@ async function withClientSession(options, action) {
88710
88805
  const target2 = await resolveConnectionTarget(options, config2, {
88711
88806
  managed: (slug) => lookupManagedInstance(slug, options)
88712
88807
  });
88808
+ warnMissingExplicitTarget(options, target2);
88713
88809
  return runResolvedClientSession(target2, timeoutMs, options, config2, action, openConnection);
88714
88810
  }
88715
88811
  async function withAdminClientSession(options, action) {
@@ -88787,6 +88883,8 @@ var init_session3 = __esm(() => {
88787
88883
  init_errors2();
88788
88884
  init_ca_fetch();
88789
88885
  init_config();
88886
+ init_log();
88887
+ init_output();
88790
88888
  init_credential6();
88791
88889
  init_target3();
88792
88890
  MAXIMUM_ROUTE_AGE_MS = 5 * 60000;
@@ -89384,7 +89482,7 @@ var init_whoami3 = __esm(() => {
89384
89482
  }
89385
89483
  console.log(`${source_default.bold(result.name)} (subject: ${result.subject})`);
89386
89484
  } catch (e) {
89387
- fatal(e);
89485
+ fatal(e, opts);
89388
89486
  }
89389
89487
  }
89390
89488
  };
@@ -89972,26 +90070,46 @@ async function refreshSdkDeps(check3, assumeYes = false) {
89972
90070
  return true;
89973
90071
  }
89974
90072
  async function cliStale(opts) {
90073
+ const running = package_default.version;
90074
+ const latest = await fetchNpmLatestVersion().catch(() => {
90075
+ return;
90076
+ });
89975
90077
  try {
89976
90078
  const r = await updateAstrale({
89977
90079
  check: true,
89978
90080
  channel: opts.channel,
89979
90081
  version: opts.version,
89980
- currentVersion: package_default.version
90082
+ currentVersion: running
89981
90083
  });
89982
- if (r.status === "updated")
89983
- return { stale: false, managed: false, current: r.currentVersion };
90084
+ if (r.status === "updated") {
90085
+ return { stale: false, managed: false, current: running, latest: latest ?? running };
90086
+ }
89984
90087
  return {
89985
- stale: r.status === "available",
90088
+ stale: latest !== undefined ? latest !== running : r.status === "available",
89986
90089
  managed: false,
89987
- current: r.currentVersion,
89988
- latest: r.latestVersion,
89989
- channel: r.channel
90090
+ current: running,
90091
+ latest: latest ?? r.latestVersion,
90092
+ channel: latest !== undefined ? "npm" : r.channel
89990
90093
  };
89991
90094
  } catch {
89992
- return { stale: false, managed: true };
90095
+ return {
90096
+ stale: latest !== undefined && latest !== running,
90097
+ managed: true,
90098
+ current: running,
90099
+ ...latest === undefined ? {} : { latest, channel: "npm" }
90100
+ };
89993
90101
  }
89994
90102
  }
90103
+ async function fetchNpmLatestVersion() {
90104
+ const response2 = await fetch("https://registry.npmjs.org/@astrale-os/cli/latest");
90105
+ if (!response2.ok)
90106
+ throw new Error(`npm registry HTTP ${response2.status}`);
90107
+ const body = await response2.json();
90108
+ if (body === null || typeof body !== "object" || typeof body.version !== "string") {
90109
+ throw new Error("npm registry latest document is missing version");
90110
+ }
90111
+ return body.version;
90112
+ }
89995
90113
  async function sdkStale() {
89996
90114
  if (!inDomainProject() || foreignPackageManager()) {
89997
90115
  return { stale: false, inProject: inDomainProject(), outdated: [] };
@@ -90109,140 +90227,6 @@ Examples:
90109
90227
  }
90110
90228
  };
90111
90229
  });
90112
- // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/errors.js
90113
- var UNKNOWN_OUTCOME_CODES;
90114
- var init_errors14 = __esm(() => {
90115
- UNKNOWN_OUTCOME_CODES = new Set(["MUTATION_OUTCOME_UNKNOWN"]);
90116
- });
90117
-
90118
- // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/rich.js
90119
- var init_rich = __esm(() => {
90120
- init_class();
90121
- init_path4();
90122
- init_v1();
90123
- });
90124
-
90125
- // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/execute.js
90126
- var init_execute2 = __esm(() => {
90127
- init_mutate();
90128
- init_errors14();
90129
- init_rich();
90130
- });
90131
-
90132
- // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/index.js
90133
- var init_mutation2 = __esm(() => {
90134
- init_execute2();
90135
- init_mutate();
90136
- });
90137
-
90138
- // src/graph/mutation.ts
90139
- function prepareMutation(input) {
90140
- if (isLegacyPatchData(input)) {
90141
- throw new TypeError("Legacy PatchData { nodes, edges } is not Mutation V3. Author { preconditions, operations } or a canonical astrale.graph.mutation/v3 document.");
90142
- }
90143
- if (isCanonicalCandidate(input))
90144
- return MutationAST.decode(input);
90145
- return MutationAST.create(input);
90146
- }
90147
- function isCanonicalCandidate(input) {
90148
- return input !== null && typeof input === "object" && !Array.isArray(input) && (Object.hasOwn(input, "format") || Object.hasOwn(input, "version"));
90149
- }
90150
- function isLegacyPatchData(input) {
90151
- return input !== null && typeof input === "object" && !Array.isArray(input) && !Object.hasOwn(input, "operations") && (Object.hasOwn(input, "nodes") || Object.hasOwn(input, "edges"));
90152
- }
90153
- var init_mutation3 = __esm(() => {
90154
- init_mutation2();
90155
- });
90156
-
90157
- // src/graph/projection.ts
90158
- function unqualifyProperty(key) {
90159
- const property2 = key.lastIndexOf(".property.");
90160
- if (property2 >= 0)
90161
- return key.slice(property2 + ".property.".length);
90162
- const slash = key.lastIndexOf("/");
90163
- return slash >= 0 ? key.slice(slash + 1) : key;
90164
- }
90165
- function nodeProperty(node4, name) {
90166
- const props4 = node4?.props;
90167
- if (props4 === undefined)
90168
- return;
90169
- if (Object.hasOwn(props4, name))
90170
- return props4[name];
90171
- for (const [key, value2] of Object.entries(props4)) {
90172
- if (unqualifyProperty(key) === name)
90173
- return value2;
90174
- }
90175
- return;
90176
- }
90177
-
90178
- // src/graph/query.ts
90179
- function prepareQuery(input) {
90180
- const limit = positiveInteger2(input.limit, "--limit", DEFAULT_LIMIT);
90181
- if (input.ast !== undefined) {
90182
- if (input.sources.length > 0 || input.definition !== undefined || input.edge !== undefined || input.direction !== undefined) {
90183
- throw new TypeError("--ast/--file cannot be combined with sources, --definition, --edge, or --direction");
90184
- }
90185
- return withPage(QueryAST.decode(input.ast), limit, input.cursor);
90186
- }
90187
- if (input.sources.length === 0 && input.definition === undefined) {
90188
- throw new TypeError("query requires a Path source, --definition, or a canonical Query V6 document");
90189
- }
90190
- if (input.direction !== undefined && input.edge === undefined) {
90191
- throw new TypeError("--direction requires --edge");
90192
- }
90193
- const paths4 = input.sources.map((source2) => Path.parse(source2));
90194
- const definition3 = input.definition === undefined ? undefined : definitionRef(input.definition);
90195
- const query3 = paths4.length > 0 ? Query2.from({
90196
- kind: "node",
90197
- paths: paths4,
90198
- ...definition3 === undefined ? {} : { definitions: [definition3] }
90199
- }) : Query2.from({ kind: "node", definitions: [definition3] });
90200
- const ast = input.edge === undefined ? query3.select({ kind: "graph" }) : query3.expand({
90201
- via: [definitionRef(input.edge)],
90202
- direction: input.direction ?? "outgoing"
90203
- }).select({ kind: "graph" });
90204
- return withPage(ast, limit, input.cursor);
90205
- }
90206
- function definitionRef(input) {
90207
- const path5 = Path.parse(input);
90208
- const step = path5.ast.steps[0];
90209
- if (path5.ast.anchor.kind !== "domain" || path5.ast.steps.length !== 1 || step?.kind !== "projection" || step.projection.kind !== "class" && step.projection.kind !== "interface") {
90210
- throw new TypeError("--definition must be one canonical Class or Interface Path");
90211
- }
90212
- return Object.freeze({
90213
- origin: path5.ast.anchor.origin,
90214
- kind: step.projection.kind,
90215
- name: step.projection.name
90216
- });
90217
- }
90218
- function positiveInteger2(raw2, name, fallback) {
90219
- if (raw2 === undefined)
90220
- return fallback;
90221
- if (!/^\d+$/.test(raw2))
90222
- throw new TypeError(`${name} must be a positive integer`);
90223
- const value2 = Number.parseInt(raw2, 10);
90224
- if (!Number.isSafeInteger(value2) || value2 <= 0) {
90225
- throw new TypeError(`${name} must be a positive integer`);
90226
- }
90227
- return value2;
90228
- }
90229
- function withPage(ast, size, cursor) {
90230
- return Object.freeze({
90231
- ast,
90232
- page: Object.freeze({ size, ...cursor === undefined ? {} : { after: cursor } })
90233
- });
90234
- }
90235
- var DEFAULT_LIMIT = 100;
90236
- var init_query6 = __esm(() => {
90237
- init_path5();
90238
- init_query4();
90239
- });
90240
-
90241
- // src/graph/index.ts
90242
- var init_graph6 = __esm(() => {
90243
- init_mutation3();
90244
- init_query6();
90245
- });
90246
90230
 
90247
90231
  // src/lib/binary.ts
90248
90232
  import { writeFile as writeFile5 } from "node:fs/promises";
@@ -90314,99 +90298,6 @@ var init_binary4 = __esm(() => {
90314
90298
  init_output();
90315
90299
  });
90316
90300
 
90317
- // src/commands/call-describe.ts
90318
- function describeCallableFromSchema(path5, schema2) {
90319
- if (path5.ast.anchor.kind !== "domain")
90320
- return;
90321
- const origin = path5.ast.anchor.origin;
90322
- const last = path5.ast.steps.at(-1);
90323
- const document = asRecord2(schema2);
90324
- if (document === undefined || last === undefined)
90325
- return;
90326
- if (last.kind === "method") {
90327
- const owner = path5.ast.steps.at(-2);
90328
- if (owner?.kind === "projection" && (owner.projection.kind === "class" || owner.projection.kind === "interface")) {
90329
- const bag = asRecord2(owner.projection.kind === "class" ? document.classes : document.interfaces);
90330
- const definition3 = asRecord2(bag?.[owner.projection.name]);
90331
- const method = asRecord2(asRecord2(definition3?.methods)?.[last.name]);
90332
- if (method !== undefined) {
90333
- return Object.freeze({
90334
- path: path5.raw,
90335
- origin,
90336
- class: owner.projection.name,
90337
- method: last.name,
90338
- dispatch: last.dispatch,
90339
- ...callableFields(method)
90340
- });
90341
- }
90342
- }
90343
- const matches3 = findNamedMethods(document, origin, path5.raw, last.name, last.dispatch);
90344
- if (matches3.length === 1)
90345
- return matches3[0];
90346
- if (matches3.length > 1) {
90347
- return Object.freeze({
90348
- path: path5.raw,
90349
- origin,
90350
- method: last.name,
90351
- dispatch: last.dispatch,
90352
- candidates: Object.freeze(matches3)
90353
- });
90354
- }
90355
- return;
90356
- }
90357
- if (last.kind === "projection" && last.projection.kind === "function") {
90358
- const fn2 = asRecord2(asRecord2(document.functions)?.[last.projection.name]);
90359
- if (fn2 === undefined)
90360
- return;
90361
- return Object.freeze({
90362
- path: path5.raw,
90363
- origin,
90364
- function: last.projection.name,
90365
- ...callableFields(fn2)
90366
- });
90367
- }
90368
- return;
90369
- }
90370
- function missingCallableDescription(path5) {
90371
- return new AstraleError("CALL_DESCRIBE_UNAVAILABLE", `No callable schema is installed for ${path5}.`, "Use a Domain-rooted Path such as /:host.astrale.ai:class.Manager:createInstance. Method Paths are not Function nodes.");
90372
- }
90373
- function findNamedMethods(schema2, origin, path5, method, dispatch) {
90374
- const matches3 = [];
90375
- for (const bag of [schema2.classes, schema2.interfaces]) {
90376
- const definitions2 = asRecord2(bag);
90377
- if (definitions2 === undefined)
90378
- continue;
90379
- for (const [className, definition3] of Object.entries(definitions2)) {
90380
- const methodDef = asRecord2(asRecord2(asRecord2(definition3)?.methods)?.[method]);
90381
- if (methodDef === undefined)
90382
- continue;
90383
- matches3.push(Object.freeze({
90384
- path: path5,
90385
- origin,
90386
- class: className,
90387
- method,
90388
- dispatch,
90389
- ...callableFields(methodDef)
90390
- }));
90391
- }
90392
- }
90393
- return matches3;
90394
- }
90395
- function callableFields(value2) {
90396
- return {
90397
- ...typeof value2.description === "string" ? { description: value2.description } : {},
90398
- ...value2.auth === undefined ? {} : { auth: value2.auth },
90399
- ...value2.input === undefined ? {} : { input: value2.input },
90400
- ...value2.output === undefined ? {} : { output: value2.output }
90401
- };
90402
- }
90403
- function asRecord2(input) {
90404
- return input !== null && typeof input === "object" && !Array.isArray(input) ? input : undefined;
90405
- }
90406
- var init_call_describe = __esm(() => {
90407
- init_errors2();
90408
- });
90409
-
90410
90301
  // src/commands/call.ts
90411
90302
  var exports_call = {};
90412
90303
  __export(exports_call, {
@@ -90422,19 +90313,19 @@ async function callCommand(path5, rawParams, opts) {
90422
90313
  try {
90423
90314
  expanded = await expandSelfInCall(path5, rawParams, opts);
90424
90315
  } catch (error52) {
90425
- log.error(error52 instanceof Error ? error52.message : "Invalid @self expansion");
90426
- process.exit(1);
90316
+ failClosed(error52, opts);
90427
90317
  }
90428
90318
  const expandedPath = expanded.path;
90429
- if (opts.describe) {
90430
- return describeOperation(expandedPath, opts);
90319
+ try {
90320
+ Path.parse(expandedPath);
90321
+ } catch (error52) {
90322
+ failClosed(error52, opts);
90431
90323
  }
90432
90324
  let params;
90433
90325
  try {
90434
90326
  params = await parseParams([...expanded.parameters], opts.data);
90435
90327
  } catch (e) {
90436
- log.error(e instanceof Error ? e.message : "Invalid params");
90437
- process.exit(1);
90328
+ failClosed(e, opts);
90438
90329
  }
90439
90330
  if (opts.dryRun) {
90440
90331
  output({ method: expandedPath, params }, opts);
@@ -90469,24 +90360,6 @@ async function materializeCallResult(result) {
90469
90360
  values.push(value2);
90470
90361
  return Object.freeze({ kind: "stream", values: Object.freeze(values) });
90471
90362
  }
90472
- async function describeOperation(path5, opts) {
90473
- await runKernelCommand({
90474
- opts,
90475
- label: `Schema for ${path5}`,
90476
- fn: async ({ graph }) => {
90477
- const parsed = Path.parse(path5);
90478
- if (parsed.ast.anchor.kind !== "domain") {
90479
- throw missingCallableDescription(path5);
90480
- }
90481
- const domain3 = await graph.getOrThrow(Path.parse(`/:${parsed.ast.anchor.origin}`));
90482
- const described = describeCallableFromSchema(parsed, nodeProperty(domain3, "schema"));
90483
- if (described === undefined)
90484
- throw missingCallableDescription(path5);
90485
- return described;
90486
- },
90487
- format: (schema2, fmtOpts) => output(schema2, fmtOpts)
90488
- });
90489
- }
90490
90363
  async function parseParams(rawParams, dataFlag) {
90491
90364
  if (dataFlag) {
90492
90365
  if (rawParams.length > 0) {
@@ -90498,6 +90371,9 @@ async function parseParams(rawParams, dataFlag) {
90498
90371
  throw new Error(`Invalid JSON in --data: ${dataFlag}`);
90499
90372
  }
90500
90373
  }
90374
+ if (rawParams.length > 0) {
90375
+ return parseKeyValue(rawParams);
90376
+ }
90501
90377
  const stdin = await readStdin();
90502
90378
  if (stdin) {
90503
90379
  try {
@@ -90506,9 +90382,6 @@ async function parseParams(rawParams, dataFlag) {
90506
90382
  throw new Error("Invalid JSON from stdin");
90507
90383
  }
90508
90384
  }
90509
- if (rawParams.length > 0) {
90510
- return parseKeyValue(rawParams);
90511
- }
90512
90385
  return {};
90513
90386
  }
90514
90387
  async function readStdin() {
@@ -90558,22 +90431,21 @@ var PARAM_KEY_RE, call_default;
90558
90431
  var init_call2 = __esm(() => {
90559
90432
  init_path5();
90560
90433
  init_connection2();
90561
- init_graph6();
90562
90434
  init_binary4();
90563
90435
  init_log();
90564
90436
  init_output();
90565
- init_call_describe();
90566
90437
  PARAM_KEY_RE = /^[A-Za-z_][A-Za-z0-9_-]*$/;
90567
90438
  call_default = {
90568
90439
  name: "call",
90569
90440
  description: "Call a kernel operation",
90570
90441
  afterHelpText: `
90571
90442
  Behavior:
90572
- Param priority (highest wins): --data > stdin > key=value > {}. If
90443
+ Param priority (highest wins): --data > key=value > stdin > {}. If
90573
90444
  both --data and key=value are given, key=value is ignored (warned).
90574
- Stdin is read only when piped (ignored on a TTY). --describe and
90575
- --dry-run short-circuit (no execution). Remote-bound functions
90576
- auto-mint a worker-scoped credential; --creds overrides it.
90445
+ Stdin is read only when piped and no --data/key=value is present
90446
+ (ignored on a TTY). --dry-run admits the Path and prints the call
90447
+ input without executing. Remote-bound functions auto-mint a
90448
+ worker-scoped credential; --creds overrides it.
90577
90449
 
90578
90450
  Self-reference:
90579
90451
  @self expands to your nodeId on the active instance (path head or
@@ -90582,11 +90454,10 @@ Self-reference:
90582
90454
  (e.g. via 'astrale get @self --json'). Resolution authenticates to
90583
90455
  the selected Kernel and never trusts a local registration or JWT sub.
90584
90456
 
90585
- --describe reads the callable's input/output from the installed Domain
90586
- schema. Method Paths are not Function nodes.
90457
+ Callable input/output lives on astrale introspect <path>.
90587
90458
 
90588
90459
  Examples:
90589
- $ astrale call /:host.astrale.ai:class.Manager:createInstance --describe
90460
+ $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
90590
90461
  $ astrale call /:blog.acme.com:class.Author:list limit=10
90591
90462
  $ astrale call '@self::deactivate'
90592
90463
  $ astrale call /:kernel.astrale.ai:function.journal --data '{"limit":5}' --json
@@ -90601,7 +90472,6 @@ Examples:
90601
90472
  options: [
90602
90473
  { flags: "-d, --data <json>", description: "Params as JSON string" },
90603
90474
  { flags: "-o, --output <file>", description: "Write binary/raw output to a file" },
90604
- { flags: "--describe", description: "Show operation schema without executing" },
90605
90475
  { flags: "--dry-run", description: "Show what would be sent without executing" }
90606
90476
  ],
90607
90477
  action: async (path5, params, opts) => {
@@ -90614,17 +90484,17 @@ Examples:
90614
90484
  var exports_token = {};
90615
90485
  __export(exports_token, {
90616
90486
  tokenCommand: () => tokenCommand,
90487
+ parseTtl: () => parseTtl,
90617
90488
  default: () => token_default
90618
90489
  });
90619
90490
  async function tokenCommand(opts) {
90620
90491
  const commandOpts = opts.for && !opts.as ? { ...opts, as: opts.for } : opts;
90492
+ const ttl = parseTtl(commandOpts.ttl);
90621
90493
  await runKernelCommand({
90622
90494
  opts: commandOpts,
90623
90495
  label: "Minting delegation token",
90624
90496
  fn: async (ctx) => {
90625
90497
  const audience = commandOpts.audience === undefined ? ctx.target.kernelIssuer : exports_issuer.accept(commandOpts.audience);
90626
- const parsedTtl = Number(commandOpts.ttl);
90627
- const ttl = Number.isFinite(parsedTtl) && parsedTtl > 0 ? parsedTtl : 3600;
90628
90498
  const self4 = await ctx.auth.whoami();
90629
90499
  return ctx.auth.delegate(self4.id, {
90630
90500
  audience,
@@ -90632,23 +90502,39 @@ async function tokenCommand(opts) {
90632
90502
  attenuation: { kind: "identity", self: true }
90633
90503
  });
90634
90504
  },
90635
- format: (token, fmtOpts, isRaw) => {
90636
- if (isRaw) {
90637
- process.stdout.write(token + `
90638
- `);
90505
+ format: (token, fmtOpts) => {
90506
+ if (fmtOpts.json || fmtOpts.format !== undefined) {
90507
+ output({ token, expiresAt: decodeJwtExpiration(token)?.expiresAt ?? null }, fmtOpts);
90639
90508
  return;
90640
90509
  }
90641
- log.dim(" (delegation token ES256, self-identity)");
90510
+ if (!fmtOpts.raw && (process.stdout.isTTY ?? false)) {
90511
+ log.dim(" (delegation token — ES256, self-identity)");
90512
+ }
90642
90513
  process.stdout.write(`${token}
90643
90514
  `);
90644
90515
  }
90645
90516
  });
90646
90517
  }
90518
+ function parseTtl(raw2) {
90519
+ if (raw2 === undefined)
90520
+ return 3600;
90521
+ if (!/^\d+$/.test(raw2)) {
90522
+ throw new AstraleError("INVALID_FLAG", `Invalid --ttl value "${raw2}" — expected a positive integer (seconds)`);
90523
+ }
90524
+ const value2 = Number.parseInt(raw2, 10);
90525
+ if (!Number.isSafeInteger(value2) || value2 <= 0) {
90526
+ throw new AstraleError("INVALID_FLAG", `Invalid --ttl value "${raw2}" — must be a positive integer`);
90527
+ }
90528
+ return value2;
90529
+ }
90647
90530
  var token_default;
90648
90531
  var init_token = __esm(() => {
90649
90532
  init_auth2();
90650
90533
  init_connection2();
90534
+ init_errors2();
90535
+ init_local_status();
90651
90536
  init_log();
90537
+ init_output();
90652
90538
  token_default = {
90653
90539
  name: "token",
90654
90540
  description: "Mint a fresh delegation token for the active instance + identity",
@@ -90664,6 +90550,7 @@ Behavior:
90664
90550
 
90665
90551
  Examples:
90666
90552
  $ export TOKEN=$(astrale token --audience shell.astrale.ai --raw)
90553
+ $ astrale token --json -i staging
90667
90554
  $ astrale token --audience worker.example.com --for alice -i staging
90668
90555
  `,
90669
90556
  options: [
@@ -90675,7 +90562,11 @@ Examples:
90675
90562
  { flags: "--for <identity>", description: "Mint the token for this identity (alias of --as)" }
90676
90563
  ],
90677
90564
  action: async (opts) => {
90678
- await tokenCommand(opts);
90565
+ try {
90566
+ await tokenCommand(opts);
90567
+ } catch (error52) {
90568
+ failClosed(error52, opts);
90569
+ }
90679
90570
  }
90680
90571
  };
90681
90572
  });
@@ -90689,17 +90580,25 @@ __export(exports_get, {
90689
90580
  async function getCommand(target2, opts) {
90690
90581
  let path5;
90691
90582
  let meta3;
90583
+ let parsed;
90692
90584
  try {
90693
90585
  ({ path: path5, meta: meta3 } = await expandSelfInPath(target2, opts));
90586
+ parsed = Path.parse(path5);
90694
90587
  } catch (error52) {
90695
90588
  await formatKernelError(error52, isMachine(opts), undefined, opts.debug);
90696
90589
  process.exit(1);
90697
90590
  }
90591
+ const last = parsed.ast.steps.at(-1);
90592
+ if (last?.kind === "method") {
90593
+ const error52 = new AstraleError("NOT_A_NODE", `${path5} is a callable Path, not a Node.`, `Use \`astrale call ${path5}\` or \`astrale introspect ${path5}\`.`);
90594
+ await formatKernelError(error52, isMachine(opts), undefined, opts.debug);
90595
+ process.exit(1);
90596
+ }
90698
90597
  await runKernelCommand({
90699
90598
  opts,
90700
90599
  label: `Node ${path5}`,
90701
- fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(Path.parse(path5)), meta3),
90702
- format: (node4, format3) => output(node4, format3)
90600
+ fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(parsed), meta3),
90601
+ format: (node4, format3) => output(opts.schema === true ? node4 : denoise(node4), format3)
90703
90602
  });
90704
90603
  }
90705
90604
  var get_default;
@@ -90707,6 +90606,7 @@ var init_get = __esm(() => {
90707
90606
  init_path5();
90708
90607
  init_connection2();
90709
90608
  init_errors12();
90609
+ init_errors2();
90710
90610
  init_output();
90711
90611
  get_default = {
90712
90612
  name: "get",
@@ -90718,19 +90618,141 @@ Behavior:
90718
90618
  intentionally indistinguishable. @self is expanded before dispatch.
90719
90619
 
90720
90620
  A Node does not contain a synthetic path, labels, or backend class ID.
90721
- Use astrale query for graph-shaped reads.
90621
+ Method Paths are not Nodes — use call / introspect. Schema-valued
90622
+ properties are omitted unless --schema is passed. Use query for
90623
+ graph-shaped reads.
90722
90624
 
90723
90625
  Examples:
90724
90626
  $ astrale get /:notes.example.dev:class.Note
90725
90627
  $ astrale get @abc123 --json
90726
90628
  $ astrale get @self
90629
+ $ astrale get /:host.astrale.ai --schema
90727
90630
  `,
90728
90631
  arguments: [{ name: "target", description: "Canonical Node Path or @id" }],
90632
+ options: [{ flags: "--schema", description: "Include schema-valued properties" }],
90729
90633
  action: async (target2, opts) => {
90730
90634
  await getCommand(target2, opts);
90731
90635
  }
90732
90636
  };
90733
90637
  });
90638
+ // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/errors.js
90639
+ var UNKNOWN_OUTCOME_CODES;
90640
+ var init_errors14 = __esm(() => {
90641
+ UNKNOWN_OUTCOME_CODES = new Set(["MUTATION_OUTCOME_UNKNOWN"]);
90642
+ });
90643
+
90644
+ // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/rich.js
90645
+ var init_rich = __esm(() => {
90646
+ init_class();
90647
+ init_path4();
90648
+ init_v1();
90649
+ });
90650
+
90651
+ // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/execute.js
90652
+ var init_execute2 = __esm(() => {
90653
+ init_mutate();
90654
+ init_errors14();
90655
+ init_rich();
90656
+ });
90657
+
90658
+ // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/mutation/index.js
90659
+ var init_mutation2 = __esm(() => {
90660
+ init_execute2();
90661
+ init_mutate();
90662
+ });
90663
+
90664
+ // src/graph/mutation.ts
90665
+ function prepareMutation(input) {
90666
+ if (isLegacyPatchData(input)) {
90667
+ throw new TypeError("Legacy PatchData { nodes, edges } is not Mutation V3. Author { preconditions, operations } or a canonical astrale.graph.mutation/v3 document.");
90668
+ }
90669
+ if (hasEmptyOperations(input)) {
90670
+ throw new TypeError("Mutation V3 requires at least one operation");
90671
+ }
90672
+ if (isCanonicalCandidate(input))
90673
+ return MutationAST.decode(input);
90674
+ return MutationAST.create(input);
90675
+ }
90676
+ function hasEmptyOperations(input) {
90677
+ return input !== null && typeof input === "object" && !Array.isArray(input) && Array.isArray(input.operations) && input.operations.length === 0;
90678
+ }
90679
+ function isCanonicalCandidate(input) {
90680
+ return input !== null && typeof input === "object" && !Array.isArray(input) && (Object.hasOwn(input, "format") || Object.hasOwn(input, "version"));
90681
+ }
90682
+ function isLegacyPatchData(input) {
90683
+ return input !== null && typeof input === "object" && !Array.isArray(input) && !Object.hasOwn(input, "operations") && (Object.hasOwn(input, "nodes") || Object.hasOwn(input, "edges"));
90684
+ }
90685
+ var init_mutation3 = __esm(() => {
90686
+ init_mutation2();
90687
+ });
90688
+ // src/graph/query.ts
90689
+ function prepareQuery(input) {
90690
+ const limit = positiveInteger2(input.limit, "--limit", DEFAULT_LIMIT);
90691
+ if (input.ast !== undefined) {
90692
+ if (input.sources.length > 0 || input.definition !== undefined || input.edge !== undefined || input.direction !== undefined) {
90693
+ throw new TypeError("--ast/--file cannot be combined with sources, --definition, --edge, or --direction");
90694
+ }
90695
+ return withPage(QueryAST.decode(input.ast), limit, input.cursor);
90696
+ }
90697
+ if (input.sources.length === 0 && input.definition === undefined) {
90698
+ throw new TypeError("query requires a Path source, --definition, or a canonical Query V6 document");
90699
+ }
90700
+ if (input.direction !== undefined && input.edge === undefined) {
90701
+ throw new TypeError("--direction requires --edge");
90702
+ }
90703
+ const paths4 = input.sources.map((source2) => Path.parse(source2));
90704
+ const definition3 = input.definition === undefined ? undefined : definitionRef(input.definition);
90705
+ const query3 = paths4.length > 0 ? Query2.from({
90706
+ kind: "node",
90707
+ paths: paths4,
90708
+ ...definition3 === undefined ? {} : { definitions: [definition3] }
90709
+ }) : Query2.from({ kind: "node", definitions: [definition3] });
90710
+ const ast = input.edge === undefined ? query3.select({ kind: "graph" }) : query3.expand({
90711
+ via: [definitionRef(input.edge)],
90712
+ direction: input.direction ?? "outgoing"
90713
+ }).select({ kind: "graph" });
90714
+ return withPage(ast, limit, input.cursor);
90715
+ }
90716
+ function definitionRef(input) {
90717
+ const path5 = Path.parse(input);
90718
+ const step = path5.ast.steps[0];
90719
+ if (path5.ast.anchor.kind !== "domain" || path5.ast.steps.length !== 1 || step?.kind !== "projection" || step.projection.kind !== "class" && step.projection.kind !== "interface") {
90720
+ throw new TypeError("--definition must be one canonical Class or Interface Path");
90721
+ }
90722
+ return Object.freeze({
90723
+ origin: path5.ast.anchor.origin,
90724
+ kind: step.projection.kind,
90725
+ name: step.projection.name
90726
+ });
90727
+ }
90728
+ function positiveInteger2(raw2, name, fallback) {
90729
+ if (raw2 === undefined)
90730
+ return fallback;
90731
+ if (!/^\d+$/.test(raw2))
90732
+ throw new TypeError(`${name} must be a positive integer`);
90733
+ const value2 = Number.parseInt(raw2, 10);
90734
+ if (!Number.isSafeInteger(value2) || value2 <= 0) {
90735
+ throw new TypeError(`${name} must be a positive integer`);
90736
+ }
90737
+ return value2;
90738
+ }
90739
+ function withPage(ast, size, cursor) {
90740
+ return Object.freeze({
90741
+ ast,
90742
+ page: Object.freeze({ size, ...cursor === undefined ? {} : { after: cursor } })
90743
+ });
90744
+ }
90745
+ var DEFAULT_LIMIT = 100;
90746
+ var init_query6 = __esm(() => {
90747
+ init_path5();
90748
+ init_query4();
90749
+ });
90750
+
90751
+ // src/graph/index.ts
90752
+ var init_graph6 = __esm(() => {
90753
+ init_mutation3();
90754
+ init_query6();
90755
+ });
90734
90756
 
90735
90757
  // src/commands/mutate.ts
90736
90758
  var exports_mutate = {};
@@ -90744,8 +90766,7 @@ async function mutateCommand(opts) {
90744
90766
  try {
90745
90767
  mutation = prepareMutation(await readDocument(opts));
90746
90768
  } catch (error52) {
90747
- log.error(error52 instanceof Error ? error52.message : "Invalid Mutation V3 document");
90748
- process.exit(1);
90769
+ failClosed(error52, opts);
90749
90770
  }
90750
90771
  if (opts.dry) {
90751
90772
  output(mutation, opts);
@@ -90847,91 +90868,6 @@ Examples:
90847
90868
  };
90848
90869
  });
90849
90870
 
90850
- // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/graph/class/index.js
90851
- var init_class3 = __esm(() => {
90852
- init_class();
90853
- });
90854
-
90855
- // src/commands/describe.ts
90856
- var exports_describe = {};
90857
- __export(exports_describe, {
90858
- describeCommand: () => describeCommand,
90859
- default: () => describe_default
90860
- });
90861
- async function describeCommand(target2, opts) {
90862
- let path5;
90863
- let meta3;
90864
- try {
90865
- ({ path: path5, meta: meta3 } = await expandSelfInPath(target2, opts));
90866
- } catch (error52) {
90867
- log.error(error52 instanceof Error ? error52.message : "Invalid target");
90868
- process.exit(1);
90869
- }
90870
- await runKernelCommand({
90871
- opts,
90872
- label: `Describe ${path5}`,
90873
- fn: ({ graph }) => withSelfHint(() => graph.getOrThrow(Path.parse(path5)), meta3),
90874
- format: (node4, format3, machine) => {
90875
- const shown = opts.schema === false ? withoutSchema(node4) : node4;
90876
- if (machine || format3.format !== undefined)
90877
- output(shown, format3);
90878
- else
90879
- printDescription(path5, shown);
90880
- }
90881
- });
90882
- }
90883
- function withoutSchema(node4) {
90884
- return {
90885
- ...node4,
90886
- props: Object.fromEntries(Object.entries(node4.props).filter(([key]) => unqualifyProperty(key) !== "schema"))
90887
- };
90888
- }
90889
- function printDescription(target2, node4) {
90890
- console.log(` ${source_default.bold.cyan(target2)}`);
90891
- console.log(` ${source_default.dim("id")} ${node4.id}`);
90892
- console.log(` ${source_default.dim("class")} ${ClassPath.name(node4.class)} ${source_default.dim(`(${node4.class})`)}`);
90893
- const properties = Object.entries(node4.props);
90894
- if (properties.length === 0)
90895
- return;
90896
- console.log(`
90897
- ${source_default.bold("Properties:")}`);
90898
- for (const [key, value2] of properties) {
90899
- const rendered = typeof value2 === "string" ? value2 : JSON.stringify(value2);
90900
- console.log(` ${source_default.cyan(unqualifyProperty(key))}: ${source_default.dim(rendered)}`);
90901
- }
90902
- }
90903
- var describe_default;
90904
- var init_describe = __esm(() => {
90905
- init_class3();
90906
- init_path5();
90907
- init_source();
90908
- init_connection2();
90909
- init_graph6();
90910
- init_log();
90911
- init_output();
90912
- describe_default = {
90913
- name: "describe",
90914
- description: "Describe the canonical facts of one node",
90915
- afterHelpText: `
90916
- Behavior:
90917
- Reads one canonical Node and presents its ID, Class, and properties.
90918
- It does not infer operations or children from path layout. --no-schema
90919
- omits schema-valued properties from Domain-sized results.
90920
-
90921
- Examples:
90922
- $ astrale describe /:kernel.astrale.ai:class.Domain
90923
- $ astrale describe @self --no-schema
90924
- `,
90925
- arguments: [{ name: "target", description: "Canonical Node Path or @id" }],
90926
- options: [
90927
- { flags: "--no-schema", description: "Omit properties whose qualified leaf is schema" }
90928
- ],
90929
- action: async (target2, opts) => {
90930
- await describeCommand(target2, opts);
90931
- }
90932
- };
90933
- });
90934
-
90935
90871
  // src/commands/query.ts
90936
90872
  var exports_query = {};
90937
90873
  __export(exports_query, {
@@ -90967,15 +90903,13 @@ async function queryCommand(sources2, opts) {
90967
90903
  };
90968
90904
  }
90969
90905
  } catch (error52) {
90970
- log.error(error52 instanceof Error ? error52.message : "Invalid query");
90971
- process.exit(1);
90906
+ failClosed(error52, opts);
90972
90907
  }
90973
90908
  let prepared;
90974
90909
  try {
90975
90910
  prepared = prepareQuery(input);
90976
90911
  } catch (error52) {
90977
- log.error(error52 instanceof Error ? error52.message : "Invalid Query V6 document");
90978
- process.exit(1);
90912
+ failClosed(error52, opts);
90979
90913
  }
90980
90914
  await runKernelCommand({
90981
90915
  opts,
@@ -91062,6 +90996,208 @@ Examples:
91062
90996
  };
91063
90997
  });
91064
90998
 
90999
+ // src/commands/call-describe.ts
91000
+ function describeCallableFromSchema(path5, schema2) {
91001
+ if (path5.ast.anchor.kind !== "domain")
91002
+ return;
91003
+ const origin = path5.ast.anchor.origin;
91004
+ const last = path5.ast.steps.at(-1);
91005
+ const document = asRecord2(schema2);
91006
+ if (document === undefined || last === undefined)
91007
+ return;
91008
+ if (last.kind === "method") {
91009
+ const owner = path5.ast.steps.at(-2);
91010
+ if (owner?.kind === "projection" && (owner.projection.kind === "class" || owner.projection.kind === "interface")) {
91011
+ const bag = asRecord2(owner.projection.kind === "class" ? document.classes : document.interfaces);
91012
+ const definition3 = asRecord2(bag?.[owner.projection.name]);
91013
+ const method = asRecord2(asRecord2(definition3?.methods)?.[last.name]);
91014
+ if (method !== undefined) {
91015
+ return Object.freeze({
91016
+ path: path5.raw,
91017
+ origin,
91018
+ class: owner.projection.name,
91019
+ method: last.name,
91020
+ dispatch: last.dispatch,
91021
+ ...callableFields(method)
91022
+ });
91023
+ }
91024
+ }
91025
+ const matches3 = findNamedMethods(document, origin, path5.raw, last.name, last.dispatch);
91026
+ if (matches3.length === 1)
91027
+ return matches3[0];
91028
+ if (matches3.length > 1) {
91029
+ return Object.freeze({
91030
+ path: path5.raw,
91031
+ origin,
91032
+ method: last.name,
91033
+ dispatch: last.dispatch,
91034
+ candidates: Object.freeze(matches3)
91035
+ });
91036
+ }
91037
+ return;
91038
+ }
91039
+ if (last.kind === "projection" && last.projection.kind === "function") {
91040
+ const fn2 = asRecord2(asRecord2(document.functions)?.[last.projection.name]);
91041
+ if (fn2 === undefined)
91042
+ return;
91043
+ return Object.freeze({
91044
+ path: path5.raw,
91045
+ origin,
91046
+ function: last.projection.name,
91047
+ ...callableFields(fn2)
91048
+ });
91049
+ }
91050
+ return;
91051
+ }
91052
+ function missingCallableDescription(path5) {
91053
+ return new AstraleError("CALL_DESCRIBE_UNAVAILABLE", `No callable schema is installed for ${path5}.`, "Use a Domain-rooted Path such as /:host.astrale.ai:class.Manager:createInstance. Method Paths are not Function nodes.");
91054
+ }
91055
+ function findNamedMethods(schema2, origin, path5, method, dispatch) {
91056
+ const matches3 = [];
91057
+ for (const bag of [schema2.classes, schema2.interfaces]) {
91058
+ const definitions2 = asRecord2(bag);
91059
+ if (definitions2 === undefined)
91060
+ continue;
91061
+ for (const [className, definition3] of Object.entries(definitions2)) {
91062
+ const methodDef = asRecord2(asRecord2(asRecord2(definition3)?.methods)?.[method]);
91063
+ if (methodDef === undefined)
91064
+ continue;
91065
+ matches3.push(Object.freeze({
91066
+ path: path5,
91067
+ origin,
91068
+ class: className,
91069
+ method,
91070
+ dispatch,
91071
+ ...callableFields(methodDef)
91072
+ }));
91073
+ }
91074
+ }
91075
+ return matches3;
91076
+ }
91077
+ function callableFields(value2) {
91078
+ return {
91079
+ ...typeof value2.description === "string" ? { description: value2.description } : {},
91080
+ ...value2.auth === undefined ? {} : { auth: value2.auth },
91081
+ ...value2.input === undefined ? {} : { input: value2.input },
91082
+ ...value2.output === undefined ? {} : { output: value2.output }
91083
+ };
91084
+ }
91085
+ function asRecord2(input) {
91086
+ return input !== null && typeof input === "object" && !Array.isArray(input) ? input : undefined;
91087
+ }
91088
+ var init_call_describe = __esm(() => {
91089
+ init_errors2();
91090
+ });
91091
+
91092
+ // src/commands/introspect.ts
91093
+ var exports_introspect = {};
91094
+ __export(exports_introspect, {
91095
+ parseIntrospectTarget: () => parseIntrospectTarget,
91096
+ introspectCommand: () => introspectCommand,
91097
+ default: () => introspect_default
91098
+ });
91099
+ async function introspectCommand(target2, opts) {
91100
+ let origin;
91101
+ let path5;
91102
+ try {
91103
+ ({ origin, path: path5 } = parseIntrospectTarget(target2));
91104
+ } catch (error52) {
91105
+ failClosed(error52, opts);
91106
+ }
91107
+ const wantsCallable = isCallablePath(path5);
91108
+ await runKernelCommand({
91109
+ opts,
91110
+ label: `Introspect ${origin}`,
91111
+ fn: async ({ session }) => {
91112
+ const includeBundle = wantsCallable || opts.bundle === true;
91113
+ const result = await session.schema.introspect({
91114
+ from: { kind: "installation", origin },
91115
+ select: {
91116
+ state: true,
91117
+ target: true,
91118
+ source: true,
91119
+ readiness: true,
91120
+ capabilities: true,
91121
+ ...includeBundle ? { bundle: true } : {}
91122
+ }
91123
+ });
91124
+ if (result === null) {
91125
+ throw new AstraleError("DOMAIN_NOT_INSTALLED", `Domain ${origin} is not installed on this Kernel.`);
91126
+ }
91127
+ if (wantsCallable) {
91128
+ const described = describeCallableFromSchema(path5, bundleRoot(result.bundle));
91129
+ if (described === undefined)
91130
+ throw missingCallableDescription(path5.raw);
91131
+ return described;
91132
+ }
91133
+ return result;
91134
+ },
91135
+ format: (value2, format3) => output(value2, format3)
91136
+ });
91137
+ }
91138
+ function parseIntrospectTarget(target2) {
91139
+ if (target2.startsWith("@")) {
91140
+ throw new AstraleError("NOT_A_DOMAIN", "introspect requires a Domain origin or Path, not an @id.", "Example: astrale introspect host.astrale.ai or /:host.astrale.ai:class.Manager:createInstance");
91141
+ }
91142
+ const raw2 = target2.startsWith("/") ? target2 : `/:${target2}`;
91143
+ let path5;
91144
+ try {
91145
+ path5 = Path.parse(raw2);
91146
+ } catch (error52) {
91147
+ throw new AstraleError("PATH_INVALID", error52 instanceof Error ? error52.message : "Invalid introspect target");
91148
+ }
91149
+ if (path5.ast.anchor.kind !== "domain") {
91150
+ throw new AstraleError("NOT_A_DOMAIN", "introspect requires a Domain-rooted Path or origin.");
91151
+ }
91152
+ return { origin: path5.ast.anchor.origin, path: path5 };
91153
+ }
91154
+ function isCallablePath(path5) {
91155
+ const last = path5.ast.steps.at(-1);
91156
+ if (last === undefined)
91157
+ return false;
91158
+ if (last.kind === "method")
91159
+ return true;
91160
+ return last.kind === "projection" && last.projection.kind === "function";
91161
+ }
91162
+ function bundleRoot(bundle) {
91163
+ if (bundle !== null && typeof bundle === "object" && "root" in bundle) {
91164
+ return bundle.root;
91165
+ }
91166
+ return bundle;
91167
+ }
91168
+ var introspect_default;
91169
+ var init_introspect3 = __esm(() => {
91170
+ init_path5();
91171
+ init_connection2();
91172
+ init_errors2();
91173
+ init_log();
91174
+ init_output();
91175
+ init_call_describe();
91176
+ introspect_default = {
91177
+ name: "introspect",
91178
+ description: "Read installed Domain schema from the Kernel Schema syscall",
91179
+ afterHelpText: `
91180
+ Behavior:
91181
+ Calls the public Kernel introspect syscall for one installed Domain.
91182
+ A bare origin (host.astrale.ai or /:host.astrale.ai) prints installation
91183
+ state, target, source, readiness, and capabilities. --bundle includes the
91184
+ schema bundle. A method or Function Path projects that callable's
91185
+ input/output from the installed bundle.
91186
+
91187
+ Examples:
91188
+ $ astrale introspect host.astrale.ai
91189
+ $ astrale introspect /:host.astrale.ai --bundle
91190
+ $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
91191
+ $ astrale introspect /:kernel.astrale.ai:function.journal
91192
+ `,
91193
+ arguments: [{ name: "target", description: "Domain origin or canonical Path" }],
91194
+ options: [{ flags: "--bundle", description: "Include the installed schema bundle" }],
91195
+ action: async (target2, opts) => {
91196
+ await introspectCommand(target2, opts);
91197
+ }
91198
+ };
91199
+ });
91200
+
91065
91201
  // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/schema/kernel/index.js
91066
91202
  var init_kernel2 = __esm(() => {
91067
91203
  init_schema7();
@@ -91077,6 +91213,11 @@ __export(exports_logs, {
91077
91213
  function buildJournalInput(opts) {
91078
91214
  const exact10 = nonEmpty4(opts.topic);
91079
91215
  const prefix = nonEmpty4(opts.topicPrefix);
91216
+ const since = timestampFlag("--since", opts.since);
91217
+ const until = timestampFlag("--until", opts.until);
91218
+ if (since !== undefined && until !== undefined && Date.parse(since) > Date.parse(until)) {
91219
+ throw new TypeError("--since must be earlier than or equal to --until");
91220
+ }
91080
91221
  return {
91081
91222
  ...exact10 === undefined && prefix === undefined ? {} : {
91082
91223
  topics: {
@@ -91085,12 +91226,28 @@ function buildJournalInput(opts) {
91085
91226
  }
91086
91227
  },
91087
91228
  ...nonEmpty4(opts.principal) === undefined ? {} : { principal: opts.principal },
91088
- ...nonEmpty4(opts.since) === undefined ? {} : { since: opts.since },
91089
- ...nonEmpty4(opts.until) === undefined ? {} : { until: opts.until },
91090
- ...nonEmpty4(opts.cursor) === undefined ? {} : { cursor: opts.cursor },
91229
+ ...since === undefined ? {} : { since },
91230
+ ...until === undefined ? {} : { until },
91231
+ ...opts.cursor === undefined ? {} : { cursor: cursorFlag(opts.cursor) },
91091
91232
  limit: opts.limit === undefined ? DEFAULT_LIMIT2 : positiveInteger3("--limit", opts.limit)
91092
91233
  };
91093
91234
  }
91235
+ function timestampFlag(name, raw2) {
91236
+ const value2 = nonEmpty4(raw2);
91237
+ if (value2 === undefined)
91238
+ return;
91239
+ if (!ISO_TIMESTAMP.test(value2) || Number.isNaN(Date.parse(value2))) {
91240
+ throw new TypeError(`${name} must be an ISO-8601 timestamp (e.g. 2026-08-19T16:51:10.049Z)`);
91241
+ }
91242
+ return value2;
91243
+ }
91244
+ function cursorFlag(raw2) {
91245
+ const value2 = raw2.trim();
91246
+ if (!CURSOR_TOKEN.test(value2)) {
91247
+ throw new TypeError("--cursor must be an opaque journal resume token (at least 8 characters)");
91248
+ }
91249
+ return value2;
91250
+ }
91094
91251
  function acceptJournalPage(input) {
91095
91252
  if (!isRecord8(input) || !Array.isArray(input.records)) {
91096
91253
  throw new TypeError("Kernel journal response must contain a records array");
@@ -91199,6 +91356,14 @@ function positiveInteger3(flag, raw2) {
91199
91356
  }
91200
91357
  return value2;
91201
91358
  }
91359
+ async function prepareLogsOpts(opts) {
91360
+ buildJournalInput(opts);
91361
+ const principal = nonEmpty4(opts.principal);
91362
+ if (principal !== "@self")
91363
+ return opts;
91364
+ const { path: path5 } = await expandSelfInPath("@self", opts);
91365
+ return { ...opts, principal: path5.startsWith("@") ? path5.slice(1) : path5 };
91366
+ }
91202
91367
  function nonEmpty4(input) {
91203
91368
  const value2 = input?.trim();
91204
91369
  return value2 ? value2 : undefined;
@@ -91206,14 +91371,17 @@ function nonEmpty4(input) {
91206
91371
  function isRecord8(input) {
91207
91372
  return input !== null && typeof input === "object" && !Array.isArray(input);
91208
91373
  }
91209
- var JOURNAL_PATH, DEFAULT_LIMIT2 = 200, FOLLOW_INTERVAL_MS = 2000, logs_default;
91374
+ var JOURNAL_PATH, DEFAULT_LIMIT2 = 200, FOLLOW_INTERVAL_MS = 2000, ISO_TIMESTAMP, CURSOR_TOKEN, logs_default;
91210
91375
  var init_logs = __esm(() => {
91211
91376
  init_path5();
91212
91377
  init_kernel2();
91213
91378
  init_source();
91214
91379
  init_connection2();
91380
+ init_log();
91215
91381
  init_output();
91216
91382
  JOURNAL_PATH = Path.project(exports_syscalls.journal.ref).raw;
91383
+ ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
91384
+ CURSOR_TOKEN = /^[A-Za-z0-9._:+=/-]{8,}$/;
91217
91385
  logs_default = {
91218
91386
  name: "logs",
91219
91387
  description: "Read or follow the authorized Kernel journal",
@@ -91243,10 +91411,15 @@ Examples:
91243
91411
  { flags: "--follow", description: "Poll using returned cursors until interrupted" }
91244
91412
  ],
91245
91413
  action: async (opts) => {
91246
- if (opts.follow)
91247
- await follow(opts);
91248
- else
91249
- await runOnce(opts);
91414
+ try {
91415
+ const prepared = await prepareLogsOpts(opts);
91416
+ if (prepared.follow)
91417
+ await follow(prepared);
91418
+ else
91419
+ await runOnce(prepared);
91420
+ } catch (error52) {
91421
+ failClosed(error52, opts);
91422
+ }
91250
91423
  }
91251
91424
  };
91252
91425
  });
@@ -92128,10 +92301,11 @@ What it does:
92128
92301
  an audience-bound credential for shell mounts, and the kernel endpoint.
92129
92302
 
92130
92303
  Examples:
92131
- $ astrale view /crm/customers/ada # views on a node
92132
- $ astrale view /:crm.acme.dev:view.dashboard # explicit ViewPath
92304
+ $ astrale view @customer
92305
+ $ astrale view /:crm.example.dev:view.dashboard
92133
92306
  $ astrale view /:agents.astrale.ai:view.agent --target @f00d1234 --as alice
92134
- $ astrale view /crm/customers/ada --snapshot # open + show it
92307
+ $ astrale view @customer --snapshot
92308
+ $ astrale view --list
92135
92309
  $ astrale view --sessions ; astrale view --close --all
92136
92310
  `,
92137
92311
  action: async (spec, opts) => {
@@ -92139,6 +92313,8 @@ Examples:
92139
92313
  return closeCommand(opts);
92140
92314
  if (opts.sessions)
92141
92315
  return sessionsCommand(opts);
92316
+ if (opts.list && !spec)
92317
+ return sessionsCommand(opts);
92142
92318
  rejectUnrepresentableOverrides(opts);
92143
92319
  if (!spec)
92144
92320
  return fatal(new Error("Nothing to open — pass a ViewPath or target node."));
@@ -94044,6 +94220,7 @@ var create_default2;
94044
94220
  var init_create3 = __esm(() => {
94045
94221
  init_identity8();
94046
94222
  init_log();
94223
+ init_output();
94047
94224
  create_default2 = {
94048
94225
  name: "create",
94049
94226
  description: "Create a new identity",
@@ -94051,20 +94228,30 @@ var init_create3 = __esm(() => {
94051
94228
  options: [
94052
94229
  { flags: "--subject <sub>", description: "Custom subject (defaults to name)" },
94053
94230
  { flags: "--local", description: "Local-only identity (default)" },
94054
- { flags: "--remote", description: "Remote (cloud-synced) identity — requires cloud login" }
94231
+ { flags: "--remote", description: "Remote (cloud-synced) identity — requires cloud login" },
94232
+ ...RAW_OUTPUT_OPTIONS
94055
94233
  ],
94056
94234
  action: async (name, opts) => {
94057
94235
  try {
94058
94236
  const mode = opts.remote ? "remote" : "local";
94059
94237
  const identity3 = await createIdentity(name, { subject: opts.subject, mode });
94238
+ if (isMachine(opts)) {
94239
+ output({ name, ...identity3 }, opts);
94240
+ return;
94241
+ }
94060
94242
  log.success(`Created identity "${name}" (subject: ${identity3.subject}, mode: ${identity3.mode})`);
94061
94243
  } catch (e) {
94062
- fatal(e);
94244
+ fatal(e, opts);
94063
94245
  }
94064
94246
  }
94065
94247
  };
94066
94248
  });
94067
94249
 
94250
+ // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/graph/class/index.js
94251
+ var init_class3 = __esm(() => {
94252
+ init_class();
94253
+ });
94254
+
94068
94255
  // node_modules/.pnpm/@astrale-os+sdk@file+vendor+astrale-os-sdk-0.5.0-beta.1.tgz_@astrale-os+ox@0.1.2_oxfmt@_72b33f8043e5d121b8114f4a315f9796/node_modules/@astrale-os/sdk/dist/graph/model/index.js
94069
94256
  var init_model8 = __esm(() => {
94070
94257
  init_graph2();
@@ -94287,16 +94474,22 @@ var use_default4;
94287
94474
  var init_use4 = __esm(() => {
94288
94475
  init_identity8();
94289
94476
  init_log();
94477
+ init_output();
94290
94478
  use_default4 = {
94291
94479
  name: "use",
94292
94480
  description: "Set the active CLI identity",
94293
94481
  arguments: [{ name: "name", description: "Identity name", required: true }],
94294
- action: async (name) => {
94482
+ options: [...RAW_OUTPUT_OPTIONS],
94483
+ action: async (name, opts) => {
94295
94484
  try {
94296
94485
  await setDefault(name);
94486
+ if (isMachine(opts)) {
94487
+ output({ default: name }, opts);
94488
+ return;
94489
+ }
94297
94490
  log.success(`Active identity set to "${name}"`);
94298
94491
  } catch (e) {
94299
- fatal(e);
94492
+ fatal(e, opts);
94300
94493
  }
94301
94494
  }
94302
94495
  };
@@ -94311,16 +94504,22 @@ var delete_default2;
94311
94504
  var init_delete2 = __esm(() => {
94312
94505
  init_identity8();
94313
94506
  init_log();
94507
+ init_output();
94314
94508
  delete_default2 = {
94315
94509
  name: "delete",
94316
94510
  description: "Delete an identity",
94317
94511
  arguments: [{ name: "name", description: "Identity name", required: true }],
94318
- action: async (name) => {
94512
+ options: [...RAW_OUTPUT_OPTIONS],
94513
+ action: async (name, opts) => {
94319
94514
  try {
94320
94515
  await deleteIdentity(name);
94516
+ if (isMachine(opts)) {
94517
+ output({ deleted: name }, opts);
94518
+ return;
94519
+ }
94321
94520
  log.success(`Deleted identity "${name}"`);
94322
94521
  } catch (e) {
94323
- fatal(e);
94522
+ fatal(e, opts);
94324
94523
  }
94325
94524
  }
94326
94525
  };
@@ -94335,6 +94534,7 @@ var sync_default;
94335
94534
  var init_sync = __esm(() => {
94336
94535
  init_identity8();
94337
94536
  init_log();
94537
+ init_output();
94338
94538
  sync_default = {
94339
94539
  name: "sync",
94340
94540
  description: "Migrate an identity local → remote (astrale cloud)",
@@ -94343,7 +94543,8 @@ var init_sync = __esm(() => {
94343
94543
  {
94344
94544
  flags: "--force",
94345
94545
  description: "Tag as remote in the local registry even without cloud login"
94346
- }
94546
+ },
94547
+ ...RAW_OUTPUT_OPTIONS
94347
94548
  ],
94348
94549
  action: async (name, opts) => {
94349
94550
  try {
@@ -94352,10 +94553,14 @@ var init_sync = __esm(() => {
94352
94553
  fatalNotImplemented("identity sync (remote)", "Cloud adapter is stubbed in v1. Use --force to pre-tag the identity locally.");
94353
94554
  }
94354
94555
  await setIdentityMode(name, "remote");
94556
+ if (isMachine(opts)) {
94557
+ output({ name, mode: "remote", subject: identity3.subject }, opts);
94558
+ return;
94559
+ }
94355
94560
  log.warn(`Tagged "${name}" as remote locally (cloud sync stubbed in v1)`);
94356
94561
  log.dim(` subject=${identity3.subject}`);
94357
94562
  } catch (e) {
94358
- fatal(e);
94563
+ fatal(e, opts);
94359
94564
  }
94360
94565
  }
94361
94566
  };
@@ -94370,21 +94575,31 @@ var unsync_default;
94370
94575
  var init_unsync = __esm(() => {
94371
94576
  init_identity8();
94372
94577
  init_log();
94578
+ init_output();
94373
94579
  unsync_default = {
94374
94580
  name: "unsync",
94375
94581
  description: "Migrate an identity remote → local",
94376
94582
  arguments: [{ name: "name", description: "Identity name", required: true }],
94377
- action: async (name) => {
94583
+ options: [...RAW_OUTPUT_OPTIONS],
94584
+ action: async (name, opts) => {
94378
94585
  try {
94379
94586
  const identity3 = await getIdentity(name);
94380
94587
  if (identity3.mode !== "remote") {
94588
+ if (isMachine(opts)) {
94589
+ output({ name, mode: identity3.mode ?? "local", unchanged: true }, opts);
94590
+ return;
94591
+ }
94381
94592
  log.warn(`Identity "${name}" is already ${identity3.mode ?? "local"}`);
94382
94593
  return;
94383
94594
  }
94384
94595
  await setIdentityMode(name, "local");
94596
+ if (isMachine(opts)) {
94597
+ output({ name, mode: "local" }, opts);
94598
+ return;
94599
+ }
94385
94600
  log.success(`Identity "${name}" → local`);
94386
94601
  } catch (e) {
94387
- fatal(e);
94602
+ fatal(e, opts);
94388
94603
  }
94389
94604
  }
94390
94605
  };
@@ -94399,6 +94614,7 @@ var export_default;
94399
94614
  var init_export2 = __esm(() => {
94400
94615
  init_identity8();
94401
94616
  init_log();
94617
+ init_output();
94402
94618
  init_prompt();
94403
94619
  export_default = {
94404
94620
  name: "export",
@@ -94408,19 +94624,24 @@ var init_export2 = __esm(() => {
94408
94624
  { name: "path", description: "Output file path", required: true }
94409
94625
  ],
94410
94626
  options: [
94411
- { flags: "--encrypt", description: "Encrypt the envelope with a passphrase (JOSE JWE)" }
94627
+ { flags: "--encrypt", description: "Encrypt the envelope with a passphrase (JOSE JWE)" },
94628
+ ...RAW_OUTPUT_OPTIONS
94412
94629
  ],
94413
94630
  action: async (name, path5, opts) => {
94414
94631
  try {
94415
94632
  const envelope2 = await exportIdentity(name);
94416
94633
  const passphrase = opts.encrypt ? await readPassphrase("Passphrase (min 8 chars): ", { minLength: 8 }) : undefined;
94417
94634
  await writeIdentityExport(path5, await encodeIdentityExport(envelope2, passphrase));
94635
+ if (isMachine(opts)) {
94636
+ output({ name, path: path5, encrypted: Boolean(opts.encrypt) }, opts);
94637
+ return;
94638
+ }
94418
94639
  log.success(`Exported identity "${name}" → ${path5}${opts.encrypt ? " (encrypted)" : ""}`);
94419
94640
  if (!opts.encrypt) {
94420
94641
  log.warn(" Plaintext private JWK — keep this file secure. Use --encrypt for passphrase wrapping.");
94421
94642
  }
94422
94643
  } catch (e) {
94423
- fatal(e);
94644
+ fatal(e, opts);
94424
94645
  }
94425
94646
  }
94426
94647
  };
@@ -94436,6 +94657,7 @@ var import_default;
94436
94657
  var init_import2 = __esm(() => {
94437
94658
  init_identity8();
94438
94659
  init_log();
94660
+ init_output();
94439
94661
  init_prompt();
94440
94662
  import_default = {
94441
94663
  name: "import",
@@ -94453,7 +94675,8 @@ var init_import2 = __esm(() => {
94453
94675
  {
94454
94676
  flags: "--replace",
94455
94677
  description: "Replace an existing key-backed identity with the imported keypair"
94456
- }
94678
+ },
94679
+ ...RAW_OUTPUT_OPTIONS
94457
94680
  ],
94458
94681
  action: async (path5, opts) => {
94459
94682
  try {
@@ -94466,9 +94689,13 @@ var init_import2 = __esm(() => {
94466
94689
  issuer: opts.issuer,
94467
94690
  replace: opts.replace
94468
94691
  });
94692
+ if (isMachine(opts)) {
94693
+ output({ name, ...identity3 }, opts);
94694
+ return;
94695
+ }
94469
94696
  log.success(`Imported identity "${name}" (subject=${identity3.subject}, kid=${identity3.kid ?? "?"})`);
94470
94697
  } catch (e) {
94471
- fatal(e);
94698
+ fatal(e, opts);
94472
94699
  }
94473
94700
  }
94474
94701
  };
@@ -94588,10 +94815,10 @@ async function resolveIdentityName(opts) {
94588
94815
  if (opts.name) {
94589
94816
  const identity4 = await getIdentity(opts.name);
94590
94817
  if ((identity4.source ?? "key") !== "idp") {
94591
- throw new Error(`Identity "${opts.name}" is not IdP-backed`);
94818
+ throw new AstraleError("AUTH_ERROR", `Identity "${opts.name}" is not IdP-backed`);
94592
94819
  }
94593
94820
  if (opts.idp && identity4.idp !== opts.idp) {
94594
- throw new Error(`Identity "${opts.name}" is backed by IdP "${identity4.idp ?? "?"}", not "${opts.idp}"`);
94821
+ throw new AstraleError("AUTH_ERROR", `Identity "${opts.name}" is backed by IdP "${identity4.idp ?? "?"}", not "${opts.idp}"`);
94595
94822
  }
94596
94823
  return opts.name;
94597
94824
  }
@@ -94599,17 +94826,17 @@ async function resolveIdentityName(opts) {
94599
94826
  const store = await readIdentities();
94600
94827
  const matches3 = Object.entries(store.identities).filter(([, identity4]) => identity4.source === "idp" && identity4.idp === opts.idp).map(([name]) => name);
94601
94828
  if (matches3.length === 0) {
94602
- throw new Error(`No IdP-backed identities found for IdP "${opts.idp}". Run: astrale auth login --idp ${opts.idp}`);
94829
+ throw new AstraleError("AUTH_ERROR", `No IdP-backed identities found for IdP "${opts.idp}". Run: astrale auth login --idp ${opts.idp}`);
94603
94830
  }
94604
94831
  if (matches3.includes(store.default))
94605
94832
  return store.default;
94606
94833
  if (matches3.length === 1)
94607
94834
  return matches3[0];
94608
- throw new Error(`Multiple IdP-backed identities found for IdP "${opts.idp}": ${matches3.join(", ")}. Pass --name.`);
94835
+ throw new AstraleError("AUTH_ERROR", `Multiple IdP-backed identities found for IdP "${opts.idp}": ${matches3.join(", ")}. Pass --name.`);
94609
94836
  }
94610
94837
  const identity3 = await getDefault();
94611
94838
  if ((identity3.source ?? "key") !== "idp") {
94612
- throw new Error("Default identity is not IdP-backed. Pass --name or --idp.");
94839
+ throw new AstraleError("AUTH_ERROR", "Default identity is not IdP-backed. Pass --name or --idp.");
94613
94840
  }
94614
94841
  return identity3.name;
94615
94842
  }
@@ -94622,6 +94849,7 @@ function tokenFromSession(session, type) {
94622
94849
  }
94623
94850
  var token_default2;
94624
94851
  var init_token2 = __esm(() => {
94852
+ init_errors2();
94625
94853
  init_identity8();
94626
94854
  init_idp();
94627
94855
  init_idp_session();
@@ -94661,7 +94889,12 @@ Examples:
94661
94889
  $ astrale auth token --name alice --type id --json
94662
94890
  `,
94663
94891
  action: async (opts) => {
94664
- const result = await resolveAuthToken(opts);
94892
+ let result;
94893
+ try {
94894
+ result = await resolveAuthToken(opts);
94895
+ } catch (error52) {
94896
+ fatal(error52, opts);
94897
+ }
94665
94898
  if (opts.raw) {
94666
94899
  process.stdout.write(result.token + `
94667
94900
  `);
@@ -95745,6 +95978,7 @@ var {
95745
95978
 
95746
95979
  // src/lib/command-dx.ts
95747
95980
  init_source();
95981
+ init_output();
95748
95982
  function collectCommandCatalog(program2) {
95749
95983
  const out = [];
95750
95984
  function walk(command, path) {
@@ -95764,39 +95998,40 @@ function renderCommanderError(program2, error, argv = process.argv.slice(2)) {
95764
95998
  const catalog = collectCommandCatalog(program2);
95765
95999
  const matched = matchRegisteredPrefix(program2, tokens);
95766
96000
  if (matched.path.length === 0 && tokens.length > 0) {
95767
- return renderUnknownCommand(tokens, catalog);
96001
+ return maybeMachine(renderUnknownCommand(tokens, catalog));
95768
96002
  }
95769
96003
  if (error.code === "commander.missingArgument") {
95770
96004
  const usage = usageFor(matched.path, matched.command);
95771
96005
  const argName = error.message.match(/'([^']+)'/)?.[1];
95772
- return [
96006
+ return maybeMachine([
95773
96007
  `Missing required argument${argName ? ` ${source_default.bold(`<${argName}>`)}` : ""} for ${source_default.bold(`astrale ${matched.path.join(" ")}`)}`,
95774
96008
  "",
95775
96009
  "Usage:",
95776
96010
  ` astrale ${usage}`
95777
96011
  ].join(`
95778
- `);
96012
+ `));
95779
96013
  }
95780
96014
  if (error.code === "commander.excessArguments") {
95781
96015
  const usage = usageFor(matched.path, matched.command);
95782
96016
  const extra = tokens.slice(matched.path.length).join(" ");
95783
- return [
96017
+ return maybeMachine([
95784
96018
  `Unexpected argument${extra.includes(" ") ? "s" : ""} for ${source_default.bold(`astrale ${matched.path.join(" ")}`)}${extra ? `: ${extra}` : ""}`,
95785
96019
  "",
95786
96020
  "Usage:",
95787
96021
  ` astrale ${usage}`
95788
96022
  ].join(`
95789
- `);
96023
+ `));
95790
96024
  }
95791
96025
  const suggestions = nearestCommands(tokens.join(" "), catalog);
95792
- return [
96026
+ return maybeMachine([
95793
96027
  error.message,
95794
96028
  ...suggestions.length > 0 ? ["", "Did you mean:", ...suggestions.map((s) => ` astrale ${s}`)] : []
95795
96029
  ].join(`
95796
- `);
96030
+ `));
95797
96031
  }
95798
96032
  var RETIRED_COMMANDS = {
95799
- ls: "astrale query <source> --edge <class>"
96033
+ ls: "astrale query <source> --edge <class>",
96034
+ describe: "astrale get <target>"
95800
96035
  };
95801
96036
  function renderUnknownCommand(tokens, catalog) {
95802
96037
  const command = tokens.join(" ");
@@ -95843,6 +96078,15 @@ function usageFor(path, command) {
95843
96078
  const suffix = command.usage().replace(/\[options\]\s*/g, "").replace(/\s+/g, " ").trim();
95844
96079
  return [path.join(" "), suffix].filter(Boolean).join(" ");
95845
96080
  }
96081
+ var ANSI_RE = new RegExp(String.fromCharCode(27) + "\\[[0-9;]*m", "g");
96082
+ function maybeMachine(text) {
96083
+ if (!isMachine())
96084
+ return text;
96085
+ const plain = text.replace(ANSI_RE, "");
96086
+ const first = plain.split(`
96087
+ `).find((line) => line.trim().length > 0) ?? plain;
96088
+ return JSON.stringify({ error: "USAGE_ERROR", message: first, detail: plain });
96089
+ }
95846
96090
  function stripOptions(argv) {
95847
96091
  const out = [];
95848
96092
  for (const token of argv) {
@@ -95879,6 +96123,12 @@ function levenshtein(a, b) {
95879
96123
  return prev[b.length] ?? 0;
95880
96124
  }
95881
96125
 
96126
+ // src/lib/invocation.ts
96127
+ var argvMachine2 = false;
96128
+ function configureInvocation(argv) {
96129
+ argvMachine2 = argv.some((token) => token === "--json" || token === "--raw" || token === "--ci");
96130
+ }
96131
+
95882
96132
  // node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
95883
96133
  var import__2 = __toESM(require_commander(), 1);
95884
96134
  var {
@@ -95914,7 +96164,7 @@ var KERNEL_PASSTHROUGH_OPTIONS = Object.freeze([
95914
96164
  { flags: "--creds <token>", description: "Use a pre-signed credential (e.g. delegation token)" },
95915
96165
  {
95916
96166
  flags: "--anonymous",
95917
- description: "Send no credential (cannot be combined with --as or --creds)"
96167
+ description: "Send no credential (cannot be combined with --as or --creds; --as and --creds are mutually exclusive)"
95918
96168
  },
95919
96169
  { flags: "--debug", description: "Print full error diagnostics on failure" }
95920
96170
  ]);
@@ -95985,7 +96235,7 @@ function registerGroup(parent, group) {
95985
96235
  // src/program/build.ts
95986
96236
  async function buildProgram() {
95987
96237
  const program3 = new Command2;
95988
- program3.name("astrale").description("Astrale CLI — connect to existing Astrale kernels").version(package_default.version).showSuggestionAfterError(true).addOption(new Option2("--ci", "Machine mode: no prompts, structured errors on stderr")).addOption(new Option2("--no-prompt", "Disable interactive prompts")).addOption(new Option2("--offline-ok", "Tolerate offline state for commands that can operate locally")).addOption(new Option2("--log-level <level>", "Log level").choices(["debug", "info", "warn", "error"])).addOption(new Option2("--log-format <format>", "Log output format").choices(["text", "json"])).action(async () => {
96238
+ program3.name("astrale").description("Astrale CLI — connect to existing Astrale kernels").version(package_default.version).showSuggestionAfterError(true).addOption(new Option2("--ci", "Machine mode: no prompts, structured errors on stderr")).addOption(new Option2("--no-prompt", "Disable interactive prompts")).action(async () => {
95989
96239
  if (process.stdin.isTTY && process.stdout.isTTY) {
95990
96240
  const { shouldAutostartSetup: shouldAutostartSetup2 } = await Promise.resolve().then(() => (init_engine(), exports_engine));
95991
96241
  if (await shouldAutostartSetup2()) {
@@ -96009,8 +96259,8 @@ async function buildProgram() {
96009
96259
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_token(), exports_token))).default));
96010
96260
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_get(), exports_get))).default));
96011
96261
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_mutate4(), exports_mutate))).default));
96012
- registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_describe(), exports_describe))).default));
96013
96262
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_query7(), exports_query))).default));
96263
+ registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_introspect3(), exports_introspect))).default));
96014
96264
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_logs(), exports_logs))).default));
96015
96265
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_view6(), exports_view2))).default));
96016
96266
  registerCommand(program3, (await Promise.resolve().then(() => (init_status(), exports_status))).default);
@@ -96096,7 +96346,7 @@ async function buildProgram() {
96096
96346
  program3.addHelpText("after", `
96097
96347
  Command groups:
96098
96348
  Getting started setup (sign in, pick an instance, equip your workspace)
96099
- Kernel get, mutate, call, query, describe, token
96349
+ Kernel get, mutate, call, query, introspect, logs, view, token
96100
96350
  Management admin, instance, domain, identity, auth, idp, update
96101
96351
  Agent browser (drive the GUI via agent-browser)
96102
96352
  Studio studio (launch the local Domain Studio GUI for a workspace)
@@ -96118,6 +96368,7 @@ Examples:
96118
96368
  $ astrale instance status staging
96119
96369
  $ astrale token --audience shell.astrale.ai --ttl 3600
96120
96370
  $ astrale query /:notes.example.dev:class.Note --limit 50
96371
+ $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
96121
96372
  $ astrale query --file query.v6.json --cursor "$CURSOR"
96122
96373
  `);
96123
96374
  return program3;
@@ -96359,6 +96610,7 @@ var errorName;
96359
96610
  if (finalize2)
96360
96611
  process.on("exit", (code) => finalize2(code ?? 0, errorName));
96361
96612
  maybeTriggerAnalysis(process.argv);
96613
+ configureInvocation(process.argv);
96362
96614
  var program3 = await buildProgram();
96363
96615
  overrideExits(program3);
96364
96616
  program3.configureOutput({ writeErr: () => {