@astrale-os/cli 1.0.0-beta.7 → 1.0.0-beta.9

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 (75) hide show
  1. package/README.md +1 -1
  2. package/dist/astrale.js +1531 -1356
  3. package/dist/public/connect-core.js +4 -4
  4. package/dist/types/admin/binding.d.ts +19 -0
  5. package/dist/types/admin/instance/client.d.ts +22 -0
  6. package/dist/types/admin/instance/index.d.ts +2 -0
  7. package/dist/types/admin/instance/model.d.ts +3 -9
  8. package/dist/types/connection/auth.d.ts +3 -0
  9. package/dist/types/connection/call.d.ts +3 -0
  10. package/dist/types/connection/command.d.ts +27 -0
  11. package/dist/types/connection/credential.d.ts +14 -0
  12. package/dist/types/connection/errors.d.ts +1 -0
  13. package/dist/types/connection/exchange.d.ts +9 -0
  14. package/dist/types/connection/failure/classify.d.ts +2 -0
  15. package/dist/types/connection/failure/index.d.ts +5 -0
  16. package/dist/types/connection/failure/model.d.ts +25 -0
  17. package/dist/types/connection/failure/render.d.ts +3 -0
  18. package/dist/types/connection/index.d.ts +8 -0
  19. package/dist/types/connection/reasons.d.ts +37 -0
  20. package/dist/types/connection/self.d.ts +37 -0
  21. package/dist/types/connection/session.d.ts +31 -0
  22. package/dist/types/connection/target.d.ts +38 -0
  23. package/dist/types/lib/admin-instance.d.ts +17 -0
  24. package/dist/types/lib/failure-debug.d.ts +1 -0
  25. package/dist/types/lib/instance.d.ts +7 -1
  26. package/dist/types/lib/log.d.ts +3 -1
  27. package/dist/types/lib/self.d.ts +9 -0
  28. package/package.json +1 -1
  29. package/src/admin/instance/__tests__/client.test.ts +4 -104
  30. package/src/admin/instance/client.ts +2 -96
  31. package/src/admin/instance/index.ts +1 -2
  32. package/src/admin/instance/model.ts +4 -14
  33. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  34. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  35. package/src/commands/call-describe.ts +1 -1
  36. package/src/commands/call.ts +2 -2
  37. package/src/commands/domain/list.ts +1 -1
  38. package/src/commands/domain/publish.ts +14 -11
  39. package/src/commands/get.ts +1 -1
  40. package/src/commands/instance/create.ts +8 -16
  41. package/src/commands/instance/delete.ts +7 -6
  42. package/src/commands/instance/list.ts +2 -2
  43. package/src/commands/instance/status.ts +4 -4
  44. package/src/commands/instance/use.ts +16 -12
  45. package/src/commands/introspect.ts +5 -5
  46. package/src/commands/view.ts +3 -3
  47. package/src/connection/__tests__/credential.test.ts +19 -0
  48. package/src/connection/__tests__/target.test.ts +1 -0
  49. package/src/connection/auth.ts +13 -0
  50. package/src/connection/failure/index.ts +1 -1
  51. package/src/connection/session.ts +12 -1
  52. package/src/lib/__tests__/command-dx.test.ts +1 -1
  53. package/src/lib/__tests__/domain-publication.test.ts +6 -1
  54. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  55. package/src/lib/__tests__/instance-target.test.ts +1 -0
  56. package/src/lib/__tests__/log-errors.test.ts +11 -0
  57. package/src/lib/admin-instance.ts +14 -8
  58. package/src/lib/command-dx.ts +8 -5
  59. package/src/lib/domain-publication.ts +8 -6
  60. package/src/lib/instance-candidates.ts +2 -2
  61. package/src/lib/instance.ts +14 -10
  62. package/src/lib/log.ts +6 -4
  63. package/src/lib/provision-instance.ts +34 -57
  64. package/src/program/__tests__/program.test.ts +20 -4
  65. package/src/program/build.ts +2 -2
  66. package/src/setup/__tests__/instance-step.test.ts +27 -10
  67. package/src/setup/steps/instance.ts +22 -15
  68. package/studio/client/dist/assets/{elk-api-Di4OXGNH.js → elk-api-ByzoDZWH.js} +1 -1
  69. package/studio/client/dist/assets/{index-DTjvkOUX.js → index-B0RCgUOT.js} +4 -4
  70. package/studio/client/dist/assets/{index-BLm6J11H.js → index-N8J8EKlB.js} +2 -2
  71. package/studio/client/dist/index.html +1 -1
  72. package/studio/server/introspect/runtime.test.ts +2 -2
  73. package/viewer/dist/main.js +28 -28
  74. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  75. /package/src/{connection/failure/debug.ts → lib/failure-debug.ts} +0 -0
@@ -8203,14 +8203,14 @@ function isPidAlive(pid) {
8203
8203
  function sleep(milliseconds) {
8204
8204
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
8205
8205
  }
8206
- // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.7/node_modules/@astrale-os/kernel-dsl/dist/value/limits.js
8206
+ // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/limits.js
8207
8207
  var defaultLimits = Object.freeze({
8208
8208
  maxBytes: 16 * 1024 * 1024,
8209
8209
  maxDepth: 64,
8210
8210
  maxMembers: 1e5,
8211
8211
  maxStringBytes: 1024 * 1024
8212
8212
  });
8213
- // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.7/node_modules/@astrale-os/kernel-dsl/dist/value/canonical.js
8213
+ // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/canonical.js
8214
8214
  var encoder2 = new TextEncoder;
8215
8215
  // node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
8216
8216
  var CharacterCodes;
@@ -8390,7 +8390,7 @@ var ParseErrorCode;
8390
8390
  ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
8391
8391
  })(ParseErrorCode || (ParseErrorCode = {}));
8392
8392
 
8393
- // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.7/node_modules/@astrale-os/kernel-dsl/dist/value/decode.js
8393
+ // node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/decode.js
8394
8394
  var decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
8395
8395
  // node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
8396
8396
  var exports_external = {};
@@ -27595,7 +27595,7 @@ var log = {
27595
27595
  dim: (msg) => console.log(source_default.dim(msg))
27596
27596
  };
27597
27597
  var IS_CI = !!(process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.NO_SPINNER);
27598
- // node_modules/.pnpm/@astrale-os+kernel-core@0.9.0-beta.9/node_modules/@astrale-os/kernel-core/dist/dns-label.js
27598
+ // node_modules/.pnpm/@astrale-os+kernel-core@0.9.0-beta.10/node_modules/@astrale-os/kernel-core/dist/dns-label.js
27599
27599
  var DNS_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
27600
27600
  function isDnsLabel(value) {
27601
27601
  return DNS_LABEL_RE.test(value);
@@ -0,0 +1,19 @@
1
+ import type { Input } from '@astrale-os/sdk/client';
2
+ import type { ClientSession } from '@astrale-os/sdk/client/session';
3
+ import type { ResolvedClass, ResolvedProperty } from '@astrale-os/sdk/schema';
4
+ import type { DomainBinding } from '@astrale-os/shell';
5
+ import { Path } from '@astrale-os/sdk/graph/path';
6
+ export type AdminBinding = DomainBinding;
7
+ /** Bind the exact Admin revision installed on this source Kernel. */
8
+ export declare function bindAdmin(session: ClientSession): Promise<AdminBinding>;
9
+ /** Admit an injected dynamic binding as the Admin Domain. */
10
+ export declare function requireAdminBinding(binding: AdminBinding): AdminBinding;
11
+ /** Resolve one required Admin Class without rebuilding its schema contract. */
12
+ export declare function requireAdminClass(binding: AdminBinding, name: string, kind: 'node'): ResolvedClass<'node'>;
13
+ export declare function requireAdminClass(binding: AdminBinding, name: string, kind: 'edge'): ResolvedClass<'edge'>;
14
+ /** Resolve one required Admin Core Node as its canonical projection Path. */
15
+ export declare function requireAdminCore(binding: AdminBinding, name: string): Path;
16
+ /** Resolve one effective Property by unambiguous member name. */
17
+ export declare function requireAdminProperty(owner: ResolvedClass, name: string): ResolvedProperty<unknown>;
18
+ /** Invoke one resolved executable instance Method through Kernel Client. */
19
+ export declare function invokeAdminMethod(session: ClientSession, binding: AdminBinding, owner: ResolvedClass<'node'>, name: string, receiver: Path, input: Input): Promise<unknown>;
@@ -0,0 +1,22 @@
1
+ import type { ClientSession } from '@astrale-os/sdk/client/session';
2
+ import { type AdminBinding } from '../binding';
3
+ import { type DomainInstallReceipt, type InstanceInfo, type OwnedInstanceInfo } from './model';
4
+ export interface AdminInstanceContext {
5
+ readonly session: ClientSession;
6
+ }
7
+ export interface AdminInstanceApi {
8
+ list(): Promise<OwnedInstanceInfo[]>;
9
+ create(slug: string): Promise<InstanceInfo>;
10
+ status(identifier: string): Promise<InstanceInfo>;
11
+ delete(identifier: string): Promise<InstanceInfo>;
12
+ installDomain(identifier: string, domain: string): Promise<DomainInstallReceipt>;
13
+ }
14
+ export interface AdminInstanceDependencies {
15
+ readonly bind?: (session: ClientSession) => Promise<AdminBinding>;
16
+ readonly operationId?: (kind: 'create' | 'status' | 'delete' | 'install-domain') => string;
17
+ }
18
+ /**
19
+ * Bind one discovered Admin root revision and expose only the public Instance
20
+ * product journey. No Host lifecycle method is present on this capability.
21
+ */
22
+ export declare function connectAdminInstances(context: AdminInstanceContext, dependencies?: AdminInstanceDependencies): Promise<AdminInstanceApi>;
@@ -0,0 +1,2 @@
1
+ export { connectAdminInstances, type AdminInstanceApi, type AdminInstanceContext, type AdminInstanceDependencies, } from './client';
2
+ export { AdminInstanceNotFoundError, findOwnedInstance, formatInstanceState, type DomainInstallReceipt, type InstanceInfo, type InstanceState, type OwnedInstanceInfo, } from './model';
@@ -4,9 +4,7 @@ export interface InstanceInfo {
4
4
  readonly id: string;
5
5
  readonly slug: string;
6
6
  readonly url: string;
7
- readonly hostId?: string;
8
- readonly region?: string;
9
- readonly state?: InstanceState;
7
+ readonly state: InstanceState;
10
8
  readonly phase?: string;
11
9
  readonly error?: string | null;
12
10
  readonly createdAt?: string;
@@ -28,12 +26,8 @@ export declare class AdminInstanceNotFoundError extends AstraleError {
28
26
  readonly identifier: string;
29
27
  constructor(identifier: string);
30
28
  }
31
- export declare class AdminHostNotFoundError extends AstraleError {
32
- readonly identifier: string;
33
- constructor(identifier: string);
34
- }
35
29
  /** Match an owner-scoped Instance by slug, canonical Node Path, or bare Node id. */
36
30
  export declare function findOwnedInstance(instances: readonly OwnedInstanceInfo[], identifier: string): OwnedInstanceInfo | undefined;
37
- /** Human-readable location of an Instance (state, region, and Host Path). */
38
- export declare function formatInstanceLocation(info: InstanceInfo): string;
31
+ /** Human-readable non-ready lifecycle state for one Instance. */
32
+ export declare function formatInstanceState(info: InstanceInfo): string;
39
33
  import { AstraleError } from '../../errors';
@@ -1,4 +1,5 @@
1
1
  import type { AstraleConfig } from '../lib/config';
2
+ import type { ConnectionOptions, ConnectionTarget } from './target';
2
3
  import { type Identity } from '../identity/registry';
3
4
  import { IdpAudienceMismatchError } from '../lib/idp';
4
5
  import { IdpSessionNoRefreshTokenError } from '../lib/idp-session';
@@ -7,6 +8,8 @@ export type KeyIdentityAuthOptions = {
7
8
  subject?: string;
8
9
  audience: string;
9
10
  };
11
+ /** Pin the local identity label before a session performs any authenticated effect. */
12
+ export declare function bindCredentialIdentity<Options extends ConnectionOptions>(options: Options, target: ConnectionTarget): Promise<Options>;
10
13
  /**
11
14
  * Resolve a signed JWT credential from CLI options.
12
15
  *
@@ -0,0 +1,3 @@
1
+ import { type Call } from '@astrale-os/sdk/client';
2
+ /** Convert the CLI's untrusted text/JSON boundary into the one public Call representation. */
3
+ export declare function createPathCall(path: string, input: unknown): Call;
@@ -0,0 +1,27 @@
1
+ import type { ConnectionContext } from './session';
2
+ import type { ConnectionOptions } from './target';
3
+ export interface KernelCommandOpts extends ConnectionOptions {
4
+ readonly raw?: boolean;
5
+ readonly json?: boolean;
6
+ readonly format?: 'yaml' | 'json';
7
+ readonly debug?: boolean;
8
+ }
9
+ export interface OperationRecovery {
10
+ readonly operation: string;
11
+ readonly retry: string;
12
+ }
13
+ /**
14
+ * Encapsulates the standard kernel command lifecycle:
15
+ * spinner → connect → call → timing → output → error handling.
16
+ *
17
+ * Commands provide a `fn` that does the actual work and an optional
18
+ * `format` callback for custom output. If `format` is omitted, the
19
+ * result is passed to the standard `output()` function.
20
+ */
21
+ export declare function runKernelCommand<T>(input: {
22
+ readonly opts: KernelCommandOpts;
23
+ readonly label: string;
24
+ readonly recovery?: OperationRecovery;
25
+ readonly fn: (context: ConnectionContext) => Promise<T>;
26
+ readonly format?: (result: T, options: KernelCommandOpts, machine: boolean) => void | Promise<void>;
27
+ }): Promise<void>;
@@ -0,0 +1,14 @@
1
+ import type { Fetch } from '@astrale-os/sdk/client';
2
+ import type { SessionAuth } from '@astrale-os/sdk/client/session';
3
+ import { type IssuerId } from '@astrale-os/sdk/auth';
4
+ import type { AstraleConfig } from '../lib/config';
5
+ import type { ConnectionOptions, ConnectionTarget } from './target';
6
+ export interface SourceCredentialResolver {
7
+ resolve(audience: IssuerId, signal: AbortSignal): Promise<string>;
8
+ }
9
+ /** Resolve source authority; an omitted Session delegation preserves exact current authority. */
10
+ export declare function createConnectionCredential(expectedSourceIssuer: IssuerId, source: SourceCredentialResolver): SessionAuth;
11
+ /** Bind CLI identity state and Core Auth delegation to one Session auth capability. */
12
+ export declare function createCliCredential(target: ConnectionTarget, options: ConnectionOptions, config: AstraleConfig, fetch?: Fetch, timeoutMs?: number): SessionAuth | undefined;
13
+ /** Reject contradictory explicit credential selections before identity or network access. */
14
+ export declare function validateCredentialSelection(options: ConnectionOptions): void;
@@ -0,0 +1 @@
1
+ export { formatKernelError, functionInputIssues, schemaUpgradeHint } from './failure';
@@ -0,0 +1,9 @@
1
+ import type { IssuerId } from '@astrale-os/sdk/auth';
2
+ import type { Fetch } from '@astrale-os/sdk/client';
3
+ import type { SourceCredentialResolver } from './credential';
4
+ import type { ConnectionTarget } from './target';
5
+ import { ExchangeCredentialCache } from '../state/exchange-credentials';
6
+ /** Exchange exact authenticated User authority for a Domain bearer bound to this Kernel. */
7
+ export declare function createExchangeCredentialResolver(target: ConnectionTarget & {
8
+ readonly domainIssuer: IssuerId;
9
+ }, source: SourceCredentialResolver, fetch: Fetch, timeoutMs: number, cache?: ExchangeCredentialCache): SourceCredentialResolver;
@@ -0,0 +1,2 @@
1
+ import type { FailureDiagnostic } from './model';
2
+ export declare function classifyFailure(error: unknown): FailureDiagnostic;
@@ -0,0 +1,5 @@
1
+ import type { OperationRecovery } from '../command';
2
+ export { functionInputIssues, schemaUpgradeHint } from '../reasons';
3
+ export declare function formatKernelError(error: unknown, machine: boolean, urlArg?: string, debug?: boolean, options?: {
4
+ recovery?: OperationRecovery;
5
+ }): Promise<void>;
@@ -0,0 +1,25 @@
1
+ export type TransportDiagnosticContext = {
2
+ readonly kind: 'acquisition';
3
+ readonly resource: 'publication' | 'bundle';
4
+ } | {
5
+ readonly kind: 'invocation';
6
+ readonly delivery: 'not-sent' | 'unknown';
7
+ readonly invocation?: unknown;
8
+ };
9
+ export type FailureDiagnostic = {
10
+ readonly kind: 'simple';
11
+ readonly code: string;
12
+ readonly message: string;
13
+ readonly hint?: string;
14
+ } | {
15
+ readonly kind: 'response';
16
+ readonly code: number;
17
+ readonly message: string;
18
+ readonly reason?: unknown;
19
+ } | {
20
+ readonly kind: 'transport';
21
+ readonly code: 'CONNECTION_ERROR' | 'DISCONNECTED' | 'TIMEOUT' | 'TRANSPORT_ERROR';
22
+ readonly message: string;
23
+ readonly phase: string;
24
+ readonly context: TransportDiagnosticContext;
25
+ };
@@ -0,0 +1,3 @@
1
+ import type { OperationRecovery } from '../command';
2
+ import type { FailureDiagnostic } from './model';
3
+ export declare function renderFailure(failure: FailureDiagnostic, machine: boolean, url: string, recovery: OperationRecovery | undefined): void;
@@ -0,0 +1,8 @@
1
+ export { createPathCall } from './call';
2
+ export { runKernelCommand } from './command';
3
+ export type { KernelCommandOpts, OperationRecovery } from './command';
4
+ export { expandSelfInCall, expandSelfInPath, withSelfHint } from './self';
5
+ export type { SelfExpansionMeta } from './self';
6
+ export { withAdminClientSession, withClientSession, type ConnectionContext } from './session';
7
+ export { registrationKeyForTarget } from './target';
8
+ export type { AdminConnectionOptions, ConnectionOptions, ConnectionTarget } from './target';
@@ -0,0 +1,37 @@
1
+ export type FunctionInputIssue = Readonly<{
2
+ code: string;
3
+ path?: string;
4
+ message: string;
5
+ }>;
6
+ export type QueryInputRepair = Readonly<{
7
+ phase: 'decode' | 'input';
8
+ path: string;
9
+ }> | Readonly<{
10
+ phase: 'plan';
11
+ issue: string;
12
+ path?: string;
13
+ }> | Readonly<{
14
+ phase: 'limit';
15
+ limit: string;
16
+ maximum: number;
17
+ actual: number;
18
+ path?: string;
19
+ }>;
20
+ export type SchemaUpgradeDetails = {
21
+ readonly origin?: string;
22
+ readonly issue?: undefined;
23
+ } | {
24
+ readonly origin: string;
25
+ readonly issue: 'issuer-changed';
26
+ readonly installedIssuer: string;
27
+ readonly replacementIssuer: string;
28
+ };
29
+ export declare function reasonCode(reason: unknown): string | undefined;
30
+ /** Admit only bounded caller-safe Function input issues established by the Kernel. */
31
+ export declare function functionInputIssues(reason: unknown): readonly FunctionInputIssue[];
32
+ /** Admit only public Query-input repair variants; unknown details remain machine-only. */
33
+ export declare function queryInputRepair(reason: unknown): QueryInputRepair | undefined;
34
+ /** Decode bounded recovery guidance while preserving the admitted reason itself elsewhere. */
35
+ export declare function schemaUpgradeDetails(reason: unknown): SchemaUpgradeDetails | undefined;
36
+ export declare function schemaUpgradeHint(details: SchemaUpgradeDetails): string;
37
+ export declare function schemaDataRemovalHint(reason: unknown): string | undefined;
@@ -0,0 +1,37 @@
1
+ import type { ConnectionContext } from './session';
2
+ /** Metadata attached to errors after an authenticated caller-authored @self expansion. */
3
+ export interface SelfExpansionMeta {
4
+ readonly original: string;
5
+ readonly expanded: string;
6
+ readonly selfId: string;
7
+ readonly slug?: string;
8
+ }
9
+ /**
10
+ * Run `action`; if it throws NodeUnavailableError, retain the authenticated
11
+ * expansion for precise diagnostics. The error is re-thrown either way.
12
+ */
13
+ export declare function withSelfHint<T>(action: () => Promise<T>, meta: SelfExpansionMeta | undefined): Promise<T>;
14
+ type AuthenticatedSelf = {
15
+ readonly id?: unknown;
16
+ readonly slug?: string;
17
+ };
18
+ export type ResolveSelfIdDependencies = {
19
+ readonly whoami?: (context: ConnectionContext) => Promise<AuthenticatedSelf>;
20
+ };
21
+ /** Resolve @self only from the effective principal authenticated by the selected Kernel. */
22
+ export declare function resolveSelfIdAuthenticated(context: ConnectionContext, dependencies?: ResolveSelfIdDependencies): Promise<{
23
+ readonly id: string;
24
+ readonly slug?: string;
25
+ }>;
26
+ /** Expand @self in path-like commands and return metadata for NotFound diagnostics. */
27
+ export declare function expandSelfInPath(path: string, context: ConnectionContext): Promise<{
28
+ readonly path: string;
29
+ readonly meta?: SelfExpansionMeta;
30
+ }>;
31
+ /** Expand @self once across one Call path and its CLI-authored string parameters. */
32
+ export declare function expandSelfInCall(path: string, parameters: Readonly<Record<string, unknown>>, context: ConnectionContext): Promise<{
33
+ readonly path: string;
34
+ readonly parameters: Readonly<Record<string, unknown>>;
35
+ readonly meta?: SelfExpansionMeta;
36
+ }>;
37
+ export {};
@@ -0,0 +1,31 @@
1
+ import type { AuthApi } from '@astrale-os/sdk/auth';
2
+ import type { GraphApi } from '@astrale-os/sdk/client';
3
+ import type { ClientSessionOptions, SessionAuth } from '@astrale-os/sdk/client/session';
4
+ import { ClientSession } from '@astrale-os/sdk/client/session';
5
+ import type { AstraleConfig } from '../lib/config';
6
+ import type { AdminConnectionOptions, ConnectionOptions, ConnectionTarget } from './target';
7
+ import { connectAdminInstances, type InstanceInfo } from '../admin/instance';
8
+ export interface ConnectionContext {
9
+ readonly session: ClientSession;
10
+ readonly graph: GraphApi;
11
+ readonly auth: AuthApi;
12
+ readonly target: ConnectionTarget;
13
+ /** Local identity label selected for this session; absent for raw credentials or anonymous use. */
14
+ readonly identity?: string;
15
+ }
16
+ interface OwnedConnection {
17
+ readonly context: ConnectionContext;
18
+ close(): void;
19
+ }
20
+ export type ConnectionFactory = (target: ConnectionTarget, timeoutMs: number, options: ConnectionOptions, config: AstraleConfig) => OwnedConnection;
21
+ /** Resolve one ordinary target, run a command action, then close terminally. */
22
+ export declare function withClientSession<Value>(options: ConnectionOptions, action: (context: ConnectionContext) => Promise<Value>): Promise<Value>;
23
+ /** Resolve the configured Admin Domain target under the same terminal lifecycle. */
24
+ export declare function withAdminClientSession<Value>(options: AdminConnectionOptions, action: (context: ConnectionContext) => Promise<Value>): Promise<Value>;
25
+ /** Owner-private seam used to prove validation order and cleanup without network I/O. */
26
+ export declare function withResolvedClientSession<Value>(target: ConnectionTarget, options: ConnectionOptions, config: AstraleConfig, action: (context: ConnectionContext) => Promise<Value>, open?: ConnectionFactory): Promise<Value>;
27
+ export declare function resolveTimeoutMs(raw: string | undefined): number;
28
+ /** Owner-private construction seam proving that transport and source identity stay distinct. */
29
+ export declare function createClientSessionOptions(target: ConnectionTarget, fetch: NonNullable<ClientSessionOptions['fetch']>, auth: SessionAuth | undefined, timeoutMs: number): ClientSessionOptions;
30
+ export declare function lookupManagedInstance(slug: string, options: ConnectionOptions, openAdmin?: typeof withAdminClientSession, connect?: typeof connectAdminInstances): Promise<InstanceInfo>;
31
+ export {};
@@ -0,0 +1,38 @@
1
+ import type { IssuerId } from '@astrale-os/sdk/auth';
2
+ import type { InstanceInfo } from '../lib/admin-instance';
3
+ import type { AdminTargetCommandOpts } from '../lib/admin-target';
4
+ import type { AstraleConfig } from '../lib/config';
5
+ import type { InstanceStore } from '../lib/instance';
6
+ export interface ConnectionOptions {
7
+ readonly url?: string;
8
+ readonly instance?: string;
9
+ readonly timeout?: string;
10
+ readonly as?: string;
11
+ readonly creds?: string;
12
+ readonly anonymous?: boolean;
13
+ readonly ci?: boolean;
14
+ }
15
+ export interface AdminConnectionOptions extends ConnectionOptions {
16
+ readonly admin?: string;
17
+ readonly adminUrl?: string;
18
+ readonly domainIssuer?: string;
19
+ }
20
+ export interface ConnectionTarget {
21
+ readonly url: string;
22
+ readonly kernelIssuer: IssuerId;
23
+ readonly domainIssuer?: IssuerId;
24
+ readonly slug?: string;
25
+ readonly defaultIdentity?: string;
26
+ readonly caFile?: string;
27
+ }
28
+ export interface TargetDependencies {
29
+ readonly instances?: InstanceStore;
30
+ readonly managed?: (slug: string) => Promise<InstanceInfo>;
31
+ }
32
+ /** Stable local identity-registration key for the exact selected source Kernel. */
33
+ export declare function registrationKeyForTarget(target: ConnectionTarget): string;
34
+ /** Resolve the existing URL / instance / active precedence into one exact source Kernel. */
35
+ export declare function resolveConnectionTarget(options: ConnectionOptions, config: AstraleConfig, dependencies?: TargetDependencies): Promise<ConnectionTarget>;
36
+ /** Resolve the configured Admin Domain target without entering managed-instance discovery. */
37
+ export declare function resolveAdminConnectionTarget(options: AdminConnectionOptions, config: AstraleConfig, instances?: InstanceStore): Promise<ConnectionTarget>;
38
+ export declare function adminLookupOptions(options: AdminConnectionOptions): AdminTargetCommandOpts;
@@ -0,0 +1,17 @@
1
+ import type { AdminConnectionOptions, ConnectionContext } from '../connection';
2
+ export { AdminInstanceNotFoundError, findOwnedInstance, formatInstanceState, type InstanceInfo, type InstanceState, type OwnedInstanceInfo, } from '../admin/instance';
3
+ /** Resolve the Admin target and read only the caller-visible Instance inventory. */
4
+ export declare function listOwnedInstances(options: AdminConnectionOptions): Promise<import("./admin-instance").OwnedInstanceInfo[]>;
5
+ /** Read caller-visible inventory together with the exact local identity used for the Admin call. */
6
+ export declare function listOwnedInstancesWithIdentity(options: AdminConnectionOptions): Promise<Readonly<{
7
+ instances: import("./admin-instance").OwnedInstanceInfo[];
8
+ identity?: string | undefined;
9
+ }>>;
10
+ /** Reuse an already-open Admin session for a caller-visible Instance inventory. */
11
+ export declare function listOwnedInstancesInContext(context: ConnectionContext): Promise<import("./admin-instance").OwnedInstanceInfo[]>;
12
+ /** Request one managed Instance; Admin owns infrastructure placement. */
13
+ export declare function createOwnedInstance(options: AdminConnectionOptions, slug: string): Promise<import("./admin-instance").InstanceInfo>;
14
+ /** Refresh one exact caller-visible Instance through its V2 receiver Method. */
15
+ export declare function statusOwnedInstance(options: AdminConnectionOptions, identifier: string): Promise<import("./admin-instance").InstanceInfo>;
16
+ /** Delete one exact caller-visible Instance through its V2 receiver Method. */
17
+ export declare function deleteOwnedInstance(options: AdminConnectionOptions, identifier: string): Promise<import("./admin-instance").InstanceInfo>;
@@ -0,0 +1 @@
1
+ export declare function printFailureDebug(error: unknown, url: string): void;
@@ -172,7 +172,13 @@ export declare function upsertInstance(key: string, opts?: AddInstanceOpts): Pro
172
172
  * normalized kernel URL). Reports the previous URL when an existing
173
173
  * bookmark was repointed to a different kernel so callers can warn.
174
174
  */
175
- export declare function upsertManagedBookmark(key: string, slug: string, rawUrl: string, organizationId?: string): Promise<{
175
+ export declare function upsertManagedBookmark(input: Readonly<{
176
+ key: string;
177
+ slug: string;
178
+ url: string;
179
+ organizationId?: string;
180
+ defaultIdentity?: string;
181
+ }>): Promise<{
176
182
  entry: InstanceEntry;
177
183
  repointedFrom?: string;
178
184
  }>;
@@ -10,7 +10,9 @@ export declare const log: {
10
10
  };
11
11
  /** Report an error with hint (when present) and exit. `--json` / `--ci` / a
12
12
  * non-TTY stdout always get one structured JSON line on stderr. */
13
- export declare function fatal(e: unknown, opts?: MachineOpts): never;
13
+ export declare function fatal(e: unknown, opts?: MachineOpts & {
14
+ readonly debug?: boolean;
15
+ }): never;
14
16
  /** Project only a caller-authored admission failure into the CLI input family. */
15
17
  export declare function failInput(error: unknown, opts?: MachineOpts): never;
16
18
  /** Shortcut for stub commands that aren't wired in v1 (§15). */
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Lexical `@self` helpers. Effective-principal resolution is deliberately not
3
+ * local: connection/self.ts asks the authenticated target Kernel through
4
+ * Identity.whoami before replacing any reference.
5
+ */
6
+ /** Cheap pre-check before invoking authenticated principal resolution. */
7
+ export declare function containsSelfRef(input: string): boolean;
8
+ /** Replace every admitted `@self` token with one authenticated NodeId. */
9
+ export declare function expandSelfReferences(input: string, selfId: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/cli",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.9",
4
4
  "description": "Astrale CLI — connect to existing Astrale kernels",
5
5
  "keywords": [
6
6
  "astrale",
@@ -1,50 +1,9 @@
1
- import type { Node } from '@astrale-os/sdk/graph/node'
2
- import type { QueryAST } from '@astrale-os/sdk/query'
1
+ import { describe, expect, test } from 'bun:test'
3
2
 
4
- import { NodeId } from '@astrale-os/sdk/graph/node'
5
- import { Path } from '@astrale-os/sdk/graph/path'
6
- import { describe, expect, mock, test } from 'bun:test'
7
-
8
- import type { AdminGraphApi } from '../../graph'
9
-
10
- import { AdminTestDomain, adminBinding, adminSession } from '../../__tests__/fixture'
3
+ import { adminBinding, adminSession } from '../../__tests__/fixture'
11
4
  import { connectAdminInstances } from '../client'
12
5
 
13
- function hostNode(id: string, props: { readonly id: string; readonly state: string }): Node {
14
- return {
15
- id: NodeId(id),
16
- class: AdminTestDomain.classes.Host.key,
17
- props: AdminTestDomain.classes.Host.properties.from(props),
18
- }
19
- }
20
-
21
- function instanceNode(id: string): Node {
22
- return {
23
- id: NodeId(id),
24
- class: AdminTestDomain.classes.Instance.key,
25
- props: AdminTestDomain.classes.Instance.properties.from({}),
26
- }
27
- }
28
-
29
- function graphResult(nodes: readonly Node[], cursor?: string) {
30
- return {
31
- result: {
32
- kind: 'nodes' as const,
33
- nodes: nodes.map((value) => ({ kind: 'value' as const, value })),
34
- },
35
- page: cursor === undefined ? {} : { next: cursor },
36
- }
37
- }
38
-
39
- function sourceName(ast: QueryAST): string | undefined {
40
- const term = ast.source.terms[0]
41
- return term?.kind === 'class' ? term.class.name : undefined
42
- }
43
-
44
6
  function fixture(input: {
45
- instances?: readonly Node[]
46
- hosts?: readonly Node[]
47
- reserved?: Node | null
48
7
  invoke?: (method: { owner: string; name: string }, receiver: unknown, input: unknown) => unknown
49
8
  }) {
50
9
  const calls: Array<{
@@ -57,26 +16,13 @@ function fixture(input: {
57
16
  return input.invoke?.(method, receiver, value)
58
17
  })
59
18
  const binding = adminBinding()
60
- const query = mock(async (ast: QueryAST) => {
61
- const name = sourceName(ast)
62
- if (name === 'Instance') return graphResult(input.instances ?? [])
63
- if (name === 'Host') return graphResult(input.hosts ?? [])
64
- throw new Error(`Unexpected graph query ${String(name)}`)
65
- })
66
- const neighbors = mock(async (source: unknown, edge: { name?: string }) => {
67
- if (String(source) === '/:admin.astrale.ai:core.fleet') return page(input.reserved ?? null)
68
- if (edge.name === 'instance_runs_on_host') return page(input.hosts?.[0] ?? null)
69
- throw new Error(`Unexpected neighbor query ${String(source)} ${String(edge)}`)
70
- })
71
- const graph = { query, neighbors } as unknown as AdminGraphApi
72
19
  return {
73
20
  binding,
74
- graph,
75
21
  invoke: remote.invoke,
76
22
  calls,
77
23
  connect: () =>
78
24
  connectAdminInstances(
79
- { session: remote.session, graph },
25
+ { session: remote.session },
80
26
  {
81
27
  bind: async () => binding,
82
28
  operationId: (kind) => `cli.instance.${kind}:test`,
@@ -85,15 +31,6 @@ function fixture(input: {
85
31
  }
86
32
  }
87
33
 
88
- function page(item: Node | null) {
89
- return {
90
- nodes: item === null ? [] : [item],
91
- first: item,
92
- graph: { nodes: item === null ? [] : [item], edges: [] },
93
- cursor: null,
94
- }
95
- }
96
-
97
34
  describe('V2 Admin Instance adapter', () => {
98
35
  test('lists caller-visible Instances through the Admin-owned Fleet operation', async () => {
99
36
  const contract = fixture({
@@ -107,8 +44,6 @@ describe('V2 Admin Instance adapter', () => {
107
44
  state: 'ready',
108
45
  createdAt: '2026-08-12T00:00:00.000Z',
109
46
  updatedAt: '2026-08-12T00:00:00.000Z',
110
- hostId: '@host-node',
111
- region: 'fr-par',
112
47
  },
113
48
  ]
114
49
  : undefined,
@@ -121,8 +56,6 @@ describe('V2 Admin Instance adapter', () => {
121
56
  url: 'https://demo.eu.astrale.ai',
122
57
  state: 'ready',
123
58
  createdAt: '2026-08-12T00:00:00.000Z',
124
- hostId: '@host-node',
125
- region: 'fr-par',
126
59
  },
127
60
  ])
128
61
  expect(contract.calls).toEqual([
@@ -143,10 +76,7 @@ describe('V2 Admin Instance adapter', () => {
143
76
  createdAt: '2026-08-12T00:00:00.000Z',
144
77
  updatedAt: '2026-08-12T00:00:00.000Z',
145
78
  }
146
- const contract = fixture({
147
- hosts: [hostNode('host-node', { id: 'host-paris', state: 'ready' })],
148
- invoke: () => created,
149
- })
79
+ const contract = fixture({ invoke: () => created })
150
80
 
151
81
  await expect((await contract.connect()).create('demo')).resolves.toMatchObject({
152
82
  id: created.id,
@@ -162,38 +92,10 @@ describe('V2 Admin Instance adapter', () => {
162
92
  value: { operationId: 'cli.instance.create:test', slug: 'demo' },
163
93
  },
164
94
  ])
165
- expect(contract.graph.query).not.toHaveBeenCalled()
166
- expect(contract.graph.neighbors).not.toHaveBeenCalled()
167
- })
168
-
169
- test('resolves --host-id to an exact Host receiver and rejects the reserved Admin Host', async () => {
170
- const reserved = hostNode('admin-host', { id: 'admin', state: 'ready' })
171
- const consumer = hostNode('consumer-host', { id: 'consumer-paris', state: 'ready' })
172
- const contract = fixture({
173
- hosts: [reserved, consumer],
174
- reserved,
175
- invoke: () => ({
176
- id: '@instance-node',
177
- slug: 'demo',
178
- url: 'https://demo.eu.astrale.ai',
179
- state: 'ready',
180
- }),
181
- })
182
- const api = await contract.connect()
183
-
184
- await expect(api.create('demo', 'admin')).rejects.toMatchObject({ code: 'HOST_NOT_FOUND' })
185
- await expect(api.create('demo', 'consumer-paris')).resolves.toMatchObject({ slug: 'demo' })
186
- expect(contract.calls.at(-1)).toEqual({
187
- method: { owner: 'Host', name: 'createInstance' },
188
- receiver: '@consumer-host::createInstance',
189
- value: { operationId: 'cli.instance.create:test', slug: 'demo' },
190
- })
191
95
  })
192
96
 
193
97
  test('refreshes and deletes through the resolved Instance receiver', async () => {
194
- const instance = instanceNode('instance-node')
195
98
  const contract = fixture({
196
- instances: [instance],
197
99
  invoke: (method) =>
198
100
  method.name === 'listInstances'
199
101
  ? [
@@ -226,9 +128,7 @@ describe('V2 Admin Instance adapter', () => {
226
128
  })
227
129
 
228
130
  test('installs a resolved catalog Domain through Instance.installDomain', async () => {
229
- const instance = instanceNode('instance-node')
230
131
  const contract = fixture({
231
- instances: [instance],
232
132
  invoke: (method) =>
233
133
  method.name === 'listInstances'
234
134
  ? [