@astrale-os/sdk 0.5.0-beta.71 → 0.5.0-beta.73

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0-beta.73](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.72...sdk-v0.5.0-beta.73) (2026-08-28)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **adapter-astrale:** discover official CLI installation ([#320](https://github.com/astrale-os/sdk/issues/320)) ([aa5ade5](https://github.com/astrale-os/sdk/commit/aa5ade5e7d861b2b3e037ae84ca14a36fef48fb2))
9
+ * add command-specific astrale-domain help ([#318](https://github.com/astrale-os/sdk/issues/318)) ([4956a77](https://github.com/astrale-os/sdk/commit/4956a77337c70659fa45102bed84e4feab39aad1))
10
+
11
+ ## [0.5.0-beta.72](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.71...sdk-v0.5.0-beta.72) (2026-08-28)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **linter:** recognize nested schema modules ([#316](https://github.com/astrale-os/sdk/issues/316)) ([d9ad841](https://github.com/astrale-os/sdk/commit/d9ad84165103ed7741f11801ea740476109b99b3))
17
+
3
18
  ## [0.5.0-beta.71](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.70...sdk-v0.5.0-beta.71) (2026-08-28)
4
19
 
5
20
 
@@ -1,6 +1,8 @@
1
1
  import type { LintReportFormat } from '../linter/index.js';
2
+ export declare const COMMANDS: readonly ['dev', 'build', 'deploy', 'lint', 'package'];
3
+ export type Command = (typeof COMMANDS)[number];
2
4
  export interface ParsedArgs {
3
- readonly command: 'dev' | 'build' | 'deploy' | 'lint' | 'package';
5
+ readonly command: Command;
4
6
  readonly env: string;
5
7
  readonly fix?: boolean;
6
8
  readonly format?: LintReportFormat;
@@ -1,4 +1,5 @@
1
1
  import { isIP } from 'node:net';
2
+ export const COMMANDS = ['dev', 'build', 'deploy', 'lint', 'package'];
2
3
  /** Parse the frozen `astrale-domain` command grammar without performing effects. */
3
4
  export function parseArgs(argv) {
4
5
  const [command, ...rest] = argv;
@@ -0,0 +1,8 @@
1
+ import { type Command } from './arguments.js';
2
+ export interface HelpRequest {
3
+ readonly command?: Command;
4
+ }
5
+ /** Resolve help without parsing a project or performing any command effects. */
6
+ export declare function helpRequest(argv: readonly string[]): HelpRequest | undefined;
7
+ export declare function helpText(command?: Command): string;
8
+ export declare const ERROR_USAGE = "Usage: astrale-domain <command> [options]\nRun \"astrale-domain --help\" for available commands.\n";
@@ -0,0 +1,117 @@
1
+ import { COMMANDS } from './arguments.js';
2
+ /** Resolve help without parsing a project or performing any command effects. */
3
+ export function helpRequest(argv) {
4
+ if (!argv.some((argument) => argument === '--help' || argument === '-h'))
5
+ return undefined;
6
+ const command = COMMANDS.find((candidate) => candidate === argv[0]);
7
+ return command === undefined ? Object.freeze({}) : Object.freeze({ command });
8
+ }
9
+ export function helpText(command) {
10
+ return command === undefined ? GLOBAL_HELP : COMMAND_HELP[command];
11
+ }
12
+ export const ERROR_USAGE = `Usage: astrale-domain <command> [options]
13
+ Run "astrale-domain --help" for available commands.
14
+ `;
15
+ const GLOBAL_HELP = `Build, develop, deploy, lint, and package Astrale Domains.
16
+
17
+ Usage:
18
+ astrale-domain <command> [options]
19
+
20
+ Commands:
21
+ dev [environment] Build and run a watched development session.
22
+ build Build and verify without deploying.
23
+ deploy <environment> Deploy through the configured adapter.
24
+ lint Check Domain source and architecture.
25
+ package Prepare public declarations for publication.
26
+
27
+ Options:
28
+ -h, --help Show help.
29
+
30
+ Run "astrale-domain <command> --help" for command-specific help.
31
+ `;
32
+ const COMMAND_HELP = Object.freeze({
33
+ dev: `Build, verify, and run a watched Domain development session.
34
+
35
+ Usage:
36
+ astrale-domain dev [environment] [options]
37
+
38
+ Arguments:
39
+ environment Adapter environment key (default: dev).
40
+
41
+ Options:
42
+ --environment <name> Select the environment without a positional argument.
43
+ --port <port> Use a strict local Worker port (default: OS-allocated).
44
+ --host <url> Use an externally managed public origin; requires a strict port
45
+ from --port or adapter configuration.
46
+ -h, --help Show help for dev.
47
+
48
+ Behavior:
49
+ Builds and verifies the Application, Runtime, and adapter-prepared artifact.
50
+ Serves the generated Worker and an optional Vite frontend. Vite uses its own
51
+ OS-allocated loopback port.
52
+ Watches imported authored sources and declared secrets. Configuration changes
53
+ require restarting the command.
54
+
55
+ Adapters:
56
+ cloudflare Runs the local Worker and optional Vite frontend only;
57
+ it owns no public ingress or Kernel installation.
58
+ astrale Also owns a Quick Tunnel when no public host is configured,
59
+ reconciles each verified Release on the configured or
60
+ CLI-active instance, and starts a local View host when
61
+ a View is declared. The installation remains after the
62
+ development session stops.
63
+ `,
64
+ build: `Build and verify a Domain without deploying it.
65
+
66
+ Usage:
67
+ astrale-domain build
68
+
69
+ Options:
70
+ -h, --help Show help for build.
71
+
72
+ Behavior:
73
+ Compiles the Application and Runtime, runs adapter preparation, and verifies
74
+ the resulting artifact. It does not load declared secrets, deploy, or install
75
+ the Domain.
76
+ `,
77
+ deploy: `Build, verify, and deploy a Domain through its configured adapter.
78
+
79
+ Usage:
80
+ astrale-domain deploy <environment>
81
+ astrale-domain deploy --environment <name>
82
+
83
+ Arguments:
84
+ environment Required adapter environment key.
85
+
86
+ Options:
87
+ --environment <name> Select the environment without a positional argument.
88
+ -h, --help Show help for deploy.
89
+
90
+ Behavior:
91
+ Builds and verifies the Release, loads declared secrets, and invokes the
92
+ adapter deployment. Deployment does not install the deployed Domain on a
93
+ Kernel instance.
94
+ `,
95
+ lint: `Check Domain source and architecture.
96
+
97
+ Usage:
98
+ astrale-domain lint [options]
99
+
100
+ Options:
101
+ --fix Apply supported fixes.
102
+ --format <format> Select stylish or json output (default: stylish).
103
+ -h, --help Show help for lint.
104
+ `,
105
+ package: `Prepare public TypeScript declarations for package publication.
106
+
107
+ Usage:
108
+ astrale-domain package
109
+
110
+ Options:
111
+ -h, --help Show help for package.
112
+
113
+ Behavior:
114
+ Normalizes public declaration references in the current package. This command
115
+ does not load astrale.config.ts and does not require Bun.
116
+ `,
117
+ });
@@ -7,11 +7,13 @@ import { parseArgs } from './arguments.js';
7
7
  import { BunRequiredError } from './bun.js';
8
8
  import { develop } from './development/develop.js';
9
9
  import { loadDeclaredSecrets } from './dotenv.js';
10
+ import { ERROR_USAGE, helpRequest, helpText } from './help.js';
10
11
  import { error, info } from './log.js';
11
12
  const CONFIG_NAMES = ['astrale.config.ts', 'astrale.config.js', 'astrale.config.mjs'];
12
13
  export async function run(argv) {
13
- if (argv.includes('--help') || argv.includes('-h')) {
14
- usage();
14
+ const requestedHelp = helpRequest(argv);
15
+ if (requestedHelp !== undefined) {
16
+ process.stdout.write(helpText(requestedHelp.command));
15
17
  return 0;
16
18
  }
17
19
  let parsed;
@@ -153,5 +155,5 @@ function deploymentLifecycle() {
153
155
  function usage(message) {
154
156
  if (message !== undefined)
155
157
  error(message);
156
- process.stderr.write('Usage: astrale-domain <dev|build|deploy|lint|package> [environment]\n');
158
+ process.stderr.write(ERROR_USAGE);
157
159
  }
@@ -206,7 +206,7 @@ async function admitFile(root, absolutePath, policy) {
206
206
  const source = ts.createSourceFile(absolutePath, text, ts.ScriptTarget.Latest, true, scriptKind(absolutePath));
207
207
  const layer = policy.layers.find(({ sourcePath }) => path.startsWith(sourcePath));
208
208
  const remainder = layer ? path.slice(layer.sourcePath.length) : undefined;
209
- const first = remainder?.split('/')[0];
209
+ const submodule = semanticSubmodule(layer?.id, remainder);
210
210
  const role = sourceRole(path, layer?.id);
211
211
  return Object.freeze({
212
212
  absolutePath,
@@ -215,11 +215,23 @@ async function admitFile(root, absolutePath, policy) {
215
215
  source,
216
216
  role,
217
217
  ...(layer ? { layer: layer.id } : {}),
218
- ...(first && remainder?.includes('/') && first !== '__tests__' ? { submodule: first } : {}),
218
+ ...(submodule ? { submodule } : {}),
219
219
  imports: Object.freeze(collectImports(source)),
220
220
  dependencyIssues: Object.freeze(collectDependencyIssues(source)),
221
221
  });
222
222
  }
223
+ function semanticSubmodule(layer, remainder) {
224
+ if (!remainder)
225
+ return undefined;
226
+ const segments = remainder.split('/');
227
+ const first = segments[0];
228
+ if (!first || first === '__tests__' || segments.length < 2)
229
+ return undefined;
230
+ if (layer === 'schema' && first === 'modules' && segments.length >= 3 && segments[1]) {
231
+ return `modules/${segments[1]}`;
232
+ }
233
+ return first;
234
+ }
223
235
  function sourceRole(path, layer) {
224
236
  const segments = path.split('/');
225
237
  if (segments.includes('__tests__') || /\.(?:test|spec|bench|perf)\.[cm]?[jt]sx?$/.test(path)) {
@@ -335,16 +335,24 @@ export const globalRules = [
335
335
  const evidence = [];
336
336
  for (const file of production(project)) {
337
337
  for (const sourceImport of file.imports) {
338
- const localDeepImport = sourceImport.specifier.match(/^#([^/]+)\/[^/]+\/.+/);
339
- if (localDeepImport &&
340
- project.policy.layers.some(({ id }) => id === localDeepImport[1])) {
338
+ const target = resolveProjectImport(project, file, sourceImport.specifier);
339
+ const localAliasSegments = sourceImport.specifier.startsWith('#')
340
+ ? sourceImport.specifier.split('/')
341
+ : [];
342
+ const aliasLayer = localAliasSegments[0]?.slice(1);
343
+ const nestedSchemaModuleFacade = aliasLayer === 'schema' &&
344
+ localAliasSegments[1] === 'modules' &&
345
+ localAliasSegments.length === 3;
346
+ if (!target &&
347
+ localAliasSegments.length >= 3 &&
348
+ !nestedSchemaModuleFacade &&
349
+ project.policy.layers.some(({ id }) => id === aliasLayer)) {
341
350
  evidence.push(violation(file, sourceImport.node, `Import ${sourceImport.specifier} reaches private source; use the semantic submodule facade.`));
342
351
  }
343
352
  if (isForeignDomain(sourceImport.specifier) &&
344
353
  isDeepPackageImport(sourceImport.specifier)) {
345
354
  evidence.push(violation(file, sourceImport.node, `Foreign Domain import ${sourceImport.specifier} bypasses ${packageRoot(sourceImport.specifier)}.`));
346
355
  }
347
- const target = resolveProjectImport(project, file, sourceImport.specifier);
348
356
  if (!file.layer ||
349
357
  !target?.layer ||
350
358
  file.layer !== target.layer ||
@@ -10,12 +10,16 @@ export const testRules = [
10
10
  if (file.layer && file.layer !== 'tests' && file.submodule) {
11
11
  const sourcePath = project.policy.layers.find(({ id }) => id === file.layer)?.sourcePath;
12
12
  if (sourcePath !== undefined) {
13
- owners.set(`${file.layer}/${file.submodule}`, { file, sourcePath });
13
+ owners.set(`${file.layer}\0${file.submodule}`, {
14
+ file,
15
+ layer: file.layer,
16
+ sourcePath,
17
+ submodule: file.submodule,
18
+ });
14
19
  }
15
20
  }
16
21
  }
17
- for (const [owner, { file, sourcePath }] of owners) {
18
- const [layer, submodule] = owner.split('/');
22
+ for (const { file, layer, sourcePath, submodule } of owners.values()) {
19
23
  const physicalOwner = `${sourcePath}${submodule}`;
20
24
  const hasFocusedEvidence = project.files.some((candidate) => candidate.layer === layer &&
21
25
  candidate.submodule === submodule &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.71",
3
+ "version": "0.5.0-beta.73",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",