@astrale-os/sdk 0.5.0-beta.132 → 0.5.0-beta.134
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/README.md +17 -2
- package/dist/application/mutation/failure.js +11 -5
- package/dist/tooling/cli/arguments.d.ts +3 -1
- package/dist/tooling/cli/arguments.js +21 -1
- package/dist/tooling/cli/help.js +24 -0
- package/dist/tooling/cli/orchestrate.js +9 -0
- package/dist/tooling/cli/upgrade/index.d.ts +6 -0
- package/dist/tooling/cli/upgrade/index.js +115 -0
- package/dist/tooling/cli/upgrade/manifest.d.ts +18 -0
- package/dist/tooling/cli/upgrade/manifest.js +77 -0
- package/dist/tooling/cli/upgrade/process.d.ts +2 -0
- package/dist/tooling/cli/upgrade/process.js +57 -0
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -31,6 +31,21 @@ npx -y create-astrale-domain@beta my-domain --yes
|
|
|
31
31
|
See [the release lifecycle](docs/release.md) for package-set versioning, verification, and stable
|
|
32
32
|
promotion.
|
|
33
33
|
|
|
34
|
+
### Update a pnpm project
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
pnpm exec astrale-domain upgrade --check # Preview; no project changes
|
|
38
|
+
pnpm exec astrale-domain upgrade # Update existing Astrale dependencies to beta
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The command covers the workspace root and its packages, pins exact versions, and updates the
|
|
42
|
+
lockfile through pnpm. Use `--channel latest` to select that tag instead. Missing tags and local,
|
|
43
|
+
catalog, or aliased dependencies are left unchanged and reported; peers and overrides are not edited.
|
|
44
|
+
For an older SDK without this command, start with `pnpm dlx @astrale-os/sdk@beta upgrade`.
|
|
45
|
+
Stop development watchers first, then run the project's checks and validate on development.
|
|
46
|
+
Nothing is committed or deployed. A Shell update also requires checking the installed Shell revision.
|
|
47
|
+
Rerunning an upgrade synchronizes installation even when the manifest versions are already current.
|
|
48
|
+
|
|
34
49
|
## Handler authority and dependencies
|
|
35
50
|
|
|
36
51
|
Authenticated handlers use Domain self authority for `kernel`, `graph`, `query`, and `mutate`.
|
|
@@ -110,10 +125,10 @@ The repository installs autonomously from its versioned npm-only lockfile:
|
|
|
110
125
|
```bash
|
|
111
126
|
git clone https://github.com/astrale-os/sdk.git
|
|
112
127
|
cd sdk
|
|
113
|
-
AGENT_HARNESSES=codex bash scripts/
|
|
128
|
+
AGENT_HARNESSES=codex bash scripts/setup/setup.sh
|
|
114
129
|
```
|
|
115
130
|
|
|
116
|
-
See [agent setup](scripts/
|
|
131
|
+
See [agent setup](scripts/setup/README.md) for Claude Cloud and validation.
|
|
117
132
|
|
|
118
133
|
It can also be consumed as a submodule of the main Astrale workspace:
|
|
119
134
|
|
|
@@ -37,15 +37,21 @@ function mutationCode(input) {
|
|
|
37
37
|
const value = input;
|
|
38
38
|
if (value.code === 'STATE_TRANSITION_ILLEGAL')
|
|
39
39
|
return value.code;
|
|
40
|
-
for (const candidate of [
|
|
40
|
+
for (const candidate of [
|
|
41
|
+
value.code,
|
|
42
|
+
directOrNestedCode(value.reason),
|
|
43
|
+
directOrNestedCode(value.data),
|
|
44
|
+
]) {
|
|
41
45
|
if (typeof candidate === 'string' && candidate.startsWith('MUTATION_')) {
|
|
42
46
|
return candidate;
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
return undefined;
|
|
46
50
|
}
|
|
47
|
-
function
|
|
48
|
-
return
|
|
49
|
-
?
|
|
50
|
-
:
|
|
51
|
+
function directOrNestedCode(input) {
|
|
52
|
+
return typeof input === 'string'
|
|
53
|
+
? input
|
|
54
|
+
: input !== null && typeof input === 'object' && !Array.isArray(input)
|
|
55
|
+
? Reflect.get(input, 'code')
|
|
56
|
+
: undefined;
|
|
51
57
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LintReportFormat } from '../linter/index.js';
|
|
2
|
-
export declare const COMMANDS: readonly ['dev', 'build', 'deploy', 'test', 'lint', 'package'];
|
|
2
|
+
export declare const COMMANDS: readonly ['dev', 'build', 'deploy', 'test', 'lint', 'package', 'upgrade'];
|
|
3
3
|
export type Command = (typeof COMMANDS)[number];
|
|
4
4
|
export interface ParsedArgs {
|
|
5
5
|
readonly command: Command;
|
|
@@ -12,6 +12,8 @@ export interface ParsedArgs {
|
|
|
12
12
|
readonly suite?: string;
|
|
13
13
|
readonly sessionFile?: string;
|
|
14
14
|
readonly secretsFile?: string;
|
|
15
|
+
readonly channel?: string;
|
|
16
|
+
readonly check?: boolean;
|
|
15
17
|
}
|
|
16
18
|
/** Parse the frozen `astrale-domain` command grammar without performing effects. */
|
|
17
19
|
export declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { isAbsolute, normalize } from 'node:path';
|
|
2
|
-
export const COMMANDS = ['dev', 'build', 'deploy', 'test', 'lint', 'package'];
|
|
2
|
+
export const COMMANDS = ['dev', 'build', 'deploy', 'test', 'lint', 'package', 'upgrade'];
|
|
3
3
|
/** Parse the frozen `astrale-domain` command grammar without performing effects. */
|
|
4
4
|
export function parseArgs(argv) {
|
|
5
5
|
const [command, ...rest] = argv;
|
|
6
|
+
if (command === 'upgrade')
|
|
7
|
+
return parseUpgrade(rest);
|
|
6
8
|
const fix = rest.includes('--fix');
|
|
7
9
|
const deployOnly = rest.includes('--deploy-only');
|
|
8
10
|
let sessionFile;
|
|
@@ -142,6 +144,24 @@ export function parseArgs(argv) {
|
|
|
142
144
|
throw new Error(command ? `Unknown command "${command}".` : 'Missing command.');
|
|
143
145
|
}
|
|
144
146
|
}
|
|
147
|
+
function parseUpgrade(args) {
|
|
148
|
+
let channel = 'beta';
|
|
149
|
+
let check = false;
|
|
150
|
+
for (let index = 0; index < args.length; index++) {
|
|
151
|
+
const argument = args[index];
|
|
152
|
+
if (argument === '--check')
|
|
153
|
+
check = true;
|
|
154
|
+
else if (argument === '--channel' || argument.startsWith('--channel=')) {
|
|
155
|
+
channel = requiredValue('--channel', argument === '--channel' ? args[++index] : argument.slice(10));
|
|
156
|
+
if (!/^[A-Za-z][A-Za-z0-9._-]*$/u.test(channel)) {
|
|
157
|
+
throw new Error('--channel must be a registry dist-tag, such as beta or latest.');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else
|
|
161
|
+
throw new Error(`Unknown upgrade argument "${argument}".`);
|
|
162
|
+
}
|
|
163
|
+
return { command: 'upgrade', env: '', channel, check };
|
|
164
|
+
}
|
|
145
165
|
function lintFormat(input) {
|
|
146
166
|
if (input !== 'stylish' && input !== 'json') {
|
|
147
167
|
throw new Error(`--format must be "stylish" or "json", got "${input ?? ''}"`);
|
package/dist/tooling/cli/help.js
CHANGED
|
@@ -24,6 +24,7 @@ Commands:
|
|
|
24
24
|
test Run Project tests, optionally against one Environment.
|
|
25
25
|
lint Check Domain source and architecture.
|
|
26
26
|
package Prepare public declarations for publication.
|
|
27
|
+
upgrade Update Astrale dependencies through pnpm (default: beta).
|
|
27
28
|
|
|
28
29
|
Options:
|
|
29
30
|
-h, --help Show help.
|
|
@@ -31,6 +32,29 @@ Options:
|
|
|
31
32
|
Run "astrale-domain <command> --help" for command-specific help.
|
|
32
33
|
`;
|
|
33
34
|
const COMMAND_HELP = Object.freeze({
|
|
35
|
+
upgrade: `Update existing Astrale dependencies in a pnpm project or workspace.
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
astrale-domain upgrade [--channel <tag>] [--check]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--channel <tag> Registry dist-tag to select (default: beta).
|
|
42
|
+
--check Show changes without modifying project files or installing.
|
|
43
|
+
-h, --help Show help for upgrade.
|
|
44
|
+
|
|
45
|
+
Behavior:
|
|
46
|
+
Updates dependencies, devDependencies, and optionalDependencies under @astrale-os/
|
|
47
|
+
and @astrale-domains/, including the workspace root. Writes exact versions and
|
|
48
|
+
runs pnpm install once. The selected tag is authoritative, even if older than
|
|
49
|
+
the current version. Installation is synchronized even when versions are unchanged,
|
|
50
|
+
so retrying can finish a previously failed install. Packages without that tag remain
|
|
51
|
+
unchanged with a warning.
|
|
52
|
+
Local links, catalogs, aliases, peers, and overrides are not rewritten.
|
|
53
|
+
Does not load astrale.config.ts, require Bun, run project checks, commit, or deploy.
|
|
54
|
+
Stop development watchers before upgrading. Review changes and run your project's
|
|
55
|
+
checks afterwards. Failed installations leave local changes available for repair.
|
|
56
|
+
For an older SDK without this command: pnpm dlx @astrale-os/sdk@beta upgrade.
|
|
57
|
+
`,
|
|
34
58
|
dev: `Build, verify, remotely deploy, and watch one Project Environment.
|
|
35
59
|
|
|
36
60
|
Usage:
|
|
@@ -29,6 +29,15 @@ export async function run(argv) {
|
|
|
29
29
|
}
|
|
30
30
|
if (parsed.command === 'lint')
|
|
31
31
|
return lint(parsed);
|
|
32
|
+
if (parsed.command === 'upgrade') {
|
|
33
|
+
const { upgrade } = await import('./upgrade/index.js');
|
|
34
|
+
await upgrade({
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
channel: parsed.channel ?? 'beta',
|
|
37
|
+
check: parsed.check ?? false,
|
|
38
|
+
});
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
32
41
|
if (parsed.command === 'package') {
|
|
33
42
|
const result = await packageDomain({ projectDir: process.cwd() });
|
|
34
43
|
info(`Packaged ${result.declarations} public declarations (${result.replacements} references normalized).`);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile, realpath, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { isAbsolute, join, relative } from 'node:path';
|
|
4
|
+
import { failureMessage } from '../failure.js';
|
|
5
|
+
import { projectRoot, readManifest, record, registryDependency, updatedManifest, } from './manifest.js';
|
|
6
|
+
import { runPnpm } from './process.js';
|
|
7
|
+
export async function upgrade(options) {
|
|
8
|
+
const root = await realpath(projectRoot(options.cwd));
|
|
9
|
+
const rootManifest = await readManifest(root);
|
|
10
|
+
const rootValue = JSON.parse(rootManifest.source);
|
|
11
|
+
const manager = record(rootValue) ? rootValue.packageManager : undefined;
|
|
12
|
+
if (manager !== undefined
|
|
13
|
+
? typeof manager !== 'string' || !manager.startsWith('pnpm@')
|
|
14
|
+
: !existsSync(join(root, 'pnpm-workspace.yaml')) && !existsSync(join(root, 'pnpm-lock.yaml'))) {
|
|
15
|
+
throw new Error('Upgrade currently supports pnpm projects only. Declare packageManager: "pnpm@<version>" in package.json.');
|
|
16
|
+
}
|
|
17
|
+
const directories = new Set([root]);
|
|
18
|
+
if (existsSync(join(root, 'pnpm-workspace.yaml'))) {
|
|
19
|
+
const inventory = JSON.parse(await runPnpm(root, [
|
|
20
|
+
'--recursive',
|
|
21
|
+
'--include-workspace-root',
|
|
22
|
+
'list',
|
|
23
|
+
'--depth',
|
|
24
|
+
'-1',
|
|
25
|
+
'--json',
|
|
26
|
+
]));
|
|
27
|
+
if (!Array.isArray(inventory))
|
|
28
|
+
throw new Error('Invalid pnpm workspace inventory.');
|
|
29
|
+
for (const entry of inventory) {
|
|
30
|
+
if (!record(entry) || typeof entry.path !== 'string' || !isAbsolute(entry.path))
|
|
31
|
+
throw new Error('Invalid pnpm workspace path.');
|
|
32
|
+
const directory = await realpath(entry.path);
|
|
33
|
+
const offset = relative(root, directory);
|
|
34
|
+
if (offset === '..' ||
|
|
35
|
+
offset.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
|
|
36
|
+
isAbsolute(offset)) {
|
|
37
|
+
throw new Error(`Workspace package is outside ${root}: ${entry.path}.`);
|
|
38
|
+
}
|
|
39
|
+
directories.add(directory);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const manifests = await Promise.all([...directories].sort().map(readManifest));
|
|
43
|
+
const names = new Set();
|
|
44
|
+
const skipped = new Set();
|
|
45
|
+
for (const manifest of manifests) {
|
|
46
|
+
for (const dependency of manifest.dependencies) {
|
|
47
|
+
if (registryDependency(dependency.value))
|
|
48
|
+
names.add(dependency.name);
|
|
49
|
+
else
|
|
50
|
+
skipped.add(`${dependency.name}: ${dependency.value} (left unchanged)`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const versions = new Map();
|
|
54
|
+
const queue = [...names].sort();
|
|
55
|
+
// Resolve the complete plan before writing. Each package's tag is observed once.
|
|
56
|
+
for (let offset = 0; offset < queue.length; offset += 4) {
|
|
57
|
+
await Promise.all(queue.slice(offset, offset + 4).map(async (name) => {
|
|
58
|
+
const tags = JSON.parse(await runPnpm(root, ['view', name, 'dist-tags', '--json']));
|
|
59
|
+
if (!record(tags))
|
|
60
|
+
throw new Error(`Invalid registry dist-tags for ${name}.`);
|
|
61
|
+
const version = tags[options.channel];
|
|
62
|
+
if (version === undefined)
|
|
63
|
+
skipped.add(`${name}: no ${options.channel} tag (left unchanged)`);
|
|
64
|
+
else if (typeof version !== 'string' ||
|
|
65
|
+
!/^\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/u.test(version)) {
|
|
66
|
+
throw new Error(`Invalid ${options.channel} version for ${name}.`);
|
|
67
|
+
}
|
|
68
|
+
else
|
|
69
|
+
versions.set(name, version);
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
process.stdout.write(`Astrale upgrade · ${options.channel}\nWorkspace: ${root}\n`);
|
|
73
|
+
for (const warning of [...skipped].sort())
|
|
74
|
+
process.stdout.write(`Skipped: ${warning}\n`);
|
|
75
|
+
const changes = manifests
|
|
76
|
+
.map((manifest) => ({ manifest, source: updatedManifest(manifest, versions) }))
|
|
77
|
+
.filter(({ manifest, source }) => manifest.source !== source);
|
|
78
|
+
for (const { manifest } of changes) {
|
|
79
|
+
for (const dependency of manifest.dependencies) {
|
|
80
|
+
const next = registryDependency(dependency.value) ? versions.get(dependency.name) : undefined;
|
|
81
|
+
if (next !== undefined && next !== dependency.value)
|
|
82
|
+
process.stdout.write(`${relative(root, manifest.path)} · ${dependency.name}: ${dependency.value} → ${next}\n`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (changes.length === 0) {
|
|
86
|
+
process.stdout.write('No dependency changes.\n');
|
|
87
|
+
}
|
|
88
|
+
if (options.check) {
|
|
89
|
+
process.stdout.write('Check only: no project files changed; nothing installed.\n');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (versions.size === 0) {
|
|
93
|
+
process.stdout.write('No matching registry versions; nothing installed.\n');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
for (const { manifest } of changes) {
|
|
97
|
+
if ((await readFile(manifest.path, 'utf8')) !== manifest.source)
|
|
98
|
+
throw new Error(`Manifest changed during upgrade: ${manifest.path}. Retry against the current files.`);
|
|
99
|
+
}
|
|
100
|
+
for (const { manifest, source } of changes)
|
|
101
|
+
await writeFile(manifest.path, source);
|
|
102
|
+
try {
|
|
103
|
+
await runPnpm(root, ['install', '--no-frozen-lockfile'], true);
|
|
104
|
+
}
|
|
105
|
+
catch (cause) {
|
|
106
|
+
throw new Error(`${failureMessage(cause)}\nDependency installation failed. Local changes remain; repair and run pnpm install. Nothing committed or deployed.`, { cause });
|
|
107
|
+
}
|
|
108
|
+
process.stdout.write("Dependencies installed. Run your project's typecheck, lint, tests, and build before deploying. Nothing committed or deployed.\n");
|
|
109
|
+
if (changes.some(({ manifest }) => manifest.dependencies.some(({ name, value }) => name === '@astrale-domains/shell' &&
|
|
110
|
+
registryDependency(value) &&
|
|
111
|
+
versions.has(name) &&
|
|
112
|
+
versions.get(name) !== value))) {
|
|
113
|
+
process.stdout.write('Shell changed: verify the installed Shell revision before deploying dependent Domains.\n');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface Dependency {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly value: string;
|
|
4
|
+
readonly start: number;
|
|
5
|
+
readonly end: number;
|
|
6
|
+
}
|
|
7
|
+
export interface Manifest {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly dependencies: readonly Dependency[];
|
|
11
|
+
}
|
|
12
|
+
export declare function record(value: unknown): value is Record<string, unknown>;
|
|
13
|
+
/** Find a declared workspace without escaping an enclosing repository. */
|
|
14
|
+
export declare function projectRoot(cwd: string): string;
|
|
15
|
+
export declare function readManifest(directory: string): Promise<Manifest>;
|
|
16
|
+
export declare function registryDependency(value: string): boolean;
|
|
17
|
+
/** Replace only dependency value tokens; preserve formatting and all unrelated content. */
|
|
18
|
+
export declare function updatedManifest(manifest: Manifest, versions: ReadonlyMap<string, string>): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
const SECTIONS = new Set(['dependencies', 'devDependencies', 'optionalDependencies']);
|
|
6
|
+
export function record(value) {
|
|
7
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
/** Find a declared workspace without escaping an enclosing repository. */
|
|
10
|
+
export function projectRoot(cwd) {
|
|
11
|
+
let directory = resolve(cwd);
|
|
12
|
+
let nearest;
|
|
13
|
+
for (;;) {
|
|
14
|
+
if (existsSync(join(directory, 'pnpm-workspace.yaml')))
|
|
15
|
+
return directory;
|
|
16
|
+
if (nearest === undefined && existsSync(join(directory, 'package.json')))
|
|
17
|
+
nearest = directory;
|
|
18
|
+
if (existsSync(join(directory, '.git')) || dirname(directory) === directory)
|
|
19
|
+
break;
|
|
20
|
+
directory = dirname(directory);
|
|
21
|
+
}
|
|
22
|
+
if (nearest === undefined)
|
|
23
|
+
throw new Error(`No package.json found from ${cwd}.`);
|
|
24
|
+
return nearest;
|
|
25
|
+
}
|
|
26
|
+
export async function readManifest(directory) {
|
|
27
|
+
const path = join(directory, 'package.json');
|
|
28
|
+
const source = await readFile(path, 'utf8');
|
|
29
|
+
const value = JSON.parse(source);
|
|
30
|
+
if (!record(value))
|
|
31
|
+
throw new Error(`Invalid package manifest: ${path}.`);
|
|
32
|
+
const tree = ts.parseJsonText(path, source);
|
|
33
|
+
const statement = tree.statements[0];
|
|
34
|
+
if (!statement ||
|
|
35
|
+
!ts.isExpressionStatement(statement) ||
|
|
36
|
+
!ts.isObjectLiteralExpression(statement.expression)) {
|
|
37
|
+
throw new Error(`Invalid package manifest: ${path}.`);
|
|
38
|
+
}
|
|
39
|
+
const dependencies = [];
|
|
40
|
+
for (const section of statement.expression.properties) {
|
|
41
|
+
if (!ts.isPropertyAssignment(section) || !SECTIONS.has(section.name.getText(tree).slice(1, -1)))
|
|
42
|
+
continue;
|
|
43
|
+
if (!ts.isObjectLiteralExpression(section.initializer))
|
|
44
|
+
throw new Error(`Invalid dependency section in ${path}.`);
|
|
45
|
+
for (const property of section.initializer.properties) {
|
|
46
|
+
if (!ts.isPropertyAssignment(property) || !ts.isStringLiteral(property.name))
|
|
47
|
+
continue;
|
|
48
|
+
const name = property.name.text;
|
|
49
|
+
if (!name.startsWith('@astrale-os/') && !name.startsWith('@astrale-domains/'))
|
|
50
|
+
continue;
|
|
51
|
+
if (!ts.isStringLiteral(property.initializer))
|
|
52
|
+
throw new Error(`Invalid dependency ${name} in ${path}.`);
|
|
53
|
+
dependencies.push({
|
|
54
|
+
name,
|
|
55
|
+
value: property.initializer.text,
|
|
56
|
+
start: property.initializer.getStart(tree),
|
|
57
|
+
end: property.initializer.end,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { path, source, dependencies };
|
|
62
|
+
}
|
|
63
|
+
export function registryDependency(value) {
|
|
64
|
+
return value.length > 0 && !/[:/\\#]/u.test(value) && !value.endsWith('.tgz');
|
|
65
|
+
}
|
|
66
|
+
/** Replace only dependency value tokens; preserve formatting and all unrelated content. */
|
|
67
|
+
export function updatedManifest(manifest, versions) {
|
|
68
|
+
let result = manifest.source;
|
|
69
|
+
for (const dependency of [...manifest.dependencies].reverse()) {
|
|
70
|
+
const version = registryDependency(dependency.value) ? versions.get(dependency.name) : undefined;
|
|
71
|
+
if (version !== undefined && version !== dependency.value) {
|
|
72
|
+
result =
|
|
73
|
+
result.slice(0, dependency.start) + JSON.stringify(version) + result.slice(dependency.end);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import spawn from 'cross-spawn';
|
|
2
|
+
/** pnpm owns registry configuration, installation policy, and lockfile resolution. */
|
|
3
|
+
export function runPnpm(cwd, args, install = false) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const child = spawn('pnpm', [...args], {
|
|
6
|
+
cwd,
|
|
7
|
+
stdio: install ? 'inherit' : ['ignore', 'pipe', 'pipe'],
|
|
8
|
+
shell: false,
|
|
9
|
+
});
|
|
10
|
+
let stdout = '';
|
|
11
|
+
let stderr = '';
|
|
12
|
+
let failure;
|
|
13
|
+
let escalation;
|
|
14
|
+
const stop = (reason) => {
|
|
15
|
+
if (failure)
|
|
16
|
+
return;
|
|
17
|
+
failure = new Error(reason);
|
|
18
|
+
child.kill('SIGTERM');
|
|
19
|
+
escalation = setTimeout(() => child.kill('SIGKILL'), 1_000);
|
|
20
|
+
};
|
|
21
|
+
const interrupt = () => stop('Upgrade interrupted; inspect local changes before retrying.');
|
|
22
|
+
process.once('SIGINT', interrupt);
|
|
23
|
+
process.once('SIGTERM', interrupt);
|
|
24
|
+
const timer = setTimeout(() => stop('pnpm timed out.'), install ? 600_000 : 60_000);
|
|
25
|
+
child.stdout?.on('data', (chunk) => {
|
|
26
|
+
stdout += chunk.toString('utf8');
|
|
27
|
+
if (stdout.length > 4 * 1024 * 1024)
|
|
28
|
+
stop('pnpm output exceeded the supported limit.');
|
|
29
|
+
});
|
|
30
|
+
child.stderr?.on('data', (chunk) => {
|
|
31
|
+
stderr += chunk.toString('utf8');
|
|
32
|
+
if (stderr.length > 4 * 1024 * 1024)
|
|
33
|
+
stop('pnpm output exceeded the supported limit.');
|
|
34
|
+
});
|
|
35
|
+
const cleanup = () => {
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
if (escalation)
|
|
38
|
+
clearTimeout(escalation);
|
|
39
|
+
process.removeListener('SIGINT', interrupt);
|
|
40
|
+
process.removeListener('SIGTERM', interrupt);
|
|
41
|
+
};
|
|
42
|
+
child.once('error', (cause) => {
|
|
43
|
+
cleanup();
|
|
44
|
+
reject(new Error("Could not start pnpm. Install the project's declared pnpm version.", { cause }));
|
|
45
|
+
});
|
|
46
|
+
child.once('close', (code, signal) => {
|
|
47
|
+
cleanup();
|
|
48
|
+
if (failure)
|
|
49
|
+
reject(failure);
|
|
50
|
+
else if (code !== 0) {
|
|
51
|
+
reject(new Error(`pnpm ${args[0]} failed (${signal ?? code}).${stderr ? `\n${stderr.trim()}` : ''}`));
|
|
52
|
+
}
|
|
53
|
+
else
|
|
54
|
+
resolve(stdout);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/sdk",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.134",
|
|
4
4
|
"description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astrale",
|
|
@@ -244,6 +244,7 @@
|
|
|
244
244
|
"@astrale-os/kernel-server": "0.5.0-beta.52",
|
|
245
245
|
"@lucide/icons": "1.34.0",
|
|
246
246
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
247
|
+
"cross-spawn": "7.0.6",
|
|
247
248
|
"hono": "^4.13.2",
|
|
248
249
|
"jose": "^6.2.9",
|
|
249
250
|
"typescript": "~6.0.3"
|
|
@@ -256,6 +257,7 @@
|
|
|
256
257
|
"@commitlint/config-conventional": "~21.2.2",
|
|
257
258
|
"@hono/node-server": "^2.1.1",
|
|
258
259
|
"@hono/node-server-v1": "npm:@hono/node-server@1.19.0",
|
|
260
|
+
"@types/cross-spawn": "6.0.6",
|
|
259
261
|
"@types/node": "^22.20.1",
|
|
260
262
|
"husky": "~9.1.7",
|
|
261
263
|
"lint-staged": "~17.3.0",
|
|
@@ -329,10 +331,11 @@
|
|
|
329
331
|
"qualify:publications": "node scripts/qualify-publications.mjs",
|
|
330
332
|
"qualify": "node scripts/qualify.mjs",
|
|
331
333
|
"sync:linter-policy": "node scripts/sync-domain-policy.mjs",
|
|
332
|
-
"setup": "bash scripts/
|
|
333
|
-
"setup:codex": "AGENT_HARNESSES=codex bash scripts/
|
|
334
|
-
"setup:claude": "AGENT_HARNESSES=claude bash scripts/
|
|
335
|
-
"check:agent-setup": "bash scripts/
|
|
336
|
-
"test:agent-setup": "node --test scripts/
|
|
334
|
+
"setup": "bash scripts/setup/setup.sh",
|
|
335
|
+
"setup:codex": "AGENT_HARNESSES=codex bash scripts/setup/setup.sh",
|
|
336
|
+
"setup:claude": "AGENT_HARNESSES=claude bash scripts/setup/setup.sh",
|
|
337
|
+
"check:agent-setup": "bash scripts/setup/verify.sh",
|
|
338
|
+
"test:agent-setup": "node --test scripts/setup/*.test.cjs",
|
|
339
|
+
"setup:local": "AGENT_SETUP_TOOLS=check bash scripts/setup/setup.sh"
|
|
337
340
|
}
|
|
338
341
|
}
|