@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 +15 -0
- package/dist/tooling/cli/arguments.d.ts +3 -1
- package/dist/tooling/cli/arguments.js +1 -0
- package/dist/tooling/cli/help.d.ts +8 -0
- package/dist/tooling/cli/help.js +117 -0
- package/dist/tooling/cli/orchestrate.js +5 -3
- package/dist/tooling/linter/adapters/typescript/discover.js +14 -2
- package/dist/tooling/linter/implementations/source/global.js +12 -4
- package/dist/tooling/linter/implementations/source/tests.js +7 -3
- package/package.json +1 -1
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:
|
|
5
|
+
readonly command: Command;
|
|
4
6
|
readonly env: string;
|
|
5
7
|
readonly fix?: boolean;
|
|
6
8
|
readonly format?: LintReportFormat;
|
|
@@ -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
|
-
|
|
14
|
-
|
|
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(
|
|
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
|
|
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
|
-
...(
|
|
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
|
|
339
|
-
|
|
340
|
-
|
|
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}
|
|
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
|
|
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 &&
|