@astrale-os/cli 0.8.1-alpha.5 → 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 (55) hide show
  1. package/README.md +1 -1
  2. package/dist/astrale.js +820 -488
  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 +35 -20
  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 +40 -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 +3 -1
  52. package/src/program/build.ts +3 -8
  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
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.5",
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);
@@ -90882,15 +90903,13 @@ async function queryCommand(sources2, opts) {
90882
90903
  };
90883
90904
  }
90884
90905
  } catch (error52) {
90885
- log.error(error52 instanceof Error ? error52.message : "Invalid query");
90886
- process.exit(1);
90906
+ failClosed(error52, opts);
90887
90907
  }
90888
90908
  let prepared;
90889
90909
  try {
90890
90910
  prepared = prepareQuery(input);
90891
90911
  } catch (error52) {
90892
- log.error(error52 instanceof Error ? error52.message : "Invalid Query V6 document");
90893
- process.exit(1);
90912
+ failClosed(error52, opts);
90894
90913
  }
90895
90914
  await runKernelCommand({
90896
90915
  opts,
@@ -90977,6 +90996,208 @@ Examples:
90977
90996
  };
90978
90997
  });
90979
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
+
90980
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
90981
91202
  var init_kernel2 = __esm(() => {
90982
91203
  init_schema7();
@@ -90992,6 +91213,11 @@ __export(exports_logs, {
90992
91213
  function buildJournalInput(opts) {
90993
91214
  const exact10 = nonEmpty4(opts.topic);
90994
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
+ }
90995
91221
  return {
90996
91222
  ...exact10 === undefined && prefix === undefined ? {} : {
90997
91223
  topics: {
@@ -91000,12 +91226,28 @@ function buildJournalInput(opts) {
91000
91226
  }
91001
91227
  },
91002
91228
  ...nonEmpty4(opts.principal) === undefined ? {} : { principal: opts.principal },
91003
- ...nonEmpty4(opts.since) === undefined ? {} : { since: opts.since },
91004
- ...nonEmpty4(opts.until) === undefined ? {} : { until: opts.until },
91005
- ...nonEmpty4(opts.cursor) === undefined ? {} : { cursor: opts.cursor },
91229
+ ...since === undefined ? {} : { since },
91230
+ ...until === undefined ? {} : { until },
91231
+ ...opts.cursor === undefined ? {} : { cursor: cursorFlag(opts.cursor) },
91006
91232
  limit: opts.limit === undefined ? DEFAULT_LIMIT2 : positiveInteger3("--limit", opts.limit)
91007
91233
  };
91008
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
+ }
91009
91251
  function acceptJournalPage(input) {
91010
91252
  if (!isRecord8(input) || !Array.isArray(input.records)) {
91011
91253
  throw new TypeError("Kernel journal response must contain a records array");
@@ -91114,6 +91356,14 @@ function positiveInteger3(flag, raw2) {
91114
91356
  }
91115
91357
  return value2;
91116
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
+ }
91117
91367
  function nonEmpty4(input) {
91118
91368
  const value2 = input?.trim();
91119
91369
  return value2 ? value2 : undefined;
@@ -91121,14 +91371,17 @@ function nonEmpty4(input) {
91121
91371
  function isRecord8(input) {
91122
91372
  return input !== null && typeof input === "object" && !Array.isArray(input);
91123
91373
  }
91124
- 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;
91125
91375
  var init_logs = __esm(() => {
91126
91376
  init_path5();
91127
91377
  init_kernel2();
91128
91378
  init_source();
91129
91379
  init_connection2();
91380
+ init_log();
91130
91381
  init_output();
91131
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,}$/;
91132
91385
  logs_default = {
91133
91386
  name: "logs",
91134
91387
  description: "Read or follow the authorized Kernel journal",
@@ -91158,10 +91411,15 @@ Examples:
91158
91411
  { flags: "--follow", description: "Poll using returned cursors until interrupted" }
91159
91412
  ],
91160
91413
  action: async (opts) => {
91161
- if (opts.follow)
91162
- await follow(opts);
91163
- else
91164
- 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
+ }
91165
91423
  }
91166
91424
  };
91167
91425
  });
@@ -92043,10 +92301,11 @@ What it does:
92043
92301
  an audience-bound credential for shell mounts, and the kernel endpoint.
92044
92302
 
92045
92303
  Examples:
92046
- $ astrale view /crm/customers/ada # views on a node
92047
- $ astrale view /:crm.acme.dev:view.dashboard # explicit ViewPath
92304
+ $ astrale view @customer
92305
+ $ astrale view /:crm.example.dev:view.dashboard
92048
92306
  $ astrale view /:agents.astrale.ai:view.agent --target @f00d1234 --as alice
92049
- $ astrale view /crm/customers/ada --snapshot # open + show it
92307
+ $ astrale view @customer --snapshot
92308
+ $ astrale view --list
92050
92309
  $ astrale view --sessions ; astrale view --close --all
92051
92310
  `,
92052
92311
  action: async (spec, opts) => {
@@ -92054,6 +92313,8 @@ Examples:
92054
92313
  return closeCommand(opts);
92055
92314
  if (opts.sessions)
92056
92315
  return sessionsCommand(opts);
92316
+ if (opts.list && !spec)
92317
+ return sessionsCommand(opts);
92057
92318
  rejectUnrepresentableOverrides(opts);
92058
92319
  if (!spec)
92059
92320
  return fatal(new Error("Nothing to open — pass a ViewPath or target node."));
@@ -93959,6 +94220,7 @@ var create_default2;
93959
94220
  var init_create3 = __esm(() => {
93960
94221
  init_identity8();
93961
94222
  init_log();
94223
+ init_output();
93962
94224
  create_default2 = {
93963
94225
  name: "create",
93964
94226
  description: "Create a new identity",
@@ -93966,15 +94228,20 @@ var init_create3 = __esm(() => {
93966
94228
  options: [
93967
94229
  { flags: "--subject <sub>", description: "Custom subject (defaults to name)" },
93968
94230
  { flags: "--local", description: "Local-only identity (default)" },
93969
- { 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
93970
94233
  ],
93971
94234
  action: async (name, opts) => {
93972
94235
  try {
93973
94236
  const mode = opts.remote ? "remote" : "local";
93974
94237
  const identity3 = await createIdentity(name, { subject: opts.subject, mode });
94238
+ if (isMachine(opts)) {
94239
+ output({ name, ...identity3 }, opts);
94240
+ return;
94241
+ }
93975
94242
  log.success(`Created identity "${name}" (subject: ${identity3.subject}, mode: ${identity3.mode})`);
93976
94243
  } catch (e) {
93977
- fatal(e);
94244
+ fatal(e, opts);
93978
94245
  }
93979
94246
  }
93980
94247
  };
@@ -94207,16 +94474,22 @@ var use_default4;
94207
94474
  var init_use4 = __esm(() => {
94208
94475
  init_identity8();
94209
94476
  init_log();
94477
+ init_output();
94210
94478
  use_default4 = {
94211
94479
  name: "use",
94212
94480
  description: "Set the active CLI identity",
94213
94481
  arguments: [{ name: "name", description: "Identity name", required: true }],
94214
- action: async (name) => {
94482
+ options: [...RAW_OUTPUT_OPTIONS],
94483
+ action: async (name, opts) => {
94215
94484
  try {
94216
94485
  await setDefault(name);
94486
+ if (isMachine(opts)) {
94487
+ output({ default: name }, opts);
94488
+ return;
94489
+ }
94217
94490
  log.success(`Active identity set to "${name}"`);
94218
94491
  } catch (e) {
94219
- fatal(e);
94492
+ fatal(e, opts);
94220
94493
  }
94221
94494
  }
94222
94495
  };
@@ -94231,16 +94504,22 @@ var delete_default2;
94231
94504
  var init_delete2 = __esm(() => {
94232
94505
  init_identity8();
94233
94506
  init_log();
94507
+ init_output();
94234
94508
  delete_default2 = {
94235
94509
  name: "delete",
94236
94510
  description: "Delete an identity",
94237
94511
  arguments: [{ name: "name", description: "Identity name", required: true }],
94238
- action: async (name) => {
94512
+ options: [...RAW_OUTPUT_OPTIONS],
94513
+ action: async (name, opts) => {
94239
94514
  try {
94240
94515
  await deleteIdentity(name);
94516
+ if (isMachine(opts)) {
94517
+ output({ deleted: name }, opts);
94518
+ return;
94519
+ }
94241
94520
  log.success(`Deleted identity "${name}"`);
94242
94521
  } catch (e) {
94243
- fatal(e);
94522
+ fatal(e, opts);
94244
94523
  }
94245
94524
  }
94246
94525
  };
@@ -94255,6 +94534,7 @@ var sync_default;
94255
94534
  var init_sync = __esm(() => {
94256
94535
  init_identity8();
94257
94536
  init_log();
94537
+ init_output();
94258
94538
  sync_default = {
94259
94539
  name: "sync",
94260
94540
  description: "Migrate an identity local → remote (astrale cloud)",
@@ -94263,7 +94543,8 @@ var init_sync = __esm(() => {
94263
94543
  {
94264
94544
  flags: "--force",
94265
94545
  description: "Tag as remote in the local registry even without cloud login"
94266
- }
94546
+ },
94547
+ ...RAW_OUTPUT_OPTIONS
94267
94548
  ],
94268
94549
  action: async (name, opts) => {
94269
94550
  try {
@@ -94272,10 +94553,14 @@ var init_sync = __esm(() => {
94272
94553
  fatalNotImplemented("identity sync (remote)", "Cloud adapter is stubbed in v1. Use --force to pre-tag the identity locally.");
94273
94554
  }
94274
94555
  await setIdentityMode(name, "remote");
94556
+ if (isMachine(opts)) {
94557
+ output({ name, mode: "remote", subject: identity3.subject }, opts);
94558
+ return;
94559
+ }
94275
94560
  log.warn(`Tagged "${name}" as remote locally (cloud sync stubbed in v1)`);
94276
94561
  log.dim(` subject=${identity3.subject}`);
94277
94562
  } catch (e) {
94278
- fatal(e);
94563
+ fatal(e, opts);
94279
94564
  }
94280
94565
  }
94281
94566
  };
@@ -94290,21 +94575,31 @@ var unsync_default;
94290
94575
  var init_unsync = __esm(() => {
94291
94576
  init_identity8();
94292
94577
  init_log();
94578
+ init_output();
94293
94579
  unsync_default = {
94294
94580
  name: "unsync",
94295
94581
  description: "Migrate an identity remote → local",
94296
94582
  arguments: [{ name: "name", description: "Identity name", required: true }],
94297
- action: async (name) => {
94583
+ options: [...RAW_OUTPUT_OPTIONS],
94584
+ action: async (name, opts) => {
94298
94585
  try {
94299
94586
  const identity3 = await getIdentity(name);
94300
94587
  if (identity3.mode !== "remote") {
94588
+ if (isMachine(opts)) {
94589
+ output({ name, mode: identity3.mode ?? "local", unchanged: true }, opts);
94590
+ return;
94591
+ }
94301
94592
  log.warn(`Identity "${name}" is already ${identity3.mode ?? "local"}`);
94302
94593
  return;
94303
94594
  }
94304
94595
  await setIdentityMode(name, "local");
94596
+ if (isMachine(opts)) {
94597
+ output({ name, mode: "local" }, opts);
94598
+ return;
94599
+ }
94305
94600
  log.success(`Identity "${name}" → local`);
94306
94601
  } catch (e) {
94307
- fatal(e);
94602
+ fatal(e, opts);
94308
94603
  }
94309
94604
  }
94310
94605
  };
@@ -94319,6 +94614,7 @@ var export_default;
94319
94614
  var init_export2 = __esm(() => {
94320
94615
  init_identity8();
94321
94616
  init_log();
94617
+ init_output();
94322
94618
  init_prompt();
94323
94619
  export_default = {
94324
94620
  name: "export",
@@ -94328,19 +94624,24 @@ var init_export2 = __esm(() => {
94328
94624
  { name: "path", description: "Output file path", required: true }
94329
94625
  ],
94330
94626
  options: [
94331
- { 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
94332
94629
  ],
94333
94630
  action: async (name, path5, opts) => {
94334
94631
  try {
94335
94632
  const envelope2 = await exportIdentity(name);
94336
94633
  const passphrase = opts.encrypt ? await readPassphrase("Passphrase (min 8 chars): ", { minLength: 8 }) : undefined;
94337
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
+ }
94338
94639
  log.success(`Exported identity "${name}" → ${path5}${opts.encrypt ? " (encrypted)" : ""}`);
94339
94640
  if (!opts.encrypt) {
94340
94641
  log.warn(" Plaintext private JWK — keep this file secure. Use --encrypt for passphrase wrapping.");
94341
94642
  }
94342
94643
  } catch (e) {
94343
- fatal(e);
94644
+ fatal(e, opts);
94344
94645
  }
94345
94646
  }
94346
94647
  };
@@ -94356,6 +94657,7 @@ var import_default;
94356
94657
  var init_import2 = __esm(() => {
94357
94658
  init_identity8();
94358
94659
  init_log();
94660
+ init_output();
94359
94661
  init_prompt();
94360
94662
  import_default = {
94361
94663
  name: "import",
@@ -94373,7 +94675,8 @@ var init_import2 = __esm(() => {
94373
94675
  {
94374
94676
  flags: "--replace",
94375
94677
  description: "Replace an existing key-backed identity with the imported keypair"
94376
- }
94678
+ },
94679
+ ...RAW_OUTPUT_OPTIONS
94377
94680
  ],
94378
94681
  action: async (path5, opts) => {
94379
94682
  try {
@@ -94386,9 +94689,13 @@ var init_import2 = __esm(() => {
94386
94689
  issuer: opts.issuer,
94387
94690
  replace: opts.replace
94388
94691
  });
94692
+ if (isMachine(opts)) {
94693
+ output({ name, ...identity3 }, opts);
94694
+ return;
94695
+ }
94389
94696
  log.success(`Imported identity "${name}" (subject=${identity3.subject}, kid=${identity3.kid ?? "?"})`);
94390
94697
  } catch (e) {
94391
- fatal(e);
94698
+ fatal(e, opts);
94392
94699
  }
94393
94700
  }
94394
94701
  };
@@ -94508,10 +94815,10 @@ async function resolveIdentityName(opts) {
94508
94815
  if (opts.name) {
94509
94816
  const identity4 = await getIdentity(opts.name);
94510
94817
  if ((identity4.source ?? "key") !== "idp") {
94511
- throw new Error(`Identity "${opts.name}" is not IdP-backed`);
94818
+ throw new AstraleError("AUTH_ERROR", `Identity "${opts.name}" is not IdP-backed`);
94512
94819
  }
94513
94820
  if (opts.idp && identity4.idp !== opts.idp) {
94514
- 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}"`);
94515
94822
  }
94516
94823
  return opts.name;
94517
94824
  }
@@ -94519,17 +94826,17 @@ async function resolveIdentityName(opts) {
94519
94826
  const store = await readIdentities();
94520
94827
  const matches3 = Object.entries(store.identities).filter(([, identity4]) => identity4.source === "idp" && identity4.idp === opts.idp).map(([name]) => name);
94521
94828
  if (matches3.length === 0) {
94522
- 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}`);
94523
94830
  }
94524
94831
  if (matches3.includes(store.default))
94525
94832
  return store.default;
94526
94833
  if (matches3.length === 1)
94527
94834
  return matches3[0];
94528
- 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.`);
94529
94836
  }
94530
94837
  const identity3 = await getDefault();
94531
94838
  if ((identity3.source ?? "key") !== "idp") {
94532
- 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.");
94533
94840
  }
94534
94841
  return identity3.name;
94535
94842
  }
@@ -94542,6 +94849,7 @@ function tokenFromSession(session, type) {
94542
94849
  }
94543
94850
  var token_default2;
94544
94851
  var init_token2 = __esm(() => {
94852
+ init_errors2();
94545
94853
  init_identity8();
94546
94854
  init_idp();
94547
94855
  init_idp_session();
@@ -94581,7 +94889,12 @@ Examples:
94581
94889
  $ astrale auth token --name alice --type id --json
94582
94890
  `,
94583
94891
  action: async (opts) => {
94584
- const result = await resolveAuthToken(opts);
94892
+ let result;
94893
+ try {
94894
+ result = await resolveAuthToken(opts);
94895
+ } catch (error52) {
94896
+ fatal(error52, opts);
94897
+ }
94585
94898
  if (opts.raw) {
94586
94899
  process.stdout.write(result.token + `
94587
94900
  `);
@@ -95665,6 +95978,7 @@ var {
95665
95978
 
95666
95979
  // src/lib/command-dx.ts
95667
95980
  init_source();
95981
+ init_output();
95668
95982
  function collectCommandCatalog(program2) {
95669
95983
  const out = [];
95670
95984
  function walk(command, path) {
@@ -95684,36 +95998,36 @@ function renderCommanderError(program2, error, argv = process.argv.slice(2)) {
95684
95998
  const catalog = collectCommandCatalog(program2);
95685
95999
  const matched = matchRegisteredPrefix(program2, tokens);
95686
96000
  if (matched.path.length === 0 && tokens.length > 0) {
95687
- return renderUnknownCommand(tokens, catalog);
96001
+ return maybeMachine(renderUnknownCommand(tokens, catalog));
95688
96002
  }
95689
96003
  if (error.code === "commander.missingArgument") {
95690
96004
  const usage = usageFor(matched.path, matched.command);
95691
96005
  const argName = error.message.match(/'([^']+)'/)?.[1];
95692
- return [
96006
+ return maybeMachine([
95693
96007
  `Missing required argument${argName ? ` ${source_default.bold(`<${argName}>`)}` : ""} for ${source_default.bold(`astrale ${matched.path.join(" ")}`)}`,
95694
96008
  "",
95695
96009
  "Usage:",
95696
96010
  ` astrale ${usage}`
95697
96011
  ].join(`
95698
- `);
96012
+ `));
95699
96013
  }
95700
96014
  if (error.code === "commander.excessArguments") {
95701
96015
  const usage = usageFor(matched.path, matched.command);
95702
96016
  const extra = tokens.slice(matched.path.length).join(" ");
95703
- return [
96017
+ return maybeMachine([
95704
96018
  `Unexpected argument${extra.includes(" ") ? "s" : ""} for ${source_default.bold(`astrale ${matched.path.join(" ")}`)}${extra ? `: ${extra}` : ""}`,
95705
96019
  "",
95706
96020
  "Usage:",
95707
96021
  ` astrale ${usage}`
95708
96022
  ].join(`
95709
- `);
96023
+ `));
95710
96024
  }
95711
96025
  const suggestions = nearestCommands(tokens.join(" "), catalog);
95712
- return [
96026
+ return maybeMachine([
95713
96027
  error.message,
95714
96028
  ...suggestions.length > 0 ? ["", "Did you mean:", ...suggestions.map((s) => ` astrale ${s}`)] : []
95715
96029
  ].join(`
95716
- `);
96030
+ `));
95717
96031
  }
95718
96032
  var RETIRED_COMMANDS = {
95719
96033
  ls: "astrale query <source> --edge <class>",
@@ -95764,6 +96078,15 @@ function usageFor(path, command) {
95764
96078
  const suffix = command.usage().replace(/\[options\]\s*/g, "").replace(/\s+/g, " ").trim();
95765
96079
  return [path.join(" "), suffix].filter(Boolean).join(" ");
95766
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
+ }
95767
96090
  function stripOptions(argv) {
95768
96091
  const out = [];
95769
96092
  for (const token of argv) {
@@ -95800,6 +96123,12 @@ function levenshtein(a, b) {
95800
96123
  return prev[b.length] ?? 0;
95801
96124
  }
95802
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
+
95803
96132
  // node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
95804
96133
  var import__2 = __toESM(require_commander(), 1);
95805
96134
  var {
@@ -95835,7 +96164,7 @@ var KERNEL_PASSTHROUGH_OPTIONS = Object.freeze([
95835
96164
  { flags: "--creds <token>", description: "Use a pre-signed credential (e.g. delegation token)" },
95836
96165
  {
95837
96166
  flags: "--anonymous",
95838
- 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)"
95839
96168
  },
95840
96169
  { flags: "--debug", description: "Print full error diagnostics on failure" }
95841
96170
  ]);
@@ -95906,7 +96235,7 @@ function registerGroup(parent, group) {
95906
96235
  // src/program/build.ts
95907
96236
  async function buildProgram() {
95908
96237
  const program3 = new Command2;
95909
- 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 () => {
95910
96239
  if (process.stdin.isTTY && process.stdout.isTTY) {
95911
96240
  const { shouldAutostartSetup: shouldAutostartSetup2 } = await Promise.resolve().then(() => (init_engine(), exports_engine));
95912
96241
  if (await shouldAutostartSetup2()) {
@@ -95931,6 +96260,7 @@ async function buildProgram() {
95931
96260
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_get(), exports_get))).default));
95932
96261
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_mutate4(), exports_mutate))).default));
95933
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));
95934
96264
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_logs(), exports_logs))).default));
95935
96265
  registerCommand(program3, withKernelOptions((await Promise.resolve().then(() => (init_view6(), exports_view2))).default));
95936
96266
  registerCommand(program3, (await Promise.resolve().then(() => (init_status(), exports_status))).default);
@@ -96016,7 +96346,7 @@ async function buildProgram() {
96016
96346
  program3.addHelpText("after", `
96017
96347
  Command groups:
96018
96348
  Getting started setup (sign in, pick an instance, equip your workspace)
96019
- Kernel get, mutate, call, query, token
96349
+ Kernel get, mutate, call, query, introspect, logs, view, token
96020
96350
  Management admin, instance, domain, identity, auth, idp, update
96021
96351
  Agent browser (drive the GUI via agent-browser)
96022
96352
  Studio studio (launch the local Domain Studio GUI for a workspace)
@@ -96038,6 +96368,7 @@ Examples:
96038
96368
  $ astrale instance status staging
96039
96369
  $ astrale token --audience shell.astrale.ai --ttl 3600
96040
96370
  $ astrale query /:notes.example.dev:class.Note --limit 50
96371
+ $ astrale introspect /:host.astrale.ai:class.Manager:createInstance
96041
96372
  $ astrale query --file query.v6.json --cursor "$CURSOR"
96042
96373
  `);
96043
96374
  return program3;
@@ -96279,6 +96610,7 @@ var errorName;
96279
96610
  if (finalize2)
96280
96611
  process.on("exit", (code) => finalize2(code ?? 0, errorName));
96281
96612
  maybeTriggerAnalysis(process.argv);
96613
+ configureInvocation(process.argv);
96282
96614
  var program3 = await buildProgram();
96283
96615
  overrideExits(program3);
96284
96616
  program3.configureOutput({ writeErr: () => {