@atolis-hq/wake 0.4.16 → 0.4.17
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/dist/src/bootstrap/config/root-schema.d.ts +10 -0
- package/dist/src/bootstrap/config/root-schema.js +18 -2
- package/dist/src/bootstrap/index.d.ts +1 -0
- package/dist/src/bootstrap/index.js +1 -0
- package/dist/src/bootstrap/npm-update-port.d.ts +11 -0
- package/dist/src/bootstrap/npm-update-port.js +45 -0
- package/dist/src/bootstrap/self-update-application.js +2 -3
- package/dist/src/bootstrap/surface-cli-applications.js +50 -18
- package/dist/src/bootstrap/version.js +1 -1
- package/dist/src/surfaces/cli/usage.js +1 -1
- package/package.json +1 -1
|
@@ -140,6 +140,11 @@ declare const hostConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
|
140
140
|
selfUpdate: z.ZodDefault<z.ZodObject<{
|
|
141
141
|
drainTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
142
142
|
cancellationTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
143
|
+
npm: z.ZodDefault<z.ZodObject<{
|
|
144
|
+
package: z.ZodDefault<z.ZodString>;
|
|
145
|
+
distTag: z.ZodDefault<z.ZodString>;
|
|
146
|
+
registry: z.ZodOptional<z.ZodString>;
|
|
147
|
+
}, z.core.$strict>>;
|
|
143
148
|
}, z.core.$strict>>;
|
|
144
149
|
}, z.core.$strict>>;
|
|
145
150
|
export declare const rootConfigSchema: z.ZodObject<{
|
|
@@ -436,6 +441,11 @@ export declare const rootConfigSchema: z.ZodObject<{
|
|
|
436
441
|
selfUpdate: z.ZodDefault<z.ZodObject<{
|
|
437
442
|
drainTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
438
443
|
cancellationTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
444
|
+
npm: z.ZodDefault<z.ZodObject<{
|
|
445
|
+
package: z.ZodDefault<z.ZodString>;
|
|
446
|
+
distTag: z.ZodDefault<z.ZodString>;
|
|
447
|
+
registry: z.ZodOptional<z.ZodString>;
|
|
448
|
+
}, z.core.$strict>>;
|
|
439
449
|
}, z.core.$strict>>;
|
|
440
450
|
}, z.core.$strict>>;
|
|
441
451
|
}, z.core.$strict>;
|
|
@@ -92,9 +92,21 @@ const hostConfigSchema = z
|
|
|
92
92
|
.object({
|
|
93
93
|
drainTimeoutMs: z.number().int().positive().default(30_000),
|
|
94
94
|
cancellationTimeoutMs: z.number().int().positive().default(30_000),
|
|
95
|
+
npm: z
|
|
96
|
+
.object({
|
|
97
|
+
package: z.string().trim().min(1).default('@atolis-hq/wake'),
|
|
98
|
+
distTag: z.string().trim().min(1).default('latest'),
|
|
99
|
+
registry: z.string().url().optional(),
|
|
100
|
+
})
|
|
101
|
+
.strict()
|
|
102
|
+
.default({ package: '@atolis-hq/wake', distTag: 'latest' }),
|
|
95
103
|
})
|
|
96
104
|
.strict()
|
|
97
|
-
.default({
|
|
105
|
+
.default({
|
|
106
|
+
drainTimeoutMs: 30_000,
|
|
107
|
+
cancellationTimeoutMs: 30_000,
|
|
108
|
+
npm: { package: '@atolis-hq/wake', distTag: 'latest' },
|
|
109
|
+
}),
|
|
98
110
|
})
|
|
99
111
|
.strict()
|
|
100
112
|
.default({
|
|
@@ -108,7 +120,11 @@ const hostConfigSchema = z
|
|
|
108
120
|
extraMounts: [],
|
|
109
121
|
},
|
|
110
122
|
development: {},
|
|
111
|
-
selfUpdate: {
|
|
123
|
+
selfUpdate: {
|
|
124
|
+
drainTimeoutMs: 30_000,
|
|
125
|
+
cancellationTimeoutMs: 30_000,
|
|
126
|
+
npm: { package: '@atolis-hq/wake', distTag: 'latest' },
|
|
127
|
+
},
|
|
112
128
|
})
|
|
113
129
|
.superRefine((value, context) => {
|
|
114
130
|
if (value.development.mode === 'source' && value.development.repoRoot === undefined)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SourceUpdatePort } from './self-update-application.js';
|
|
2
|
+
export interface NpmUpdateProcess {
|
|
3
|
+
execute(command: string, args: readonly string[]): Promise<string>;
|
|
4
|
+
}
|
|
5
|
+
/** Resolves immutable published package versions. Installation is performed by the rollout. */
|
|
6
|
+
export declare function createNpmUpdatePort(input: {
|
|
7
|
+
readonly packageName: string;
|
|
8
|
+
readonly distTag?: string;
|
|
9
|
+
readonly registry?: string;
|
|
10
|
+
readonly execute?: NpmUpdateProcess['execute'];
|
|
11
|
+
}): SourceUpdatePort;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { execFile as nodeExecFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const execFile = promisify(nodeExecFile);
|
|
4
|
+
/** Resolves immutable published package versions. Installation is performed by the rollout. */
|
|
5
|
+
export function createNpmUpdatePort(input) {
|
|
6
|
+
const execute = input.execute ?? runProcess;
|
|
7
|
+
const distTag = input.distTag ?? 'latest';
|
|
8
|
+
const registry = input.registry === undefined ? [] : [`--registry=${input.registry}`];
|
|
9
|
+
return {
|
|
10
|
+
isClean: async () => true,
|
|
11
|
+
async latestTag() {
|
|
12
|
+
const resolved = await resolveVersion();
|
|
13
|
+
if (resolved === undefined)
|
|
14
|
+
throw new Error(`No npm version is available for ${input.packageName}`);
|
|
15
|
+
return resolved;
|
|
16
|
+
},
|
|
17
|
+
async candidateTags() {
|
|
18
|
+
const resolved = await resolveVersion();
|
|
19
|
+
return resolved === undefined ? [] : [resolved];
|
|
20
|
+
},
|
|
21
|
+
// The Docker rollout installs this exact version. Keeping this side-effect-free means
|
|
22
|
+
// the updater never overwrites the CLI process which is coordinating the update.
|
|
23
|
+
checkout: async () => { },
|
|
24
|
+
healthy: async () => true,
|
|
25
|
+
};
|
|
26
|
+
async function resolveVersion() {
|
|
27
|
+
const output = await execute('npm', [
|
|
28
|
+
'view',
|
|
29
|
+
`${input.packageName}@${distTag}`,
|
|
30
|
+
'version',
|
|
31
|
+
'--json',
|
|
32
|
+
...registry,
|
|
33
|
+
]);
|
|
34
|
+
const parsed = JSON.parse(output);
|
|
35
|
+
const value = Array.isArray(parsed) ? parsed.at(0) : parsed;
|
|
36
|
+
if (typeof value !== 'string' ||
|
|
37
|
+
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u.test(value))
|
|
38
|
+
throw new Error(`npm returned an invalid version for ${input.packageName}@${distTag}`);
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function runProcess(command, args) {
|
|
43
|
+
const result = await execFile(command, args, { encoding: 'utf8' });
|
|
44
|
+
return result.stdout;
|
|
45
|
+
}
|
|
@@ -10,9 +10,8 @@ export function createSelfUpdateApplication(input) {
|
|
|
10
10
|
async updateLatest(force = false) {
|
|
11
11
|
const candidates = await input.source.candidateTags();
|
|
12
12
|
const [latestCandidate] = candidates;
|
|
13
|
-
if (latestCandidate === undefined)
|
|
14
|
-
throw new Error('No
|
|
15
|
-
}
|
|
13
|
+
if (latestCandidate === undefined)
|
|
14
|
+
throw new Error('No update versions are available');
|
|
16
15
|
for (const tag of candidates) {
|
|
17
16
|
if (!force && (await input.ledger.isBad(tag))) {
|
|
18
17
|
continue;
|
|
@@ -12,6 +12,7 @@ import { ResourceCorrelationRole, resourceId } from '../resources/index.js';
|
|
|
12
12
|
import { DockerProcessError, createApiDispatcher, createLoggedDockerCli, createPackagedAssetSource, createPairingGrant, createProcessLogSink, createSandboxDockerPort, createSurfaceHttpServer, drainProcessOutput, loadOrCreateCredentials, redeemPairingGrant, replaceAccessKey, runDoctor, runSandbox, runSandboxEntrypoint, runSandboxSetup, runSelfUpdateLatestLoop, runTargetSmoke, verifyResidentStart, waitForActiveRuns, waitForever, } from '../surfaces/index.js';
|
|
13
13
|
import { WorkStreamKind, workItemId } from '../work/index.js';
|
|
14
14
|
import { loadConfig } from './config/load-config.js';
|
|
15
|
+
import { createNpmUpdatePort } from './npm-update-port.js';
|
|
15
16
|
import { runtimeProjectionDefinitions } from './projection-runtime.js';
|
|
16
17
|
import { createRunnerRegistry } from './runner-registry.js';
|
|
17
18
|
import { createOneShotRunnerAdvance, createResidentRunnerAdvance, withFinalProjectionCatchUp, } from './runner-tick-adapter.js';
|
|
@@ -315,7 +316,7 @@ function sandboxDockerOptions(root, overrides) {
|
|
|
315
316
|
wakeRoot: root.paths.wakeRoot,
|
|
316
317
|
containerHomeRoot: root.paths.containerHomeRoot,
|
|
317
318
|
image: overrides?.image ?? root.config.host.sandbox.image,
|
|
318
|
-
development: root.config.host.development,
|
|
319
|
+
development: overrides?.development ?? root.config.host.development,
|
|
319
320
|
containerName: root.config.host.sandbox.containerName,
|
|
320
321
|
...(root.config.surfaces.api.enabled ? { publishedPort: root.config.surfaces.api.port } : {}),
|
|
321
322
|
wakeMountPath: root.config.host.sandbox.wakeMountPath,
|
|
@@ -324,7 +325,9 @@ function sandboxDockerOptions(root, overrides) {
|
|
|
324
325
|
startEnabled: root.config.host.sandbox.start.enabled,
|
|
325
326
|
...(process.env.WAKE_MEMORY_PROFILE === 'runner' ? { memoryProfile: 'runner' } : {}),
|
|
326
327
|
inspect: createDockerInspection(root.paths.wakeRoot),
|
|
327
|
-
resolveBuildVersion: () =>
|
|
328
|
+
resolveBuildVersion: async () => overrides?.buildVersion === undefined
|
|
329
|
+
? resolveSandboxBuildVersion(root)
|
|
330
|
+
: overrides.buildVersion,
|
|
328
331
|
};
|
|
329
332
|
}
|
|
330
333
|
function createSandboxDocker(root, overrides) {
|
|
@@ -408,11 +411,13 @@ function createSandboxRuntimeApplications(root) {
|
|
|
408
411
|
* resident `wake start` process actually came back up. Reused for both the
|
|
409
412
|
* forward deploy and a same-shaped rollback to a previously-built tag.
|
|
410
413
|
*/
|
|
411
|
-
async function deploySandboxTag(root, docker, tag, image) {
|
|
412
|
-
const port = createSandboxDockerPort(docker, sandboxDockerOptions(root, { image }));
|
|
414
|
+
async function deploySandboxTag(root, docker, tag, image, overrides) {
|
|
415
|
+
const port = createSandboxDockerPort(docker, sandboxDockerOptions(root, { image, ...overrides }));
|
|
413
416
|
await port.build();
|
|
414
417
|
await port.update();
|
|
415
|
-
const wakeInvocation =
|
|
418
|
+
const wakeInvocation = overrides?.development?.mode === 'source'
|
|
419
|
+
? ['node', '/app/dist/src/main.js']
|
|
420
|
+
: sandboxWakeInvocation(root);
|
|
416
421
|
await verifyResidentStart(docker, root.config.host.sandbox.containerName, [...wakeInvocation, 'start', '--wake-root', '/wake'].join(' '));
|
|
417
422
|
await port.exec([
|
|
418
423
|
...wakeInvocation,
|
|
@@ -421,10 +426,12 @@ async function deploySandboxTag(root, docker, tag, image) {
|
|
|
421
426
|
`/tmp/wake-self-update-healthcheck-${tag}`,
|
|
422
427
|
]);
|
|
423
428
|
}
|
|
424
|
-
async function rollbackSandboxTag(root, docker, image) {
|
|
429
|
+
async function rollbackSandboxTag(root, docker, image, development) {
|
|
425
430
|
const port = createSandboxDockerPort(docker, sandboxDockerOptions(root, { image }));
|
|
426
431
|
await port.update();
|
|
427
|
-
const wakeInvocation =
|
|
432
|
+
const wakeInvocation = development?.mode === 'source'
|
|
433
|
+
? ['node', '/app/dist/src/main.js']
|
|
434
|
+
: sandboxWakeInvocation(root);
|
|
428
435
|
await verifyResidentStart(docker, root.config.host.sandbox.containerName, [...wakeInvocation, 'start', '--wake-root', '/wake'].join(' '));
|
|
429
436
|
}
|
|
430
437
|
function createOperationalApplications(root) {
|
|
@@ -450,31 +457,56 @@ function createOperationalApplications(root) {
|
|
|
450
457
|
sandboxEntrypoint: async () => {
|
|
451
458
|
await runSandboxEntrypoint(createSandboxEntrypointDependencies(root));
|
|
452
459
|
},
|
|
460
|
+
// eslint-disable-next-line complexity -- update source and loop options are validated at this CLI boundary.
|
|
453
461
|
selfUpdate: async (arguments_) => {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const repoRoot = root.config.host.development.repoRoot;
|
|
457
|
-
if (
|
|
462
|
+
const sourceRoot = optionalOperationalOption(arguments_, '--source');
|
|
463
|
+
const configuredSource = root.config.host.development.mode === 'source';
|
|
464
|
+
const repoRoot = sourceRoot ?? root.config.host.development.repoRoot;
|
|
465
|
+
if (sourceRoot !== undefined && root.config.host.development.mode === 'source')
|
|
466
|
+
throw new Error('wake self-update --source cannot override source-mode configuration');
|
|
467
|
+
if (configuredSource && repoRoot === undefined)
|
|
458
468
|
throw new Error('wake self-update requires host.development.repoRoot');
|
|
459
469
|
const tag = optionalOperationalOption(arguments_, '--tag');
|
|
470
|
+
const version = optionalOperationalOption(arguments_, '--version');
|
|
471
|
+
if (tag !== undefined && version !== undefined)
|
|
472
|
+
throw new Error('wake self-update accepts only one of --tag or --version');
|
|
473
|
+
if (version !== undefined && (configuredSource || sourceRoot !== undefined))
|
|
474
|
+
throw new Error('wake self-update --version is only valid for npm updates');
|
|
475
|
+
const useSource = configuredSource || sourceRoot !== undefined;
|
|
476
|
+
const updatePort = useSource
|
|
477
|
+
? createSourceUpdatePort({ repoRoot: repoRoot })
|
|
478
|
+
: createNpmUpdatePort({
|
|
479
|
+
packageName: root.config.host.selfUpdate.npm.package,
|
|
480
|
+
distTag: root.config.host.selfUpdate.npm.distTag,
|
|
481
|
+
...(root.config.host.selfUpdate.npm.registry === undefined
|
|
482
|
+
? {}
|
|
483
|
+
: { registry: root.config.host.selfUpdate.npm.registry }),
|
|
484
|
+
});
|
|
485
|
+
const updateTag = tag ?? version;
|
|
486
|
+
const updateDevelopment = useSource
|
|
487
|
+
? { mode: 'source', repoRoot: repoRoot }
|
|
488
|
+
: { mode: 'packaged' };
|
|
460
489
|
const dockerCli = createDockerCliForRoot(root);
|
|
461
490
|
const imageRepository = root.config.host.sandbox.imageRepository;
|
|
462
491
|
const failureLog = createSelfUpdateFailureLog(root.paths.wakeRoot);
|
|
463
492
|
const application = createSelfUpdateApplication({
|
|
464
493
|
ledger: createUpdateLedger(root.paths.wakeRoot),
|
|
465
|
-
source:
|
|
494
|
+
source: updatePort,
|
|
466
495
|
rollout: {
|
|
467
496
|
async deploy(deployTag) {
|
|
468
497
|
await waitForActiveRuns({
|
|
469
498
|
activeRunIds: () => activeExecutionRunIds(root),
|
|
470
499
|
sleep: async (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
471
500
|
});
|
|
472
|
-
await deploySandboxTag(root, dockerCli, deployTag, `${imageRepository}:${deployTag}
|
|
501
|
+
await deploySandboxTag(root, dockerCli, deployTag, `${imageRepository}:${deployTag}`, {
|
|
502
|
+
development: updateDevelopment,
|
|
503
|
+
buildVersion: deployTag,
|
|
504
|
+
});
|
|
473
505
|
// A later deploy succeeding after a prior rollback clears the stale warning.
|
|
474
506
|
await failureLog.clear();
|
|
475
507
|
},
|
|
476
508
|
async rollback(rollbackTag) {
|
|
477
|
-
await rollbackSandboxTag(root, dockerCli, `${imageRepository}:${rollbackTag}
|
|
509
|
+
await rollbackSandboxTag(root, dockerCli, `${imageRepository}:${rollbackTag}`, updateDevelopment);
|
|
478
510
|
},
|
|
479
511
|
recordFailure: (failedTag, error) => failureLog.record(failedTag, error),
|
|
480
512
|
},
|
|
@@ -485,12 +517,12 @@ function createOperationalApplications(root) {
|
|
|
485
517
|
const force = arguments_.includes('--force');
|
|
486
518
|
if (arguments_.includes('--loop')) {
|
|
487
519
|
const intervalMs = selfUpdateLoopInterval(arguments_);
|
|
488
|
-
if (
|
|
489
|
-
return runSelfUpdateLatestLoop(async () => application.update(
|
|
520
|
+
if (updateTag !== undefined)
|
|
521
|
+
return runSelfUpdateLatestLoop(async () => application.update(updateTag, force), () => delay(intervalMs));
|
|
490
522
|
return runSelfUpdateLatestLoop(async () => application.updateLatest(force), () => delay(intervalMs));
|
|
491
523
|
}
|
|
492
|
-
if (
|
|
493
|
-
return { tag, updated: await application.update(
|
|
524
|
+
if (updateTag !== undefined)
|
|
525
|
+
return { tag: updateTag, updated: await application.update(updateTag, force) };
|
|
494
526
|
return application.updateLatest(force);
|
|
495
527
|
},
|
|
496
528
|
smoke: async () => runTargetSmoke(createRunnerRegistry(root.config.execution, root.fakeScenarios), root.config.execution.defaultRunnerPool, new AbortController().signal),
|
|
@@ -124,6 +124,6 @@ export function resolveWakeVersion(options = {}) {
|
|
|
124
124
|
return `g${headHash.slice(0, 7)}`;
|
|
125
125
|
return '0.1.0-dev';
|
|
126
126
|
}
|
|
127
|
-
export const wakeVersion = "v0.4.
|
|
127
|
+
export const wakeVersion = "v0.4.17";
|
|
128
128
|
/** The registry-installable version used by packaged sandbox images. */
|
|
129
129
|
export const wakePackageVersion = packageVersion(defaultRepoRoot) ?? wakeVersion;
|
|
@@ -24,7 +24,7 @@ export const usage = [
|
|
|
24
24
|
' wake run resolve <run-id> --failed --reason <message>',
|
|
25
25
|
' wake api Run the target API surface',
|
|
26
26
|
' wake sandbox-entrypoint Run the sandbox resident entrypoint',
|
|
27
|
-
' wake self-update Safely update a source
|
|
27
|
+
' wake self-update Safely update Wake from npm or a source checkout',
|
|
28
28
|
'',
|
|
29
29
|
'Getting started:',
|
|
30
30
|
' 1. wake init ./wake-home',
|