screencast-axi 0.1.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/LICENSE +21 -0
- package/README.md +555 -0
- package/dist/bin/screencast-axi.d.ts +2 -0
- package/dist/bin/screencast-axi.js +16 -0
- package/dist/bin/screencast-axi.js.map +1 -0
- package/dist/src/auth/strategies.d.ts +54 -0
- package/dist/src/auth/strategies.js +137 -0
- package/dist/src/auth/strategies.js.map +1 -0
- package/dist/src/auth/types.d.ts +65 -0
- package/dist/src/auth/types.js +2 -0
- package/dist/src/auth/types.js.map +1 -0
- package/dist/src/browser.d.ts +100 -0
- package/dist/src/browser.js +168 -0
- package/dist/src/browser.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +160 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/auth.d.ts +4 -0
- package/dist/src/commands/auth.js +207 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/check.d.ts +12 -0
- package/dist/src/commands/check.js +103 -0
- package/dist/src/commands/check.js.map +1 -0
- package/dist/src/commands/doctor.d.ts +15 -0
- package/dist/src/commands/doctor.js +131 -0
- package/dist/src/commands/doctor.js.map +1 -0
- package/dist/src/commands/guide.d.ts +6 -0
- package/dist/src/commands/guide.js +257 -0
- package/dist/src/commands/guide.js.map +1 -0
- package/dist/src/commands/home.d.ts +12 -0
- package/dist/src/commands/home.js +78 -0
- package/dist/src/commands/home.js.map +1 -0
- package/dist/src/commands/list.d.ts +6 -0
- package/dist/src/commands/list.js +128 -0
- package/dist/src/commands/list.js.map +1 -0
- package/dist/src/commands/record.d.ts +7 -0
- package/dist/src/commands/record.js +266 -0
- package/dist/src/commands/record.js.map +1 -0
- package/dist/src/commands/scaffold.d.ts +4 -0
- package/dist/src/commands/scaffold.js +122 -0
- package/dist/src/commands/scaffold.js.map +1 -0
- package/dist/src/commands/setup.d.ts +14 -0
- package/dist/src/commands/setup.js +137 -0
- package/dist/src/commands/setup.js.map +1 -0
- package/dist/src/config.d.ts +126 -0
- package/dist/src/config.js +275 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/director.d.ts +217 -0
- package/dist/src/director.js +415 -0
- package/dist/src/director.js.map +1 -0
- package/dist/src/duration.d.ts +33 -0
- package/dist/src/duration.js +68 -0
- package/dist/src/duration.js.map +1 -0
- package/dist/src/encode.d.ts +67 -0
- package/dist/src/encode.js +225 -0
- package/dist/src/encode.js.map +1 -0
- package/dist/src/errors.d.ts +19 -0
- package/dist/src/errors.js +27 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/flags.d.ts +39 -0
- package/dist/src/flags.js +130 -0
- package/dist/src/flags.js.map +1 -0
- package/dist/src/forensics.d.ts +51 -0
- package/dist/src/forensics.js +107 -0
- package/dist/src/forensics.js.map +1 -0
- package/dist/src/hooks.d.ts +9 -0
- package/dist/src/hooks.js +20 -0
- package/dist/src/hooks.js.map +1 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.js +18 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/inventory.d.ts +45 -0
- package/dist/src/inventory.js +89 -0
- package/dist/src/inventory.js.map +1 -0
- package/dist/src/manifest.d.ts +89 -0
- package/dist/src/manifest.js +137 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/output.d.ts +8 -0
- package/dist/src/output.js +2 -0
- package/dist/src/output.js.map +1 -0
- package/dist/src/overlay.d.ts +105 -0
- package/dist/src/overlay.js +302 -0
- package/dist/src/overlay.js.map +1 -0
- package/dist/src/reference.d.ts +1 -0
- package/dist/src/reference.js +108 -0
- package/dist/src/reference.js.map +1 -0
- package/dist/src/run.d.ts +82 -0
- package/dist/src/run.js +321 -0
- package/dist/src/run.js.map +1 -0
- package/dist/src/skill.d.ts +12 -0
- package/dist/src/skill.js +69 -0
- package/dist/src/skill.js.map +1 -0
- package/dist/src/toolchain.d.ts +62 -0
- package/dist/src/toolchain.js +127 -0
- package/dist/src/toolchain.js.map +1 -0
- package/dist/src/types.d.ts +88 -0
- package/dist/src/types.js +18 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/version.d.ts +10 -0
- package/dist/src/version.js +11 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +93 -0
- package/skills/screencast-axi/SKILL.md +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { openContext, resolveViewport } from "../browser.js";
|
|
4
|
+
import { loadConfig, selectStrategy } from "../config.js";
|
|
5
|
+
import { ScreencastError } from "../errors.js";
|
|
6
|
+
import { parseFlags } from "../flags.js";
|
|
7
|
+
import { parseDuration } from "../duration.js";
|
|
8
|
+
export const AUTH_FLAGS = {
|
|
9
|
+
config: { kind: "string", description: "Path to a config file", placeholder: "path" },
|
|
10
|
+
"base-url": { kind: "string", description: "Site to sign in to", placeholder: "url" },
|
|
11
|
+
interactive: { kind: "boolean", description: "Required for `login`: opens a real browser" },
|
|
12
|
+
"save-state": {
|
|
13
|
+
kind: "string",
|
|
14
|
+
description: "Write a Playwright storage state here as well",
|
|
15
|
+
placeholder: "path",
|
|
16
|
+
},
|
|
17
|
+
headed: { kind: "boolean", description: "Show the browser for `check`" },
|
|
18
|
+
wait: {
|
|
19
|
+
kind: "string",
|
|
20
|
+
description: "How long `login` waits for the window to close (default 5m)",
|
|
21
|
+
placeholder: "5m",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
function contextFor(baseUrl, rootDir) {
|
|
25
|
+
return {
|
|
26
|
+
baseUrl,
|
|
27
|
+
rootDir,
|
|
28
|
+
scenario: { id: "auth", title: "Sign-in check" },
|
|
29
|
+
log: (message) => void process.stderr.write(` ${message}\n`),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether a browser window could actually be seen by someone.
|
|
34
|
+
*
|
|
35
|
+
* On Linux a missing DISPLAY means no window can appear at all, so waiting for
|
|
36
|
+
* one to close is dead time. macOS and Windows always have a desktop for a
|
|
37
|
+
* logged-in session.
|
|
38
|
+
*/
|
|
39
|
+
function hasDisplay() {
|
|
40
|
+
if (process.platform !== "linux")
|
|
41
|
+
return true;
|
|
42
|
+
return Boolean(process.env["DISPLAY"] ?? process.env["WAYLAND_DISPLAY"]);
|
|
43
|
+
}
|
|
44
|
+
async function withTimeout(work, ms, baseUrl) {
|
|
45
|
+
let timer;
|
|
46
|
+
try {
|
|
47
|
+
return await Promise.race([
|
|
48
|
+
work,
|
|
49
|
+
new Promise((_, reject) => {
|
|
50
|
+
timer = setTimeout(() => reject(new ScreencastError("Timed out waiting for the sign-in window", "LOGIN_TIMEOUT", [
|
|
51
|
+
"Nothing was saved. Run it again when there is time to finish signing in",
|
|
52
|
+
`Give it longer with \`--wait 15m\`, or sign in at ${baseUrl} first`,
|
|
53
|
+
])), ms);
|
|
54
|
+
}),
|
|
55
|
+
]);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
if (timer)
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function authCommand(args) {
|
|
63
|
+
const { positionals, flags } = parseFlags(args, AUTH_FLAGS);
|
|
64
|
+
const [action, name] = positionals;
|
|
65
|
+
if (action !== "login" && action !== "check") {
|
|
66
|
+
throw new ScreencastError(action ? `Unknown auth action: ${action}` : "Say what to do", "VALIDATION_ERROR", [
|
|
67
|
+
"`screencast-axi auth login --interactive` opens a browser to sign in by hand",
|
|
68
|
+
"`screencast-axi auth check` reports whether the saved session still works",
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
const config = await loadConfig(flags["config"]);
|
|
72
|
+
const baseUrl = flags["base-url"] ?? config.baseUrl;
|
|
73
|
+
const strategy = selectStrategy(config, undefined, name);
|
|
74
|
+
if (!strategy) {
|
|
75
|
+
throw new ScreencastError("No auth strategy is configured", "NO_AUTH_STRATEGY", [
|
|
76
|
+
"Add one under `auth` in screencast.config.ts",
|
|
77
|
+
"`profileAuth()` is the one that needs no code for the site you are recording",
|
|
78
|
+
"Import it from `screencast-axi`",
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
const viewport = await resolveViewport({ ...(config.device ? { device: config.device } : {}) }, config.viewport);
|
|
82
|
+
const authCtx = contextFor(baseUrl, config.rootDir);
|
|
83
|
+
if (action === "login") {
|
|
84
|
+
return login(config, strategy, viewport, authCtx, flags);
|
|
85
|
+
}
|
|
86
|
+
return check(config, strategy, viewport, authCtx, flags);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Opens a browser so a person can sign in by hand.
|
|
90
|
+
*
|
|
91
|
+
* The one command here that needs a human, and the reason the whole tool works
|
|
92
|
+
* on a site nobody wrote a strategy for: OAuth, SSO, a magic link and
|
|
93
|
+
* two-factor are all just "the person does the thing", and the session lands
|
|
94
|
+
* in the profile.
|
|
95
|
+
*
|
|
96
|
+
* It never reads stdin, so an agent can open the window on the user's screen
|
|
97
|
+
* rather than making them retype a command. What it must never do is hang: the
|
|
98
|
+
* wait is bounded, it says on stderr what it is waiting for, and it refuses up
|
|
99
|
+
* front where no window could appear (a headless Linux box has no display, so
|
|
100
|
+
* nobody would ever see it and the wait would be pure dead time).
|
|
101
|
+
*
|
|
102
|
+
* `--interactive` stays required. An agent reaching for `auth login` without
|
|
103
|
+
* meaning to involve a person should be told to, not quietly open a window.
|
|
104
|
+
*/
|
|
105
|
+
async function login(config, strategy, viewport, authCtx, flags) {
|
|
106
|
+
if (!strategy.interactiveLogin) {
|
|
107
|
+
throw new ScreencastError(`The \`${strategy.name}\` strategy has no interactive sign-in`, "NOT_SUPPORTED", [
|
|
108
|
+
"`profileAuth()` is the strategy that signs in through a real browser",
|
|
109
|
+
`\`${strategy.name}\` gets its session another way - check its own configuration`,
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
112
|
+
if (flags["interactive"] !== true) {
|
|
113
|
+
throw new ScreencastError("Signing in needs a person at the keyboard", "NEEDS_HUMAN", [
|
|
114
|
+
"Pass `--interactive` to open a browser window for them to sign in",
|
|
115
|
+
"The window has to appear on a screen someone is actually looking at",
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
if (!hasDisplay()) {
|
|
119
|
+
throw new ScreencastError("No display to open a browser window on", "NO_DISPLAY", [
|
|
120
|
+
"Ask the user to run this on their own machine:",
|
|
121
|
+
` npx -y screencast-axi auth login --interactive --base-url ${authCtx.baseUrl}`,
|
|
122
|
+
"Or produce a session file there and point `storageStateAuth` at it",
|
|
123
|
+
]);
|
|
124
|
+
}
|
|
125
|
+
if (!config.browser.profileDir) {
|
|
126
|
+
throw new ScreencastError("No profile directory to save the session in", "CONFIG_MISSING", [
|
|
127
|
+
"Set `browser.profileDir` in screencast.config.ts, e.g. `.screencast/profile`",
|
|
128
|
+
"The profile is what remembers the session between takes - add it to .gitignore",
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
await mkdir(config.browser.profileDir, { recursive: true });
|
|
132
|
+
const opened = await openContext({
|
|
133
|
+
resolved: viewport,
|
|
134
|
+
headless: false,
|
|
135
|
+
args: config.browser.args,
|
|
136
|
+
profileDir: config.browser.profileDir,
|
|
137
|
+
});
|
|
138
|
+
try {
|
|
139
|
+
const waitMs = flags["wait"] ? parseDuration(flags["wait"]) : 5 * 60_000;
|
|
140
|
+
// Immediately, and to stderr: a window has appeared somewhere and the
|
|
141
|
+
// process is now waiting on a human. Silence here reads as a hang.
|
|
142
|
+
process.stderr.write(`A browser window is open at ${authCtx.baseUrl}.\n` +
|
|
143
|
+
`Sign in, then close the window. Waiting up to ${Math.round(waitMs / 60_000)} minutes.\n`);
|
|
144
|
+
await withTimeout(strategy.interactiveLogin(opened.context, opened.page, authCtx), waitMs, authCtx.baseUrl);
|
|
145
|
+
const savePath = flags["save-state"];
|
|
146
|
+
let saved;
|
|
147
|
+
if (savePath) {
|
|
148
|
+
saved = isAbsolute(savePath) ? savePath : resolve(config.rootDir, savePath);
|
|
149
|
+
await mkdir(dirname(saved), { recursive: true });
|
|
150
|
+
await opened.context.storageState({ path: saved });
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
"signed in": strategy.name,
|
|
154
|
+
profile: config.browser.profileDir,
|
|
155
|
+
...(saved ? { storage_state: saved } : {}),
|
|
156
|
+
help: [
|
|
157
|
+
"Check it took: `screencast-axi auth check`",
|
|
158
|
+
"The session lives in the profile, so every take reuses it until it expires",
|
|
159
|
+
...(saved ? [] : ["Add `--save-state <path>` to also write a portable session file"]),
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
await opened.close().catch(() => undefined);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** Reports whether the saved session still gets past the login. */
|
|
168
|
+
async function check(config, strategy, viewport, authCtx, flags) {
|
|
169
|
+
await strategy.preflight?.(authCtx);
|
|
170
|
+
const patch = strategy.prepareContext?.(authCtx) ?? {};
|
|
171
|
+
const opened = await openContext({
|
|
172
|
+
resolved: viewport,
|
|
173
|
+
headless: flags["headed"] !== true,
|
|
174
|
+
args: config.browser.args,
|
|
175
|
+
...(config.browser.profileDir ? { profileDir: config.browser.profileDir } : {}),
|
|
176
|
+
...(patch.storageState ? { storageState: patch.storageState } : {}),
|
|
177
|
+
...(patch.httpCredentials ? { httpCredentials: patch.httpCredentials } : {}),
|
|
178
|
+
});
|
|
179
|
+
try {
|
|
180
|
+
// Open the site first. A strategy that only patches the context - basic
|
|
181
|
+
// auth, a storage state - never navigates on its own, and reporting
|
|
182
|
+
// `landed: about:blank` next to "signed in: true" tells nobody anything.
|
|
183
|
+
// A strategy that does navigate (to verify) simply moves on from here.
|
|
184
|
+
await opened.page.goto(authCtx.baseUrl, { waitUntil: "domcontentloaded" });
|
|
185
|
+
const identity = await strategy.signIn?.(opened.page, authCtx);
|
|
186
|
+
await strategy.assertSignedIn?.(opened.page, authCtx);
|
|
187
|
+
const shot = resolve(config.rawDir, "auth-check.png");
|
|
188
|
+
await mkdir(config.rawDir, { recursive: true });
|
|
189
|
+
await opened.page.screenshot({ path: shot }).catch(() => undefined);
|
|
190
|
+
return {
|
|
191
|
+
"signed in": true,
|
|
192
|
+
strategy: strategy.name,
|
|
193
|
+
...(identity ? { as: identity.label } : {}),
|
|
194
|
+
landed: opened.page.url(),
|
|
195
|
+
screenshot: shot,
|
|
196
|
+
...(strategy.describe ? { config: strategy.describe() } : {}),
|
|
197
|
+
help: [
|
|
198
|
+
"Looks good. Record with `screencast-axi record <id>`",
|
|
199
|
+
"Open the screenshot if the landed URL is not what you expected",
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await opened.close().catch(() => undefined);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type FlagSpecs } from "../flags.js";
|
|
2
|
+
import type { AxiStructuredOutput } from "../output.js";
|
|
3
|
+
export declare const CHECK_FLAGS: FlagSpecs;
|
|
4
|
+
/**
|
|
5
|
+
* Does the clip library hang together?
|
|
6
|
+
*
|
|
7
|
+
* The browser-free half of verifying a set of screencasts: manifest against
|
|
8
|
+
* scenarios against the files on disk. Everything a page-level audit would
|
|
9
|
+
* also check needs a browser and a built site, and belongs in whatever builds
|
|
10
|
+
* that site - this part does not, and runs in milliseconds.
|
|
11
|
+
*/
|
|
12
|
+
export declare function checkCommand(args: string[]): Promise<AxiStructuredOutput>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
import { buildInventory } from "../inventory.js";
|
|
5
|
+
import { parseFlags } from "../flags.js";
|
|
6
|
+
import { readManifest, writeManifest } from "../manifest.js";
|
|
7
|
+
export const CHECK_FLAGS = {
|
|
8
|
+
config: { kind: "string", description: "Path to a config file", placeholder: "path" },
|
|
9
|
+
"fix-orphans": {
|
|
10
|
+
kind: "boolean",
|
|
11
|
+
description: "Delete manifest entries and media with no scenario behind them",
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Does the clip library hang together?
|
|
16
|
+
*
|
|
17
|
+
* The browser-free half of verifying a set of screencasts: manifest against
|
|
18
|
+
* scenarios against the files on disk. Everything a page-level audit would
|
|
19
|
+
* also check needs a browser and a built site, and belongs in whatever builds
|
|
20
|
+
* that site - this part does not, and runs in milliseconds.
|
|
21
|
+
*/
|
|
22
|
+
export async function checkCommand(args) {
|
|
23
|
+
const { flags } = parseFlags(args, CHECK_FLAGS);
|
|
24
|
+
const config = await loadConfig(flags["config"]);
|
|
25
|
+
const inventory = await buildInventory(config);
|
|
26
|
+
const failures = [];
|
|
27
|
+
for (const p of inventory.problems) {
|
|
28
|
+
failures.push({
|
|
29
|
+
problem: "manifest entry is invalid",
|
|
30
|
+
detail: p.index >= 0 ? `entry ${p.index}: ${p.reason}` : p.reason,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
for (const row of inventory.rows) {
|
|
34
|
+
if (row.status === "incomplete") {
|
|
35
|
+
failures.push({ problem: `${row.id} is missing files`, detail: row.missing.join(", ") });
|
|
36
|
+
}
|
|
37
|
+
if (row.status === "stale") {
|
|
38
|
+
failures.push({ problem: `${row.id} is stale`, detail: row.staleReason ?? "changed" });
|
|
39
|
+
}
|
|
40
|
+
if (row.status === "never-recorded") {
|
|
41
|
+
failures.push({ problem: `${row.id} has never been recorded`, detail: row.file });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const orphan of inventory.orphans) {
|
|
45
|
+
failures.push({
|
|
46
|
+
problem: `${orphan.id} has no scenario`,
|
|
47
|
+
detail: "in the manifest, but nothing in the config produces it any more",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (const stray of inventory.strays) {
|
|
51
|
+
failures.push({
|
|
52
|
+
problem: `${stray} is not in the manifest`,
|
|
53
|
+
detail: "left over from a rename or a deleted scenario",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (flags["fix-orphans"] === true &&
|
|
57
|
+
(inventory.orphans.length > 0 || inventory.strays.length > 0)) {
|
|
58
|
+
const removed = [];
|
|
59
|
+
const { entries } = readManifest(config.outDir);
|
|
60
|
+
const keep = entries.filter((e) => !inventory.orphans.some((o) => o.id === e.id));
|
|
61
|
+
if (keep.length !== entries.length) {
|
|
62
|
+
writeManifest(config.outDir, keep);
|
|
63
|
+
removed.push(...inventory.orphans.map((o) => `${o.id} (manifest entry)`));
|
|
64
|
+
}
|
|
65
|
+
for (const orphan of inventory.orphans) {
|
|
66
|
+
for (const ext of orphan.formats ?? ["mp4", "webm", "webp"]) {
|
|
67
|
+
const file = join(config.outDir, `${orphan.id}.${ext}`);
|
|
68
|
+
await rm(file, { force: true });
|
|
69
|
+
removed.push(`${orphan.id}.${ext}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const stray of inventory.strays) {
|
|
73
|
+
await rm(join(config.outDir, stray), { force: true });
|
|
74
|
+
removed.push(stray);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
removed,
|
|
78
|
+
totals: `${removed.length} removed`,
|
|
79
|
+
help: ["Run `screencast-axi check` again to confirm the library is clean"],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (failures.length === 0) {
|
|
83
|
+
return {
|
|
84
|
+
checked: inventory.rows.length,
|
|
85
|
+
result: "consistent",
|
|
86
|
+
totals: `${inventory.rows.length} scenarios, manifest and files all agree`,
|
|
87
|
+
help: ["Nothing to do"],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
failures,
|
|
92
|
+
totals: `${failures.length} problem(s) across ${inventory.rows.length} scenarios`,
|
|
93
|
+
help: [
|
|
94
|
+
...(inventory.rows.some((r) => r.status !== "recorded")
|
|
95
|
+
? ["`screencast-axi record --all --if-changed` re-shoots what has drifted"]
|
|
96
|
+
: []),
|
|
97
|
+
...(inventory.orphans.length + inventory.strays.length > 0
|
|
98
|
+
? ["`screencast-axi check --fix-orphans` deletes what no scenario claims"]
|
|
99
|
+
: []),
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/commands/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type FlagSpecs } from "../flags.js";
|
|
2
|
+
import type { AxiStructuredOutput } from "../output.js";
|
|
3
|
+
import { run } from "../toolchain.js";
|
|
4
|
+
export declare const DOCTOR_FLAGS: FlagSpecs;
|
|
5
|
+
/**
|
|
6
|
+
* Everything that has to be true before a take can run.
|
|
7
|
+
*
|
|
8
|
+
* The point is to answer all of it at once. A missing ffmpeg discovered
|
|
9
|
+
* partway through a forty-second recording is the same information delivered
|
|
10
|
+
* at the worst possible moment, and each prerequisite found one at a time is a
|
|
11
|
+
* separate round trip.
|
|
12
|
+
*/
|
|
13
|
+
export declare function doctorCommand(args: string[]): Promise<AxiStructuredOutput>;
|
|
14
|
+
/** Exposed for `setup`, which needs the same probe. */
|
|
15
|
+
export { run };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { access, constants, mkdir } from "node:fs/promises";
|
|
2
|
+
import { loadConfig, resolveConfigPath } from "../config.js";
|
|
3
|
+
import { parseFlags } from "../flags.js";
|
|
4
|
+
import { detectToolchain, installHint, run } from "../toolchain.js";
|
|
5
|
+
import { resolvePlaywright } from "../browser.js";
|
|
6
|
+
export const DOCTOR_FLAGS = {
|
|
7
|
+
config: { kind: "string", description: "Path to a config file", placeholder: "path" },
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Everything that has to be true before a take can run.
|
|
11
|
+
*
|
|
12
|
+
* The point is to answer all of it at once. A missing ffmpeg discovered
|
|
13
|
+
* partway through a forty-second recording is the same information delivered
|
|
14
|
+
* at the worst possible moment, and each prerequisite found one at a time is a
|
|
15
|
+
* separate round trip.
|
|
16
|
+
*/
|
|
17
|
+
export async function doctorCommand(args) {
|
|
18
|
+
const { flags } = parseFlags(args, DOCTOR_FLAGS);
|
|
19
|
+
const findings = [];
|
|
20
|
+
findings.push({
|
|
21
|
+
what: "node",
|
|
22
|
+
ok: Number(process.versions.node.split(".")[0]) >= 20,
|
|
23
|
+
detail: process.versions.node,
|
|
24
|
+
...(Number(process.versions.node.split(".")[0]) >= 20
|
|
25
|
+
? {}
|
|
26
|
+
: { fix: "Upgrade to Node 20 or newer" }),
|
|
27
|
+
});
|
|
28
|
+
let playwright = null;
|
|
29
|
+
try {
|
|
30
|
+
const { specifier } = await resolvePlaywright();
|
|
31
|
+
playwright = specifier;
|
|
32
|
+
findings.push({ what: "playwright", ok: true, detail: `resolved from \`${specifier}\`` });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
findings.push({
|
|
36
|
+
what: "playwright",
|
|
37
|
+
ok: false,
|
|
38
|
+
detail: "not installed",
|
|
39
|
+
fix: "pnpm add -D playwright",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (playwright) {
|
|
43
|
+
// Launching is the only honest check: the package can be installed while
|
|
44
|
+
// the browser binary it needs has never been downloaded.
|
|
45
|
+
try {
|
|
46
|
+
const { module } = await resolvePlaywright();
|
|
47
|
+
const browser = await module.chromium.launch();
|
|
48
|
+
const version = browser.version?.() ?? "ok";
|
|
49
|
+
await browser.close();
|
|
50
|
+
findings.push({ what: "chromium", ok: true, detail: String(version) });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
findings.push({
|
|
54
|
+
what: "chromium",
|
|
55
|
+
ok: false,
|
|
56
|
+
detail: error.message.split("\n")[0] ?? "will not launch",
|
|
57
|
+
fix: "screencast-axi setup",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const toolchain = await detectToolchain();
|
|
62
|
+
findings.push({
|
|
63
|
+
what: "ffmpeg",
|
|
64
|
+
ok: toolchain.ffmpeg !== null,
|
|
65
|
+
detail: toolchain.ffmpeg
|
|
66
|
+
? `${toolchain.ffmpeg.version.replace(/^ffmpeg version /, "").split(" ")[0]} (${toolchain.ffmpeg.source})`
|
|
67
|
+
: "not found",
|
|
68
|
+
...(toolchain.ffmpeg ? {} : { fix: installHint("ffmpeg") }),
|
|
69
|
+
});
|
|
70
|
+
findings.push({
|
|
71
|
+
what: "poster encoder",
|
|
72
|
+
ok: true,
|
|
73
|
+
detail: toolchain.posterEncoder === "png"
|
|
74
|
+
? "PNG fallback - neither ffmpeg's libwebp nor cwebp is available"
|
|
75
|
+
: `WebP via ${toolchain.posterEncoder}`,
|
|
76
|
+
...(toolchain.posterEncoder === "png" ? { fix: installHint("cwebp") } : {}),
|
|
77
|
+
});
|
|
78
|
+
findings.push({
|
|
79
|
+
what: "animated webp",
|
|
80
|
+
ok: true,
|
|
81
|
+
detail: toolchain.gif2webp ? "available via gif2webp" : "unavailable - `--webp` will fail",
|
|
82
|
+
...(toolchain.gif2webp ? {} : { fix: installHint("cwebp") }),
|
|
83
|
+
});
|
|
84
|
+
const configPath = resolveConfigPath(flags["config"]);
|
|
85
|
+
findings.push({
|
|
86
|
+
what: "config",
|
|
87
|
+
ok: true,
|
|
88
|
+
detail: configPath ?? "none - defaults apply, which is fine for a one-off",
|
|
89
|
+
});
|
|
90
|
+
if (configPath) {
|
|
91
|
+
const config = await loadConfig(flags["config"]);
|
|
92
|
+
let writable = true;
|
|
93
|
+
try {
|
|
94
|
+
await mkdir(config.outDir, { recursive: true });
|
|
95
|
+
await access(config.outDir, constants.W_OK);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
writable = false;
|
|
99
|
+
}
|
|
100
|
+
findings.push({
|
|
101
|
+
what: "output directory",
|
|
102
|
+
ok: writable,
|
|
103
|
+
detail: writable ? config.outDir : `${config.outDir} is not writable`,
|
|
104
|
+
...(writable ? {} : { fix: `Check permissions on ${config.outDir}` }),
|
|
105
|
+
});
|
|
106
|
+
findings.push({
|
|
107
|
+
what: "scenarios",
|
|
108
|
+
ok: true,
|
|
109
|
+
detail: config.scenarios.length > 0 ? config.scenarios.join(", ") : "none configured",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const broken = findings.filter((f) => !f.ok);
|
|
113
|
+
const fixes = findings.filter((f) => f.fix).map((f) => `${f.what}: ${f.fix}`);
|
|
114
|
+
return {
|
|
115
|
+
ready: broken.length === 0,
|
|
116
|
+
checks: findings.map((f) => ({
|
|
117
|
+
what: f.what,
|
|
118
|
+
ok: f.ok,
|
|
119
|
+
detail: f.detail,
|
|
120
|
+
})),
|
|
121
|
+
totals: broken.length === 0
|
|
122
|
+
? `${findings.length} checks, all clear`
|
|
123
|
+
: `${broken.length} of ${findings.length} checks need attention`,
|
|
124
|
+
help: fixes.length > 0
|
|
125
|
+
? fixes
|
|
126
|
+
: ["Everything a recording needs is in place. `screencast-axi record <id>`"],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Exposed for `setup`, which needs the same probe. */
|
|
130
|
+
export { run };
|
|
131
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type FlagSpecs } from "../flags.js";
|
|
2
|
+
import type { AxiStructuredOutput } from "../output.js";
|
|
3
|
+
/** No flags: it takes a topic and nothing else. */
|
|
4
|
+
export declare const GUIDE_FLAGS: FlagSpecs;
|
|
5
|
+
export declare function guideCommand(args: string[]): AxiStructuredOutput;
|
|
6
|
+
export declare function guideHelp(): string;
|