@atolis-hq/wake 0.4.32 → 0.4.33
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/surface-api-applications.d.ts +3 -1
- package/dist/src/bootstrap/surface-api-applications.js +29 -0
- package/dist/src/bootstrap/surface-cli-applications.js +30 -2
- package/dist/src/bootstrap/update-maintenance-lease.d.ts +1 -0
- package/dist/src/bootstrap/update-maintenance-lease.js +9 -0
- package/dist/src/bootstrap/version.js +1 -1
- package/dist/src/surfaces/api/contracts/control-plane.d.ts +1 -0
- package/dist/src/surfaces/api/routes/applications.d.ts +4 -0
- package/dist/src/surfaces/api/routes/commands.js +32 -1
- package/dist/src/surfaces/api/routes/control-plane.d.ts +1 -1
- package/dist/src/surfaces/api/routes/control-plane.js +1 -0
- package/dist/src/surfaces/api/routes/index.d.ts +1 -1
- package/dist/src/surfaces/cli/infrastructure/sandbox-startup-failure.d.ts +7 -0
- package/dist/src/surfaces/cli/infrastructure/sandbox-startup-failure.js +33 -0
- package/dist/src/surfaces/cli/main.d.ts +5 -1
- package/dist/src/surfaces/cli/main.js +8 -0
- package/dist/src/surfaces/cli/usage.js +2 -0
- package/dist/src/surfaces/index.d.ts +1 -0
- package/dist/src/surfaces/index.js +1 -0
- package/dist/src/surfaces/web-assets/assets/{index-qai1Ymhv.js → index-Cs3ckFXD.js} +2 -2
- package/dist/src/surfaces/web-assets/index.html +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type ApiApplications } from '../surfaces/index.js';
|
|
2
2
|
import type { CompositionRoot } from './composition-root.js';
|
|
3
|
+
import { UpdateMaintenancePhase } from './update-maintenance-lease.js';
|
|
3
4
|
export declare function createSurfaceApiApplications(root: CompositionRoot, now: () => string): ApiApplications;
|
|
4
5
|
export declare function readControlPlaneStatus(root: CompositionRoot, now: () => string): Promise<{
|
|
5
6
|
data: {
|
|
6
7
|
maintenanceLease?: {
|
|
7
8
|
failure?: string;
|
|
8
|
-
|
|
9
|
+
attemptId: string;
|
|
10
|
+
phase: UpdateMaintenancePhase;
|
|
9
11
|
startedAt: string;
|
|
10
12
|
};
|
|
11
13
|
updatedAt: string;
|
|
@@ -9,6 +9,7 @@ import { projectionMeta, sampledMeta } from './surface-api-metadata.js';
|
|
|
9
9
|
import { projectionPage } from './surface-api-projection-pages.js';
|
|
10
10
|
import { createSurfaceWorkApplications } from './surface-api-work-applications.js';
|
|
11
11
|
import { createWorkflowDiagramApplications } from './surface-api-workflow-diagrams.js';
|
|
12
|
+
import { UpdateMaintenancePhase } from './update-maintenance-lease.js';
|
|
12
13
|
import { wakeVersion } from './version.js';
|
|
13
14
|
export function createSurfaceApiApplications(root, now) {
|
|
14
15
|
return {
|
|
@@ -366,6 +367,33 @@ function createControlPlaneApplications(root, now) {
|
|
|
366
367
|
await root.controlPlane.resume(command.idempotencyKey);
|
|
367
368
|
return commandAccepted(command, now());
|
|
368
369
|
},
|
|
370
|
+
async clearMaintenance(command) {
|
|
371
|
+
const lease = await root.maintenance.read();
|
|
372
|
+
if (lease === null ||
|
|
373
|
+
lease.attemptId !== command.attemptId ||
|
|
374
|
+
lease.phase !== UpdateMaintenancePhase.Failed)
|
|
375
|
+
return maintenanceClearConflict(lease);
|
|
376
|
+
try {
|
|
377
|
+
await root.maintenance.clearFailed(command.attemptId);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
return maintenanceClearConflict(await root.maintenance.read());
|
|
381
|
+
}
|
|
382
|
+
return commandAccepted(command, now());
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function maintenanceClearConflict(lease) {
|
|
387
|
+
return {
|
|
388
|
+
conflict: true,
|
|
389
|
+
code: 'maintenance-not-clearable',
|
|
390
|
+
detail: 'The failed maintenance lease is no longer available to clear',
|
|
391
|
+
retryable: false,
|
|
392
|
+
...(lease === null
|
|
393
|
+
? {}
|
|
394
|
+
: {
|
|
395
|
+
current: { attemptId: lease.attemptId, phase: lease.phase, startedAt: lease.startedAt },
|
|
396
|
+
}),
|
|
369
397
|
};
|
|
370
398
|
}
|
|
371
399
|
export async function readControlPlaneStatus(root, now) {
|
|
@@ -382,6 +410,7 @@ export async function readControlPlaneStatus(root, now) {
|
|
|
382
410
|
? {}
|
|
383
411
|
: {
|
|
384
412
|
maintenanceLease: {
|
|
413
|
+
attemptId: lease.attemptId,
|
|
385
414
|
phase: lease.phase,
|
|
386
415
|
startedAt: lease.startedAt,
|
|
387
416
|
...(lease.failure === undefined ? {} : { failure: lease.failure }),
|
|
@@ -9,7 +9,7 @@ import { BuiltInActivityName, agentActivityDefinition } from '../activities/inde
|
|
|
9
9
|
import { IntakeHost, ResidentHost, TickHost, } from '../control-plane/index.js';
|
|
10
10
|
import { ExecutionFailureCode, RunStatus, isActiveRunStatus, loadPromptTemplate, } from '../execution/index.js';
|
|
11
11
|
import { ResourceCorrelationRole, resourceId } from '../resources/index.js';
|
|
12
|
-
import { DockerProcessError, createApiDispatcher, createLoggedDockerCli, createPackagedAssetSource, createPairingGrant, createProcessLogSink, createSandboxDockerPort, createSurfaceHttpServer, drainProcessOutput, loadOrCreateCredentials, promoteSandboxImage, redeemPairingGrant, replaceAccessKey, runDoctor, runSandbox, runSandboxEntrypoint, runSandboxSetup, runSelfUpdateLatestLoop, runTargetSmoke, verifyResidentStart, waitForActiveRuns, waitForever, } from '../surfaces/index.js';
|
|
12
|
+
import { DockerProcessError, createApiDispatcher, createLoggedDockerCli, createPackagedAssetSource, createPairingGrant, createProcessLogSink, createSandboxDockerPort, createSurfaceHttpServer, describeSandboxStartupFailure, drainProcessOutput, loadOrCreateCredentials, promoteSandboxImage, 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
15
|
import { createNpmUpdatePort } from './npm-update-port.js';
|
|
@@ -427,7 +427,12 @@ async function deploySandboxTag(root, docker, tag, image, overrides) {
|
|
|
427
427
|
: sandboxWakeInvocation(root);
|
|
428
428
|
const healthcheckRoot = `/tmp/wake-self-update-healthcheck-${tag}`;
|
|
429
429
|
await port.build();
|
|
430
|
-
|
|
430
|
+
try {
|
|
431
|
+
await port.update();
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
throw await describeSandboxStartupFailure(docker, root.config.host.sandbox.containerName, error);
|
|
435
|
+
}
|
|
431
436
|
await verifyResidentStart(docker, root.config.host.sandbox.containerName, [...wakeInvocation, 'start', '--wake-root', '/wake'].join(' '));
|
|
432
437
|
await port.exec([...wakeInvocation, 'init', healthcheckRoot]);
|
|
433
438
|
await port.exec([...wakeInvocation, 'tick', '--wake-root', healthcheckRoot, '--no-sandbox']);
|
|
@@ -456,6 +461,16 @@ function createOperationalApplications(root) {
|
|
|
456
461
|
},
|
|
457
462
|
},
|
|
458
463
|
}),
|
|
464
|
+
maintenance: async (arguments_) => {
|
|
465
|
+
const command = withoutOperationalWakeRoot(arguments_);
|
|
466
|
+
if (command.length !== 2 || command[0] !== 'clear' || command[1] !== '--failed')
|
|
467
|
+
throw new Error('wake maintenance clear requires --failed');
|
|
468
|
+
const lease = await root.maintenance.read();
|
|
469
|
+
if (lease === null)
|
|
470
|
+
return { cleared: false };
|
|
471
|
+
await root.maintenance.clearFailed(lease.attemptId);
|
|
472
|
+
return { cleared: true, tag: lease.tag };
|
|
473
|
+
},
|
|
459
474
|
sandboxSetup: async (arguments_) => {
|
|
460
475
|
if (arguments_.length > 0)
|
|
461
476
|
throw new Error('wake sandbox-setup accepts no arguments');
|
|
@@ -766,6 +781,19 @@ function selfUpdateLoopInterval(arguments_) {
|
|
|
766
781
|
throw new Error('wake self-update --loop-interval-ms must be a positive integer');
|
|
767
782
|
return interval;
|
|
768
783
|
}
|
|
784
|
+
function withoutOperationalWakeRoot(arguments_) {
|
|
785
|
+
const result = [];
|
|
786
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
787
|
+
if (arguments_[index] !== '--wake-root') {
|
|
788
|
+
result.push(arguments_[index]);
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (arguments_[index + 1] === undefined)
|
|
792
|
+
throw new Error('wake maintenance requires --wake-root <path>');
|
|
793
|
+
index += 1;
|
|
794
|
+
}
|
|
795
|
+
return result;
|
|
796
|
+
}
|
|
769
797
|
function delay(milliseconds) {
|
|
770
798
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
771
799
|
}
|
|
@@ -20,5 +20,6 @@ export interface UpdateMaintenanceLease {
|
|
|
20
20
|
transition(phase: Exclude<UpdateMaintenancePhase, typeof UpdateMaintenancePhase.Failed>, attemptId?: string): Promise<UpdateMaintenanceState>;
|
|
21
21
|
fail(error: unknown, attemptId?: string): Promise<UpdateMaintenanceState>;
|
|
22
22
|
clear(attemptId?: string): Promise<void>;
|
|
23
|
+
clearFailed(attemptId: string): Promise<void>;
|
|
23
24
|
}
|
|
24
25
|
export declare function createUpdateMaintenanceLease(wakeRoot: string, now?: () => string, createAttemptId?: () => string, isProcessAlive?: (pid: number) => boolean): UpdateMaintenanceLease;
|
|
@@ -72,6 +72,15 @@ export function createUpdateMaintenanceLease(wakeRoot, now = () => new Date().to
|
|
|
72
72
|
await rm(path, { force: true });
|
|
73
73
|
});
|
|
74
74
|
},
|
|
75
|
+
async clearFailed(attemptId) {
|
|
76
|
+
await withLeaseLock(path, async () => {
|
|
77
|
+
const current = await requireState(path);
|
|
78
|
+
requireOwnership(current, attemptId);
|
|
79
|
+
if (current.phase !== UpdateMaintenancePhase.Failed)
|
|
80
|
+
throw new Error('Only a failed maintenance lease can be cleared by an operator');
|
|
81
|
+
await rm(path, { force: true });
|
|
82
|
+
});
|
|
83
|
+
},
|
|
75
84
|
};
|
|
76
85
|
}
|
|
77
86
|
function requireOwnership(state, attemptId) {
|
|
@@ -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.33";
|
|
128
128
|
/** The registry-installable version used by packaged sandbox images. */
|
|
129
129
|
export const wakePackageVersion = packageVersion(defaultRepoRoot) ?? wakeVersion;
|
|
@@ -11,6 +11,7 @@ export interface ControlPlaneStatusResponse {
|
|
|
11
11
|
* lease exists, including a failed one -- see update-maintenance-lease.ts.
|
|
12
12
|
*/
|
|
13
13
|
readonly maintenanceLease?: {
|
|
14
|
+
readonly attemptId: string;
|
|
14
15
|
readonly phase: string;
|
|
15
16
|
readonly startedAt: string;
|
|
16
17
|
readonly failure?: string;
|
|
@@ -20,6 +20,9 @@ export type ApiResourceResult<T> = ResourceResponse<T>;
|
|
|
20
20
|
export interface ApiCommandRequest {
|
|
21
21
|
readonly idempotencyKey: string;
|
|
22
22
|
}
|
|
23
|
+
export interface ApiClearMaintenanceRequest extends ApiCommandRequest {
|
|
24
|
+
readonly attemptId: string;
|
|
25
|
+
}
|
|
23
26
|
export type ApiRunResolutionRequest = (ApiCommandRequest & {
|
|
24
27
|
readonly status: typeof RunStatus.Succeeded;
|
|
25
28
|
readonly outcome: unknown;
|
|
@@ -46,6 +49,7 @@ export interface ApiApplications {
|
|
|
46
49
|
status(): Promise<ApiResourceResult<ControlPlaneStatusResponse>>;
|
|
47
50
|
pause?(command: ApiCommandRequest): Promise<ApiCommandResult>;
|
|
48
51
|
resume?(command: ApiCommandRequest): Promise<ApiCommandResult>;
|
|
52
|
+
clearMaintenance?(command: ApiClearMaintenanceRequest): Promise<ApiCommandResult>;
|
|
49
53
|
};
|
|
50
54
|
readonly work: {
|
|
51
55
|
list(query: CollectionQuery): Promise<ApiCollectionPage<WorkItemResponse>>;
|
|
@@ -10,6 +10,9 @@ export async function dispatchCommand(applications, url, body) {
|
|
|
10
10
|
const work = await dispatchWorkCommand(applications, url.pathname, body);
|
|
11
11
|
if (work !== undefined)
|
|
12
12
|
return work;
|
|
13
|
+
const maintenance = await dispatchMaintenanceClear(applications, url.pathname, body);
|
|
14
|
+
if (maintenance !== undefined)
|
|
15
|
+
return maintenance;
|
|
13
16
|
const request = commandRequest(body);
|
|
14
17
|
if (isHttpResponse(request))
|
|
15
18
|
return request;
|
|
@@ -78,6 +81,8 @@ async function dispatchControlCommand(applications, pathname, request) {
|
|
|
78
81
|
const name = controlCommandName(pathname);
|
|
79
82
|
if (name === undefined)
|
|
80
83
|
return undefined;
|
|
84
|
+
if (name === 'clear-maintenance')
|
|
85
|
+
return undefined;
|
|
81
86
|
const status = await applications.controlPlane.status();
|
|
82
87
|
const operation = applications.controlPlane[name];
|
|
83
88
|
return operation === undefined
|
|
@@ -89,7 +94,33 @@ function controlCommandName(pathname) {
|
|
|
89
94
|
if (!pathname.startsWith(prefix))
|
|
90
95
|
return undefined;
|
|
91
96
|
const name = pathname.slice(prefix.length);
|
|
92
|
-
return name === 'pause' || name === 'resume' ? name : undefined;
|
|
97
|
+
return name === 'pause' || name === 'resume' || name === 'clear-maintenance' ? name : undefined;
|
|
98
|
+
}
|
|
99
|
+
async function dispatchMaintenanceClear(applications, pathname, body) {
|
|
100
|
+
if (pathname !== '/api/v1/control-plane/commands/clear-maintenance')
|
|
101
|
+
return undefined;
|
|
102
|
+
const request = clearMaintenanceRequest(body);
|
|
103
|
+
if (isHttpResponse(request))
|
|
104
|
+
return request;
|
|
105
|
+
const operation = applications.controlPlane.clearMaintenance;
|
|
106
|
+
const status = await applications.controlPlane.status();
|
|
107
|
+
return operation === undefined
|
|
108
|
+
? unavailable('clear-maintenance', status.data)
|
|
109
|
+
: accepted(await operation(request), applications.now());
|
|
110
|
+
}
|
|
111
|
+
function clearMaintenanceRequest(body) {
|
|
112
|
+
if (!isObject(body))
|
|
113
|
+
return invalidRequest('idempotencyKey', 'A JSON object with an idempotency key is required');
|
|
114
|
+
if (Object.keys(body).some((key) => key !== 'idempotencyKey' && key !== 'attemptId'))
|
|
115
|
+
return invalidRequest('', 'The command body contains unknown fields');
|
|
116
|
+
const command = commandRequest({ idempotencyKey: body.idempotencyKey });
|
|
117
|
+
if (isHttpResponse(command))
|
|
118
|
+
return command;
|
|
119
|
+
if (typeof body.attemptId !== 'string' || body.attemptId.trim() === '')
|
|
120
|
+
return invalidRequest('attemptId', 'Must be a non-empty string');
|
|
121
|
+
if (body.attemptId.length > 200)
|
|
122
|
+
return invalidRequest('attemptId', 'Must be at most 200 characters');
|
|
123
|
+
return { ...command, attemptId: body.attemptId };
|
|
93
124
|
}
|
|
94
125
|
async function dispatchRunnerCommand(applications, pathname, request) {
|
|
95
126
|
const match = /^\/api\/v1\/runners\/([^/]+)\/commands\/(pause|unpause)$/.exec(pathname);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const controlPlaneRoutes: readonly ["/api/v1/control-plane/status", "/api/v1/control-plane/commands/pause", "/api/v1/control-plane/commands/resume"];
|
|
1
|
+
export declare const controlPlaneRoutes: readonly ["/api/v1/control-plane/status", "/api/v1/control-plane/commands/pause", "/api/v1/control-plane/commands/resume", "/api/v1/control-plane/commands/clear-maintenance"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ApiDispatcher } from '../http-server.js';
|
|
2
2
|
import type { ApiApplications } from './applications.js';
|
|
3
|
-
export type { ApiApplications, ApiCollectionPage, ApiCommandRequest, ApiResourceResult, ApiRunResolutionRequest, ApiSystemApplications, CollectionQuery, } from './applications.js';
|
|
3
|
+
export type { ApiApplications, ApiClearMaintenanceRequest, ApiCollectionPage, ApiCommandRequest, ApiResourceResult, ApiRunResolutionRequest, ApiSystemApplications, CollectionQuery, } from './applications.js';
|
|
4
4
|
export declare function createApiDispatcher(applications: ApiApplications): ApiDispatcher;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type DockerCli } from './docker-cli.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adds the short-lived replacement container's logs to a rollout failure
|
|
4
|
+
* before rollback removes that container. Docker otherwise reports only the
|
|
5
|
+
* follow-on `exec` failure, which hides the actual entrypoint error.
|
|
6
|
+
*/
|
|
7
|
+
export declare function describeSandboxStartupFailure(docker: DockerCli, containerName: string, error: unknown): Promise<Error>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DockerProcessError } from './docker-cli.js';
|
|
2
|
+
import { scrubProcessLog } from './process-log.js';
|
|
3
|
+
/**
|
|
4
|
+
* Adds the short-lived replacement container's logs to a rollout failure
|
|
5
|
+
* before rollback removes that container. Docker otherwise reports only the
|
|
6
|
+
* follow-on `exec` failure, which hides the actual entrypoint error.
|
|
7
|
+
*/
|
|
8
|
+
export async function describeSandboxStartupFailure(docker, containerName, error) {
|
|
9
|
+
const failure = formatDockerError(error);
|
|
10
|
+
try {
|
|
11
|
+
const output = await docker.invoke(['logs', '--tail', '100', containerName], {
|
|
12
|
+
suppressOutput: true,
|
|
13
|
+
});
|
|
14
|
+
const logs = scrubProcessLog(`${output.stdout}${output.stderr}`).trim();
|
|
15
|
+
if (logs.length > 0)
|
|
16
|
+
return new Error(`Sandbox replacement "${containerName}" failed during startup: ${failure}\n` +
|
|
17
|
+
`Container logs:\n${logs}`, { cause: error });
|
|
18
|
+
}
|
|
19
|
+
catch (logsError) {
|
|
20
|
+
return new Error(`Sandbox replacement "${containerName}" failed during startup: ${failure}. ` +
|
|
21
|
+
`Could not collect its logs: ${formatDockerError(logsError)}`, { cause: error });
|
|
22
|
+
}
|
|
23
|
+
return new Error(`Sandbox replacement "${containerName}" failed during startup: ${failure}`, {
|
|
24
|
+
cause: error,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function formatDockerError(error) {
|
|
28
|
+
if (error instanceof DockerProcessError) {
|
|
29
|
+
const output = `${error.result.stdout}${error.result.stderr}`.trim();
|
|
30
|
+
return output.length === 0 ? error.message : `${error.message}: ${scrubProcessLog(output)}`;
|
|
31
|
+
}
|
|
32
|
+
return error instanceof Error ? error.message : String(error);
|
|
33
|
+
}
|
|
@@ -5,6 +5,9 @@ export interface HostOptions {
|
|
|
5
5
|
readonly port?: number;
|
|
6
6
|
readonly wakeRoot?: string;
|
|
7
7
|
}
|
|
8
|
+
export declare const WakeOperationalCommand: {
|
|
9
|
+
readonly Maintenance: "maintenance";
|
|
10
|
+
};
|
|
8
11
|
export type WakeCommand = ({
|
|
9
12
|
readonly kind: 'tick' | 'start' | 'stop';
|
|
10
13
|
} & {
|
|
@@ -37,7 +40,7 @@ export type WakeCommand = ({
|
|
|
37
40
|
readonly rebuildProjections: boolean;
|
|
38
41
|
readonly wakeRoot?: string;
|
|
39
42
|
} | {
|
|
40
|
-
readonly kind: 'init' | 'doctor' | 'sandbox-setup' | 'sandbox-entrypoint' | 'self-update' | 'smoke';
|
|
43
|
+
readonly kind: 'init' | 'doctor' | typeof WakeOperationalCommand.Maintenance | 'sandbox-setup' | 'sandbox-entrypoint' | 'self-update' | 'smoke';
|
|
41
44
|
readonly arguments: readonly string[];
|
|
42
45
|
} | {
|
|
43
46
|
readonly kind: 'sandbox';
|
|
@@ -59,6 +62,7 @@ export interface WakeCliApplications {
|
|
|
59
62
|
readonly operational?: {
|
|
60
63
|
readonly init: (arguments_: readonly string[]) => Promise<unknown>;
|
|
61
64
|
readonly doctor: (arguments_: readonly string[]) => Promise<unknown>;
|
|
65
|
+
readonly maintenance: (arguments_: readonly string[]) => Promise<unknown>;
|
|
62
66
|
readonly sandbox: (arguments_: readonly string[]) => Promise<unknown>;
|
|
63
67
|
readonly sandboxSetup: (arguments_: readonly string[]) => Promise<unknown>;
|
|
64
68
|
readonly sandboxEntrypoint: (arguments_: readonly string[]) => Promise<unknown>;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import qrcodeTerminal from 'qrcode-terminal';
|
|
3
3
|
import { ExecutionStreamKind, RunStatus } from '../../execution/index.js';
|
|
4
|
+
import { defineClosedVocabulary } from '../../kernel/index.js';
|
|
5
|
+
export const WakeOperationalCommand = defineClosedVocabulary({
|
|
6
|
+
Maintenance: 'maintenance',
|
|
7
|
+
});
|
|
4
8
|
const defaultBudget = { maxAdvances: 100, maxRuns: 100, maxDurationMs: 30_000 };
|
|
5
9
|
/** Parses Surface vocabulary only; Bootstrap supplies every application facade. */
|
|
6
10
|
// eslint-disable-next-line complexity -- command vocabulary is intentionally exhaustive at the Surface boundary.
|
|
@@ -29,6 +33,7 @@ export function parseWakeCommand(arguments_) {
|
|
|
29
33
|
return parseResidentCommand(command, arguments_.slice(1));
|
|
30
34
|
case 'init':
|
|
31
35
|
case 'doctor':
|
|
36
|
+
case WakeOperationalCommand.Maintenance:
|
|
32
37
|
case 'sandbox-setup':
|
|
33
38
|
case 'sandbox-entrypoint':
|
|
34
39
|
case 'sandbox':
|
|
@@ -153,6 +158,9 @@ export async function runWakeCommand(command, applications, output, signal) {
|
|
|
153
158
|
case 'doctor':
|
|
154
159
|
writeResult(output, await operational(applications).doctor(command.arguments));
|
|
155
160
|
return;
|
|
161
|
+
case WakeOperationalCommand.Maintenance:
|
|
162
|
+
writeResult(output, await operational(applications).maintenance(command.arguments));
|
|
163
|
+
return;
|
|
156
164
|
case 'sandbox':
|
|
157
165
|
writeResult(output, await operational(applications).sandbox(command.arguments));
|
|
158
166
|
return;
|
|
@@ -16,6 +16,7 @@ export const usage = [
|
|
|
16
16
|
' wake correlate Manually correlate a resource to a work item',
|
|
17
17
|
' wake run resolve Resolve an escalated ambiguous run',
|
|
18
18
|
' wake doctor Diagnose config/GitHub/Docker/sandbox setup problems',
|
|
19
|
+
' wake maintenance clear Clear an abandoned failed self-update maintenance lease',
|
|
19
20
|
' wake --version Print the installed Wake version',
|
|
20
21
|
' wake --help Show this message',
|
|
21
22
|
'',
|
|
@@ -25,6 +26,7 @@ export const usage = [
|
|
|
25
26
|
' wake api Run the target API surface',
|
|
26
27
|
' wake sandbox-entrypoint Run the sandbox resident entrypoint',
|
|
27
28
|
' wake self-update Safely update Wake from npm or a source checkout',
|
|
29
|
+
' wake maintenance clear --failed',
|
|
28
30
|
'',
|
|
29
31
|
'Getting started:',
|
|
30
32
|
' 1. wake init ./wake-home',
|
|
@@ -42,6 +42,7 @@ export * from './cli/commands/ui.js';
|
|
|
42
42
|
export * from './cli/commands/validate-state.js';
|
|
43
43
|
export * from './cli/infrastructure/docker-cli.js';
|
|
44
44
|
export * from './cli/infrastructure/process-log.js';
|
|
45
|
+
export * from './cli/infrastructure/sandbox-startup-failure.js';
|
|
45
46
|
export * from './cli/main.js';
|
|
46
47
|
export * from './cli/usage.js';
|
|
47
48
|
export * from './contracts/config.js';
|
|
@@ -42,6 +42,7 @@ export * from './cli/commands/ui.js';
|
|
|
42
42
|
export * from './cli/commands/validate-state.js';
|
|
43
43
|
export * from './cli/infrastructure/docker-cli.js';
|
|
44
44
|
export * from './cli/infrastructure/process-log.js';
|
|
45
|
+
export * from './cli/infrastructure/sandbox-startup-failure.js';
|
|
45
46
|
export * from './cli/main.js';
|
|
46
47
|
export * from './cli/usage.js';
|
|
47
48
|
export * from './contracts/config.js';
|