windows-development-sandbox 1.23.1 → 1.25.0
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/config.example.json +0 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-USTRSHIE.js → chunk-IZRGTSQ5.js} +158 -131
- package/dist/bin/{chunk-QFSJX2KW.js → chunk-KH4MI2U5.js} +1 -1
- package/dist/bin/{chunk-7YPEDAJD.js → chunk-SUYYVIDW.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/core/config/defaults.js +0 -1
- package/dist/core/detect/toolchains.js +0 -6
- package/dist/core/schema/config.d.ts +1 -2
- package/dist/core/schema/toolchains.d.ts +1 -2
- package/dist/core/schema/toolchains.js +3 -6
- package/dist/guest/agents/agent-files.d.ts +11 -7
- package/dist/guest/agents/agent-files.js +37 -11
- package/dist/guest/agents/local-state.d.ts +2 -1
- package/dist/guest/agents/local-state.js +2 -1
- package/dist/guest/boot/boot-console.d.ts +28 -0
- package/dist/guest/boot/boot-console.js +98 -0
- package/dist/guest/boot/boot.d.ts +8 -1
- package/dist/guest/boot/boot.js +66 -42
- package/dist/guest/boot/graph.d.ts +9 -5
- package/dist/guest/boot/graph.js +8 -2
- package/dist/guest/boot/progress-view.d.ts +116 -0
- package/dist/guest/boot/progress-view.js +456 -0
- package/dist/guest/boot/runner.d.ts +20 -10
- package/dist/guest/boot/runner.js +39 -47
- package/dist/guest/runtime/log-line.d.ts +7 -0
- package/dist/guest/runtime/log-line.js +18 -0
- package/dist/guest/runtime/log.d.ts +17 -4
- package/dist/guest/runtime/log.js +40 -17
- package/dist/guest/runtime/process.d.ts +9 -0
- package/dist/guest/runtime/process.js +69 -8
- package/dist/guest/setup/environment.js +9 -4
- package/dist/guest/setup/hooks.d.ts +2 -0
- package/dist/guest/setup/hooks.js +4 -0
- package/dist/guest/setup/path-plan.d.ts +12 -0
- package/dist/guest/setup/path-plan.js +18 -0
- package/dist/guest/toolchains/native/unreal.js +4 -6
- package/dist/guest/toolchains/native/visual-studio.d.ts +14 -14
- package/dist/guest/toolchains/native/visual-studio.js +145 -174
- package/dist/guest/toolchains/native/vs-persist.d.ts +189 -0
- package/dist/guest/toolchains/native/vs-persist.js +256 -0
- package/dist/guest/toolchains/native/vs-request.d.ts +6 -22
- package/dist/guest/toolchains/native/vs-request.js +16 -46
- package/dist/guest/toolchains/plan.js +11 -14
- package/dist/host/migrate/migrations/drop-vs-install-files.d.ts +5 -0
- package/dist/host/migrate/migrations/drop-vs-install-files.js +34 -0
- package/dist/host/migrate/registry.js +7 -1
- package/dist/runtime/agent.js +67 -26
- package/dist/runtime/daemon.js +958 -716
- package/dist/runtime/db.js +67 -26
- package/dist/runtime/main.js +1792 -1038
- package/dist/runtime/netproxy.js +3 -6
- package/dist/runtime/tool.js +44 -24
- package/dist/runtime/view.js +4 -7
- package/dist/selftest/agent-paths.test.js +17 -1
- package/dist/selftest/agent-settings.test.js +36 -5
- package/dist/selftest/boot-console.test.d.ts +2 -0
- package/dist/selftest/boot-console.test.js +291 -0
- package/dist/selftest/boot-runner.test.js +10 -12
- package/dist/selftest/guest-boot.test.js +7 -1
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/layout.test.js +4 -0
- package/dist/selftest/migrate.test.js +21 -0
- package/dist/selftest/persisted-installs.test.js +169 -32
- package/dist/selftest/support/engine-golden.js +2 -0
- package/dist/selftest/support/fixtures.d.ts +1 -2
- package/dist/shared/channel/schema.d.ts +3 -6
- package/dist/shared/pty/terminal.js +2 -1
- package/dist/sync/watcher.js +5 -1
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
- package/sandbox/scripts/restore-visual-studio.ps1 +78 -0
- package/sandbox/scripts/save-visual-studio.ps1 +106 -0
- package/schemas/config.schema.json +3 -7
- package/schemas/sandbox-config.schema.json +3 -7
- package/dist/guest/toolchains/native/autosdk.d.ts +0 -3
- package/dist/guest/toolchains/native/autosdk.js +0 -50
package/dist/guest/boot/boot.js
CHANGED
|
@@ -15,7 +15,7 @@ import { linkProfileDirsAsync } from '../agents/profile-links.js';
|
|
|
15
15
|
import { restoreClaudeMem } from '../setup/claude-mem.js';
|
|
16
16
|
import { syncClaudeProfile } from '../setup/claude-profile.js';
|
|
17
17
|
import { agentEnv, persistEnvironment } from '../setup/environment.js';
|
|
18
|
-
import { runHooks } from '../setup/hooks.js';
|
|
18
|
+
import { hasHooks, runHooks } from '../setup/hooks.js';
|
|
19
19
|
import { applyAllowOnly, proxyEnv } from '../network/allow-only.js';
|
|
20
20
|
import { applyNetworkPolicy, networkProblems } from '../network/firewall.js';
|
|
21
21
|
import { writeManagedSettings } from '../setup/managed-policy.js';
|
|
@@ -37,12 +37,14 @@ import { now } from '../../shared/channel/run-dir.js';
|
|
|
37
37
|
import { writeJsonAtomic } from '../../shared/io/json.js';
|
|
38
38
|
import { viewSession } from '../sessions/viewer.js';
|
|
39
39
|
import { saveBootEnv } from './boot-env.js';
|
|
40
|
-
import { BOOT_DEFS, STAGES, stageTitle } from './graph.js';
|
|
41
|
-
import { BootRunner,
|
|
40
|
+
import { BOOT_DEFS, STAGES, stageName, stageTitle } from './graph.js';
|
|
41
|
+
import { BootRunner, duration } from './runner.js';
|
|
42
|
+
import { BootConsole } from './boot-console.js';
|
|
43
|
+
import { stepsDetail } from './progress-view.js';
|
|
42
44
|
import { installPools } from '../runtime/pools.js';
|
|
43
45
|
import { primaryProject, saveProjectStatus } from './project-status.js';
|
|
44
46
|
import { dryRun, isWin, localDir, logsDir, run, toolsDir } from '../runtime/paths.js';
|
|
45
|
-
import { log, logPath, runQuiet, warn, withLogContext } from '../runtime/log.js';
|
|
47
|
+
import { log, logPath, notice, record, runQuiet, warn, withLogContext } from '../runtime/log.js';
|
|
46
48
|
import { mkdirp } from '../runtime/fs.js';
|
|
47
49
|
import { session, workspace } from '../runtime/session.js';
|
|
48
50
|
import { applyBootEnvironment, BOOT_SECRETS_VARIABLE, takeSecrets } from '../runtime/secrets.js';
|
|
@@ -159,6 +161,12 @@ export class Boot {
|
|
|
159
161
|
secrets = Object.freeze({});
|
|
160
162
|
basePath = '';
|
|
161
163
|
startedAt = Date.now();
|
|
164
|
+
who = {
|
|
165
|
+
...(session.vpn ? { vpnServer: session.vpn.server } : {}),
|
|
166
|
+
agent: session.harnessName,
|
|
167
|
+
};
|
|
168
|
+
/** The console while the boot runs: the stage rows, warnings and summary (released before the first session). */
|
|
169
|
+
progress = BootConsole.create(Array.from({ length: STAGES }, (_, i) => ({ stage: i + 1, name: stageName(i + 1, this.who) })), BOOT_DEFS.filter((d) => !d.background), { plain: dryRun });
|
|
162
170
|
openGate = () => undefined;
|
|
163
171
|
gate = new Promise((resolve) => {
|
|
164
172
|
this.openGate = resolve;
|
|
@@ -170,14 +178,39 @@ export class Boot {
|
|
|
170
178
|
stepsDone = 0;
|
|
171
179
|
stepsTotal = 0;
|
|
172
180
|
async run() {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
const agent = session.harness ? session.harnessName : 'no agent';
|
|
182
|
+
this.progress.start('Agent sandbox · ' + session.project + ' · ' + agent + ' · ' + workspace);
|
|
183
|
+
let runner;
|
|
184
|
+
try {
|
|
185
|
+
runner = await this.foreground();
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
this.progress.release(null);
|
|
189
|
+
throw e;
|
|
190
|
+
}
|
|
191
|
+
this.progress.release({
|
|
192
|
+
ms: Date.now() - this.startedAt,
|
|
193
|
+
outcomes: runner.results(),
|
|
194
|
+
background: this.backgroundNames(),
|
|
195
|
+
logPath,
|
|
196
|
+
});
|
|
197
|
+
if (dryRun) {
|
|
198
|
+
// Same graph, one task at a time: the background tasks run in place, right after the session.
|
|
199
|
+
this.openGate();
|
|
200
|
+
await runner.run('background');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.openGate();
|
|
204
|
+
const later = runner.run('background');
|
|
205
|
+
// The viewer owns the console now: the background tasks write to the log file only.
|
|
206
|
+
if (session.harness && session.autoSession !== false && process.stdin.isTTY) {
|
|
207
|
+
await viewSession(session.launchId);
|
|
208
|
+
log('\nThis window stays open in ' + workspace + '. Other sessions keep running in their own tabs.');
|
|
209
|
+
}
|
|
210
|
+
await later.catch((e) => warn('Background work failed: ' + errMsg(e)));
|
|
211
|
+
}
|
|
212
|
+
/** The prelude, then every foreground task (the console shows them). */
|
|
213
|
+
async foreground() {
|
|
181
214
|
if (!fs.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
|
|
182
215
|
throw new Error('Workspace folder is missing in the sandbox: ' + workspace);
|
|
183
216
|
this.basePath = process.env.PATH ?? '';
|
|
@@ -189,7 +222,7 @@ export class Boot {
|
|
|
189
222
|
prepareGithubFolder(this.secrets.githubToken);
|
|
190
223
|
installPools();
|
|
191
224
|
const runner = new BootRunner(BOOT_DEFS, this.tasks(), {
|
|
192
|
-
|
|
225
|
+
trace: (line) => record(line),
|
|
193
226
|
warn: (line, quiet) => (quiet ? runQuiet(() => warn(line)) : warn(line)),
|
|
194
227
|
now: () => Date.now(),
|
|
195
228
|
dryRun,
|
|
@@ -199,36 +232,26 @@ export class Boot {
|
|
|
199
232
|
this.lastStatus = s;
|
|
200
233
|
this.publish();
|
|
201
234
|
},
|
|
202
|
-
|
|
235
|
+
observer: this.progress,
|
|
236
|
+
inContext: (ctx, work) => withLogContext({ stage: ctx.stage, task: ctx.title, quiet: ctx.quiet }, work),
|
|
203
237
|
});
|
|
204
238
|
await runner.run('foreground');
|
|
205
|
-
|
|
206
|
-
log(bootSummary(Date.now() - this.startedAt, runner.results(), background, logPath));
|
|
207
|
-
if (dryRun) {
|
|
208
|
-
// Same graph, one task at a time: the background tasks run in place, right after the session.
|
|
209
|
-
this.openGate();
|
|
210
|
-
await runner.run('background');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
this.openGate();
|
|
214
|
-
const later = runner.run('background');
|
|
215
|
-
// The viewer owns the console now: the background tasks write to the log file only.
|
|
216
|
-
if (session.harness && session.autoSession !== false && process.stdin.isTTY) {
|
|
217
|
-
await viewSession(session.launchId);
|
|
218
|
-
log('\nThis window stays open in ' + workspace + '. Other sessions keep running in their own tabs.');
|
|
219
|
-
}
|
|
220
|
-
await later.catch((e) => warn('Background work failed: ' + errMsg(e)));
|
|
239
|
+
return runner;
|
|
221
240
|
}
|
|
222
241
|
stageTitle(n) {
|
|
223
|
-
return stageTitle(n,
|
|
242
|
+
return stageTitle(n, this.who);
|
|
224
243
|
}
|
|
225
|
-
/** The
|
|
244
|
+
/** The toolchain steps that go on after the boot is ready (Visual Studio and what needs it), in plan order. */
|
|
226
245
|
backgroundNames() {
|
|
227
246
|
const t = this.tools;
|
|
228
247
|
if (!t?.later)
|
|
229
248
|
return [];
|
|
230
|
-
|
|
231
|
-
|
|
249
|
+
return t.names.filter((n) => !(n in t.steps));
|
|
250
|
+
}
|
|
251
|
+
/** Runs a stage's hooks; they write to the terminal themselves, so the progress block steps aside for them. */
|
|
252
|
+
hooks(stage, env) {
|
|
253
|
+
if (hasHooks(stage))
|
|
254
|
+
this.progress.aside(() => runHooks(stage, env));
|
|
232
255
|
}
|
|
233
256
|
/**
|
|
234
257
|
* The host's one-shot file, read once. Your saved service sign-ins (accounts.<kind>.share) go to their tools before
|
|
@@ -262,7 +285,7 @@ export class Boot {
|
|
|
262
285
|
setSandboxStatus(s.phase, s.message, {
|
|
263
286
|
step: s.step,
|
|
264
287
|
steps: STAGES,
|
|
265
|
-
title:
|
|
288
|
+
title: stageName(s.step, this.who),
|
|
266
289
|
active: [...s.running.map((name) => ({ name })), ...this.activeSteps],
|
|
267
290
|
done: this.stepsDone,
|
|
268
291
|
total: this.stepsTotal,
|
|
@@ -281,7 +304,7 @@ export class Boot {
|
|
|
281
304
|
},
|
|
282
305
|
audit: () => enableProcessAudit(),
|
|
283
306
|
// 2 - pre-provision hooks and desktop
|
|
284
|
-
hooksPreProvision: () =>
|
|
307
|
+
hooksPreProvision: () => this.hooks('pre-provision', process.env),
|
|
285
308
|
desktop: () => applyPersonalization(),
|
|
286
309
|
browserGpu: () => keepBrowsersOffGpu(),
|
|
287
310
|
// 3 - developer tools
|
|
@@ -343,7 +366,7 @@ export class Boot {
|
|
|
343
366
|
await agents.provision(session.harnessName, session.harness, this.env);
|
|
344
367
|
},
|
|
345
368
|
// 8 - pre-agent hooks
|
|
346
|
-
hooksPreAgent: () =>
|
|
369
|
+
hooksPreAgent: () => this.hooks('pre-agent', this.env),
|
|
347
370
|
// 9 - start
|
|
348
371
|
session: () => this.start(),
|
|
349
372
|
// After the first session runs
|
|
@@ -371,6 +394,7 @@ export class Boot {
|
|
|
371
394
|
...(session.pcInstalls ? { pcInstalls: session.pcInstalls } : {}),
|
|
372
395
|
}, {
|
|
373
396
|
progress: (p) => {
|
|
397
|
+
this.progress.detail('toolchains', stepsDetail(p.active.map((a) => a.name + (a.percent === undefined ? '' : ' ' + Math.round(a.percent) + '%')), p.done, p.total));
|
|
374
398
|
this.activeSteps = p.active;
|
|
375
399
|
this.stepsDone = p.done;
|
|
376
400
|
this.stepsTotal = p.total;
|
|
@@ -424,8 +448,7 @@ export class Boot {
|
|
|
424
448
|
lan: this.lan,
|
|
425
449
|
});
|
|
426
450
|
saveProjectStatus(primaryProject(), workspace, 'ready', 'Ready', session.databases ?? [], this.summary);
|
|
427
|
-
|
|
428
|
-
log(' ' + line);
|
|
451
|
+
this.progress.summary(this.summary);
|
|
429
452
|
}
|
|
430
453
|
/** The toolchains' lines, then the missing protections, allowOnly and VS Code (in this order). */
|
|
431
454
|
summaryLines(toolchainLines) {
|
|
@@ -441,7 +464,8 @@ export class Boot {
|
|
|
441
464
|
const tools = this.tools;
|
|
442
465
|
if (!tools?.later)
|
|
443
466
|
return;
|
|
444
|
-
const
|
|
467
|
+
const names = this.backgroundNames();
|
|
468
|
+
const name = names.length ? names.slice(0, 3).join(', ') + (names.length > 3 ? ' ...' : '') : 'Visual Studio';
|
|
445
469
|
const began = Date.now();
|
|
446
470
|
setBackgroundWork([{ name, state: 'running' }]);
|
|
447
471
|
log('Background: ' + name + ' (installing)');
|
|
@@ -468,7 +492,7 @@ export class Boot {
|
|
|
468
492
|
saveProjectStatus(primaryProject(), workspace, 'ready', 'Ready', session.databases ?? [], this.summary);
|
|
469
493
|
await soft('Sandbox guide for the agent', () => writeGuides(this.summary, this.lan));
|
|
470
494
|
setBackgroundWork([{ name, state: 'done' }]);
|
|
471
|
-
log('Background done in ' +
|
|
495
|
+
log('Background done in ' + duration(Date.now() - began) + ': ' + name);
|
|
472
496
|
}
|
|
473
497
|
catch (e) {
|
|
474
498
|
setBackgroundWork([{ name, state: 'failed' }]);
|
|
@@ -512,7 +536,7 @@ export class Boot {
|
|
|
512
536
|
});
|
|
513
537
|
if (!(await waitForPrimary()))
|
|
514
538
|
throw new Error('The agent session did not start. Logs: ' + logsDir);
|
|
515
|
-
|
|
539
|
+
notice('If Claude asks you to sign in, do it once; the login is saved in persistent storage.');
|
|
516
540
|
}
|
|
517
541
|
}
|
|
518
542
|
export function runBoot() {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { BootTaskDef } from './runner.js';
|
|
2
2
|
export declare const STAGES = 9;
|
|
3
|
-
/**
|
|
4
|
-
export
|
|
5
|
-
vpnServer?: string;
|
|
6
|
-
agent?: string;
|
|
7
|
-
}
|
|
3
|
+
/** Who the stage titles name. */
|
|
4
|
+
export interface StageWho {
|
|
5
|
+
readonly vpnServer?: string;
|
|
6
|
+
readonly agent?: string;
|
|
7
|
+
}
|
|
8
|
+
/** The titles of the nine stages, with a note where one helps (the host's status message). */
|
|
9
|
+
export declare function stageTitle(stage: number, who?: StageWho): string;
|
|
10
|
+
/** The short titles of the nine stages: the console's stage rows and the host's progress line. */
|
|
11
|
+
export declare function stageName(stage: number, who?: StageWho): string;
|
|
8
12
|
/** The boot state the tasks share. */
|
|
9
13
|
export type BootStateKey = 'ptyHost' | 'lan' | 'tools' | 'dbBin' | 'allowSummary' | 'vscodeSummary' | 'env' | 'toolVars' | 'summary' | 'headroom' | 'later';
|
|
10
14
|
export interface BootTaskInfo {
|
package/dist/guest/boot/graph.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
export const STAGES = 9;
|
|
2
|
-
/** The titles of the nine stages
|
|
2
|
+
/** The titles of the nine stages, with a note where one helps (the host's status message). */
|
|
3
3
|
export function stageTitle(stage, who = {}) {
|
|
4
|
+
return stage === 3
|
|
5
|
+
? stageName(stage, who) + ' (the first start downloads them once; later starts are quick)'
|
|
6
|
+
: stageName(stage, who);
|
|
7
|
+
}
|
|
8
|
+
/** The short titles of the nine stages: the console's stage rows and the host's progress line. */
|
|
9
|
+
export function stageName(stage, who = {}) {
|
|
4
10
|
switch (stage) {
|
|
5
11
|
case 1:
|
|
6
12
|
return 'Network and session host';
|
|
7
13
|
case 2:
|
|
8
14
|
return 'Pre-provision hooks and desktop';
|
|
9
15
|
case 3:
|
|
10
|
-
return 'Developer tools
|
|
16
|
+
return 'Developer tools';
|
|
11
17
|
case 4:
|
|
12
18
|
return who.vpnServer ? 'VPN (' + who.vpnServer + ')' : 'VPN (off)';
|
|
13
19
|
case 5:
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type TaskOutcome } from './runner.js';
|
|
2
|
+
export interface ViewStage {
|
|
3
|
+
readonly stage: number;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ViewTask {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly stage: number;
|
|
9
|
+
readonly title: string;
|
|
10
|
+
/** Its failure fails the boot (a soft failure is a warning). */
|
|
11
|
+
readonly critical?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** The marks of a stage row. */
|
|
14
|
+
export interface Glyphs {
|
|
15
|
+
readonly done: string;
|
|
16
|
+
readonly failed: string;
|
|
17
|
+
readonly warned: string;
|
|
18
|
+
readonly skipped: string;
|
|
19
|
+
readonly waiting: string;
|
|
20
|
+
readonly more: string;
|
|
21
|
+
readonly spinner: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
/** For Windows Terminal (Cascadia has braille and check marks). */
|
|
24
|
+
export declare const RICH_GLYPHS: Glyphs;
|
|
25
|
+
/** For the classic console (Consolas has neither braille nor check marks). */
|
|
26
|
+
export declare const CONSOLE_GLYPHS: Glyphs;
|
|
27
|
+
export interface Screen {
|
|
28
|
+
/** Writes text as it is (the view writes its own line ends and, when live, its cursor moves). */
|
|
29
|
+
write(text: string): void;
|
|
30
|
+
/** The terminal's width (live mode). */
|
|
31
|
+
columns(): number;
|
|
32
|
+
}
|
|
33
|
+
export interface ViewOptions {
|
|
34
|
+
/** A terminal: the stage block redraws in place. Otherwise plain, ordered lines. */
|
|
35
|
+
readonly live: boolean;
|
|
36
|
+
readonly screen: Screen;
|
|
37
|
+
/** Milliseconds. */
|
|
38
|
+
readonly now: () => number;
|
|
39
|
+
readonly glyphs?: Glyphs;
|
|
40
|
+
}
|
|
41
|
+
/** The end of the boot: how long it took, which tasks took longest and what goes on in the background. */
|
|
42
|
+
export interface ReadyInfo {
|
|
43
|
+
readonly ms: number;
|
|
44
|
+
readonly outcomes: readonly TaskOutcome[];
|
|
45
|
+
readonly background: readonly string[];
|
|
46
|
+
readonly logPath: string;
|
|
47
|
+
}
|
|
48
|
+
/** "Node, Python, Rust +2 (5/13)": what the toolchain scheduler runs now. */
|
|
49
|
+
export declare function stepsDetail(active: readonly string[], done: number, total: number): string;
|
|
50
|
+
/** "Ready in 46.8s (slowest: ...)" and, when work goes on, the line that says what still installs. */
|
|
51
|
+
export declare function readyLines(info: ReadyInfo): string[];
|
|
52
|
+
/** Word-wraps `text` to `width` columns; a word longer than that is cut. Linear in the text. */
|
|
53
|
+
export declare function wrap(text: string, width: number): string[];
|
|
54
|
+
/** One boot's console: fed by the runner's events and the boot's lines, drawn on a screen. */
|
|
55
|
+
export declare class ProgressView {
|
|
56
|
+
private readonly o;
|
|
57
|
+
private readonly stages;
|
|
58
|
+
private readonly byStage;
|
|
59
|
+
private readonly taskById;
|
|
60
|
+
private readonly nameWidth;
|
|
61
|
+
private readonly glyphs;
|
|
62
|
+
private readonly warnings;
|
|
63
|
+
private readonly notices;
|
|
64
|
+
private tools;
|
|
65
|
+
/** Lines of the live block on the screen now (the cursor is just below them). */
|
|
66
|
+
private drawn;
|
|
67
|
+
private lastFrame;
|
|
68
|
+
private asideDepth;
|
|
69
|
+
private released;
|
|
70
|
+
constructor(stages: readonly ViewStage[], tasks: readonly ViewTask[], o: ViewOptions);
|
|
71
|
+
/**
|
|
72
|
+
* Whether programs should hand their output to the log now: it would draw over the live block, or come out between
|
|
73
|
+
* the plain stages. Not while a hook has the terminal.
|
|
74
|
+
*/
|
|
75
|
+
get capturing(): boolean;
|
|
76
|
+
/** The header line, then (live) the first frame. */
|
|
77
|
+
start(header: string): void;
|
|
78
|
+
started(task: ViewTask): void;
|
|
79
|
+
finished(task: ViewTask, outcome: TaskOutcome): void;
|
|
80
|
+
/** What a running task's place on its row says instead of its title (null: its title again). */
|
|
81
|
+
detail(taskId: string, text: string | null): void;
|
|
82
|
+
/** An info line: the file has it; plain output shows it under its stage (or at once, outside a stage). */
|
|
83
|
+
line(text: string, stage: number | undefined): void;
|
|
84
|
+
warning(text: string): void;
|
|
85
|
+
notice(text: string): void;
|
|
86
|
+
/** The tool summary ("name: detail" lines), printed once at the end. */
|
|
87
|
+
summary(lines: readonly string[]): void;
|
|
88
|
+
/** Redraws the live block (the boot calls it a few times a second). */
|
|
89
|
+
tick(): void;
|
|
90
|
+
/** Runs `work`, which writes to the terminal itself (the hooks): the live block steps aside until it is done. */
|
|
91
|
+
aside<T>(work: () => T): T;
|
|
92
|
+
/**
|
|
93
|
+
* The boot is over (`ready`) or failed (null): the final block, warnings, tools, notices and the ready line, once.
|
|
94
|
+
* The console is free afterwards (the first session takes it); nothing of this view prints again.
|
|
95
|
+
*/
|
|
96
|
+
release(ready: ReadyInfo | null): void;
|
|
97
|
+
/** The live block as it would be drawn now (no colours when `colour` is false): the tests read it. */
|
|
98
|
+
frame(colour?: boolean): string[];
|
|
99
|
+
private draw;
|
|
100
|
+
private erase;
|
|
101
|
+
/** Plain output: every finished stage whose earlier stages are printed, in stage order. */
|
|
102
|
+
private flushPlain;
|
|
103
|
+
private stageBlock;
|
|
104
|
+
private indent;
|
|
105
|
+
/** One stage row; `now` null: the final, still row (no spinner). */
|
|
106
|
+
private row;
|
|
107
|
+
/** The tool summary as two aligned columns, the detail wrapped under itself. */
|
|
108
|
+
private toolRows;
|
|
109
|
+
/** `lead` + `text`, wrapped to `width` with the next lines indented under the text. */
|
|
110
|
+
private hanging;
|
|
111
|
+
/** The segments as one line of at most `width` columns, cut with the "more" mark. */
|
|
112
|
+
private render;
|
|
113
|
+
private paint;
|
|
114
|
+
/** The usable width: one column less than the terminal (a full line would wrap the cursor). */
|
|
115
|
+
private width;
|
|
116
|
+
}
|