astroshot 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -0
- package/bin/astroshot.mjs +71 -0
- package/node_modules/@archastro/astroshot/LICENSE +21 -0
- package/node_modules/@archastro/astroshot/README.md +96 -0
- package/node_modules/@archastro/astroshot/bin/astroshot.mjs +276 -0
- package/node_modules/@archastro/astroshot/bin/demo.mjs +275 -0
- package/node_modules/@archastro/astroshot/bin/doctor.mjs +492 -0
- package/node_modules/@archastro/astroshot/bin/mac-preferences.mjs +346 -0
- package/node_modules/@archastro/astroshot/bin/templates.mjs +186 -0
- package/node_modules/@archastro/astroshot/fixtures/demo/fixtures.json +42 -0
- package/node_modules/@archastro/astroshot/fixtures/demo/journey.png +0 -0
- package/node_modules/@archastro/astroshot/fixtures/demo/journey.webm +0 -0
- package/node_modules/@archastro/astroshot/fixtures/demo/next-steps.png +0 -0
- package/node_modules/@archastro/astroshot/fixtures/demo/welcome.png +0 -0
- package/node_modules/@archastro/astroshot/ink.d.ts +5 -0
- package/node_modules/@archastro/astroshot/ink.js +1 -0
- package/node_modules/@archastro/astroshot/package.json +79 -0
- package/node_modules/@archastro/astroshot/pty.d.ts +8 -0
- package/node_modules/@archastro/astroshot/pty.js +1 -0
- package/node_modules/@archastro/astroshot/react.d.ts +1 -0
- package/node_modules/@archastro/astroshot/react.js +1 -0
- package/node_modules/@archastro/astroshot/tui.d.ts +1 -0
- package/node_modules/@archastro/astroshot/tui.js +1 -0
- package/node_modules/@archastro/movie-harness/README.md +138 -0
- package/node_modules/@archastro/movie-harness/bin/astroshot-movie.mjs +5 -0
- package/node_modules/@archastro/movie-harness/dist/cli.d.ts +1 -0
- package/node_modules/@archastro/movie-harness/dist/cli.js +389 -0
- package/node_modules/@archastro/movie-harness/dist/encode.d.ts +14 -0
- package/node_modules/@archastro/movie-harness/dist/encode.js +184 -0
- package/node_modules/@archastro/movie-harness/dist/index.d.ts +14 -0
- package/node_modules/@archastro/movie-harness/dist/index.js +11 -0
- package/node_modules/@archastro/movie-harness/dist/paths.d.ts +9 -0
- package/node_modules/@archastro/movie-harness/dist/paths.js +57 -0
- package/node_modules/@archastro/movie-harness/dist/png.d.ts +8 -0
- package/node_modules/@archastro/movie-harness/dist/png.js +79 -0
- package/node_modules/@archastro/movie-harness/dist/session.d.ts +45 -0
- package/node_modules/@archastro/movie-harness/dist/session.js +170 -0
- package/node_modules/@archastro/movie-harness/dist/sink.d.ts +7 -0
- package/node_modules/@archastro/movie-harness/dist/sink.js +113 -0
- package/node_modules/@archastro/movie-harness/dist/source-help.d.ts +29 -0
- package/node_modules/@archastro/movie-harness/dist/source-help.js +222 -0
- package/node_modules/@archastro/movie-harness/dist/sources/browser.d.ts +7 -0
- package/node_modules/@archastro/movie-harness/dist/sources/browser.js +87 -0
- package/node_modules/@archastro/movie-harness/dist/sources/desktop-macos.d.ts +110 -0
- package/node_modules/@archastro/movie-harness/dist/sources/desktop-macos.js +505 -0
- package/node_modules/@archastro/movie-harness/dist/sources/frames-store.d.ts +19 -0
- package/node_modules/@archastro/movie-harness/dist/sources/frames-store.js +165 -0
- package/node_modules/@archastro/movie-harness/dist/sources/pty.d.ts +15 -0
- package/node_modules/@archastro/movie-harness/dist/sources/pty.js +330 -0
- package/node_modules/@archastro/movie-harness/dist/terminal-paint.d.ts +27 -0
- package/node_modules/@archastro/movie-harness/dist/terminal-paint.js +190 -0
- package/node_modules/@archastro/movie-harness/dist/types.d.ts +140 -0
- package/node_modules/@archastro/movie-harness/dist/types.js +1 -0
- package/node_modules/@archastro/movie-harness/native/macos/WindowTools.swift +164 -0
- package/node_modules/@archastro/movie-harness/package.json +67 -0
- package/node_modules/@archastro/react-shot/LICENSE +21 -0
- package/node_modules/@archastro/react-shot/README.md +181 -0
- package/node_modules/@archastro/react-shot/bin/react-shot.mjs +2 -0
- package/node_modules/@archastro/react-shot/dist/batch-paths.d.ts +4 -0
- package/node_modules/@archastro/react-shot/dist/batch-paths.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/batch-paths.js +34 -0
- package/node_modules/@archastro/react-shot/dist/batch-paths.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/cli.d.ts +3 -0
- package/node_modules/@archastro/react-shot/dist/cli.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/cli.js +217 -0
- package/node_modules/@archastro/react-shot/dist/cli.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/config.d.ts +5 -0
- package/node_modules/@archastro/react-shot/dist/config.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/config.js +75 -0
- package/node_modules/@archastro/react-shot/dist/config.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/create-server.d.ts +13 -0
- package/node_modules/@archastro/react-shot/dist/create-server.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/create-server.js +254 -0
- package/node_modules/@archastro/react-shot/dist/create-server.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/index.d.ts +4 -0
- package/node_modules/@archastro/react-shot/dist/index.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/index.js +3 -0
- package/node_modules/@archastro/react-shot/dist/index.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/meta.d.ts +9 -0
- package/node_modules/@archastro/react-shot/dist/meta.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/meta.js +23 -0
- package/node_modules/@archastro/react-shot/dist/meta.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/shot.d.ts +4 -0
- package/node_modules/@archastro/react-shot/dist/shot.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/shot.js +259 -0
- package/node_modules/@archastro/react-shot/dist/shot.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/stubs.d.ts +6 -0
- package/node_modules/@archastro/react-shot/dist/stubs.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/stubs.js +49 -0
- package/node_modules/@archastro/react-shot/dist/stubs.js.map +1 -0
- package/node_modules/@archastro/react-shot/dist/types.d.ts +79 -0
- package/node_modules/@archastro/react-shot/dist/types.d.ts.map +1 -0
- package/node_modules/@archastro/react-shot/dist/types.js +2 -0
- package/node_modules/@archastro/react-shot/dist/types.js.map +1 -0
- package/node_modules/@archastro/react-shot/host/index.html +22 -0
- package/node_modules/@archastro/react-shot/package.json +81 -0
- package/node_modules/@archastro/tui-shot/LICENSE +21 -0
- package/node_modules/@archastro/tui-shot/README.md +145 -0
- package/node_modules/@archastro/tui-shot/bin/tui-shot.mjs +23 -0
- package/node_modules/@archastro/tui-shot/dist/batch-paths.d.ts +3 -0
- package/node_modules/@archastro/tui-shot/dist/batch-paths.js +33 -0
- package/node_modules/@archastro/tui-shot/dist/cli.d.ts +2 -0
- package/node_modules/@archastro/tui-shot/dist/cli.js +224 -0
- package/node_modules/@archastro/tui-shot/dist/index.d.ts +3 -0
- package/node_modules/@archastro/tui-shot/dist/index.js +2 -0
- package/node_modules/@archastro/tui-shot/dist/pty-exit-wrapper.d.ts +1 -0
- package/node_modules/@archastro/tui-shot/dist/pty-exit-wrapper.js +50 -0
- package/node_modules/@archastro/tui-shot/dist/pty-shot.d.ts +2 -0
- package/node_modules/@archastro/tui-shot/dist/pty-shot.js +483 -0
- package/node_modules/@archastro/tui-shot/dist/render-ink.d.ts +10 -0
- package/node_modules/@archastro/tui-shot/dist/render-ink.js +87 -0
- package/node_modules/@archastro/tui-shot/dist/shot.d.ts +24 -0
- package/node_modules/@archastro/tui-shot/dist/shot.js +250 -0
- package/node_modules/@archastro/tui-shot/dist/terminal-html.d.ts +14 -0
- package/node_modules/@archastro/tui-shot/dist/terminal-html.js +144 -0
- package/node_modules/@archastro/tui-shot/dist/types.d.ts +81 -0
- package/node_modules/@archastro/tui-shot/dist/types.js +1 -0
- package/node_modules/@archastro/tui-shot/package.json +90 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# `astroshot`
|
|
2
|
+
|
|
3
|
+
One command for deterministic React, Ink, and arbitrary terminal screenshots —
|
|
4
|
+
plus **journey movies** into `.astroshot/`.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx astroshot --help
|
|
8
|
+
npx astroshot init react
|
|
9
|
+
npx astroshot react ./react.shot.tsx -o ./react.png
|
|
10
|
+
npx astroshot ink ./ink.shot.tsx -o ./ink.png
|
|
11
|
+
npx astroshot pty ./pty.shot.yaml -o ./terminal.png
|
|
12
|
+
npx astroshot movie which-source "ratatui truecolor dashboard"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
No registry flags, no scope configuration, no `--registry` override.
|
|
16
|
+
|
|
17
|
+
## What this package is
|
|
18
|
+
|
|
19
|
+
`astroshot` is the public, unscoped entry point for
|
|
20
|
+
[`@archastro/astroshot`](https://www.npmjs.com/package/@archastro/astroshot).
|
|
21
|
+
It ships the unified CLI and all three capture engines
|
|
22
|
+
(`@archastro/react-shot`, `@archastro/tui-shot`, `@archastro/movie-harness`)
|
|
23
|
+
*inside its own tarball* using npm `bundleDependencies`.
|
|
24
|
+
|
|
25
|
+
That matters because many developers have a `~/.npmrc` that maps the whole
|
|
26
|
+
`@archastro` scope to a private registry:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
@archastro:registry=https://npm.pkg.github.com
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
With that config, `npx @archastro/astroshot` fails with **E404** — npm never
|
|
33
|
+
asks the public registry for the package at all. Because this package bundles
|
|
34
|
+
everything scoped, nothing scoped is fetched at install time, so a plain
|
|
35
|
+
`npx astroshot` works regardless of scope configuration.
|
|
36
|
+
|
|
37
|
+
The scoped packages remain fully supported and unchanged; use them directly if
|
|
38
|
+
you prefer, or if you already have the scope pointed at the public registry.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# one-off
|
|
44
|
+
npx astroshot --help
|
|
45
|
+
|
|
46
|
+
# project dev dependency
|
|
47
|
+
npm install --save-dev astroshot
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Install the shared Chromium runtime once before browser-backed captures:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx astroshot install-browser
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
On Linux CI images that also need Chromium's system libraries, add
|
|
57
|
+
`--with-deps`.
|
|
58
|
+
|
|
59
|
+
## Peer dependencies you supply
|
|
60
|
+
|
|
61
|
+
This package deliberately does **not** pin your framework versions. Install the
|
|
62
|
+
peers for the modes you use:
|
|
63
|
+
|
|
64
|
+
| Mode | Peers |
|
|
65
|
+
|------|-------|
|
|
66
|
+
| `astroshot react` | `react`, `react-dom` (>=18) |
|
|
67
|
+
| `astroshot ink` | `ink@^7.1`, `react@^19` |
|
|
68
|
+
| `astroshot pty`, `astroshot movie` | none |
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install --save-dev ink@^7.1 react@^19
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`node-pty` is an **optional** dependency. PTY and movie-PTY capture need it;
|
|
75
|
+
every other mode works without it, so an environment that cannot build the
|
|
76
|
+
native addon still installs successfully.
|
|
77
|
+
|
|
78
|
+
## Documentation
|
|
79
|
+
|
|
80
|
+
Full fixture APIs, the PTY action contract, manifest formats, and movie sources
|
|
81
|
+
are documented in the
|
|
82
|
+
[repository README](https://github.com/ArchAstro/astroshots#readme) and in
|
|
83
|
+
[`@archastro/astroshot`](https://www.npmjs.com/package/@archastro/astroshot).
|
|
84
|
+
|
|
85
|
+
Fixtures, imported modules, and PTY commands execute with the current user's
|
|
86
|
+
permissions. Review untrusted files before capture and never include
|
|
87
|
+
credentials or private customer data in fixtures or generated images.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Unscoped `astroshot` entry point.
|
|
4
|
+
*
|
|
5
|
+
* This package exists so `npx astroshot ...` works with no registry flags. The
|
|
6
|
+
* @archastro packages ship *inside* this tarball through bundleDependencies, so
|
|
7
|
+
* a developer whose ~/.npmrc maps @archastro to a private registry can still
|
|
8
|
+
* install and run the CLI. See docs/UNSCOPED-CLI-DESIGN.md.
|
|
9
|
+
*
|
|
10
|
+
* The only job of this file is to hand every argument to the real CLI and
|
|
11
|
+
* faithfully return its stdout, stderr, exit code, and terminating signal.
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import process from "node:process";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
|
|
19
|
+
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
20
|
+
const CLI_RELATIVE_PATH = path.join(
|
|
21
|
+
"@archastro",
|
|
22
|
+
"astroshot",
|
|
23
|
+
"bin",
|
|
24
|
+
"astroshot.mjs",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Look for the bundled CLI next to this package first (the published layout
|
|
29
|
+
* puts it in ./node_modules), then walk up through parent node_modules
|
|
30
|
+
* directories so the workspace checkout resolves its symlinked sibling.
|
|
31
|
+
*/
|
|
32
|
+
function resolveCli() {
|
|
33
|
+
const searched = [];
|
|
34
|
+
let directory = packageRoot;
|
|
35
|
+
for (;;) {
|
|
36
|
+
const candidate = path.join(directory, "node_modules", CLI_RELATIVE_PATH);
|
|
37
|
+
searched.push(candidate);
|
|
38
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
39
|
+
const parent = path.dirname(directory);
|
|
40
|
+
if (parent === directory) break;
|
|
41
|
+
directory = parent;
|
|
42
|
+
}
|
|
43
|
+
return { searched };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const cli = resolveCli();
|
|
47
|
+
if (typeof cli !== "string") {
|
|
48
|
+
console.error(
|
|
49
|
+
"astroshot: the bundled @archastro/astroshot CLI is missing from this " +
|
|
50
|
+
"installation. Reinstall with `npm install astroshot`.\nLooked in:\n" +
|
|
51
|
+
cli.searched.map((entry) => ` ${entry}`).join("\n"),
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// stdio: "inherit" hands the real file descriptors to the CLI, so stdout and
|
|
57
|
+
// stderr stay unbuffered, interleaved, and TTY-aware exactly as if the user had
|
|
58
|
+
// run @archastro/astroshot directly.
|
|
59
|
+
const result = spawnSync(process.execPath, [cli, ...process.argv.slice(2)], {
|
|
60
|
+
stdio: "inherit",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (result.error) {
|
|
64
|
+
console.error(`astroshot could not start the CLI: ${result.error.message}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
// Re-raise the child's signal so `kill`/Ctrl-C semantics survive the hop.
|
|
68
|
+
if (result.signal) {
|
|
69
|
+
process.kill(process.pid, result.signal);
|
|
70
|
+
}
|
|
71
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ArchAstro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# `@archastro/astroshot`
|
|
2
|
+
|
|
3
|
+
One command for deterministic React, Ink, and arbitrary terminal screenshots —
|
|
4
|
+
plus **journey movies** into `.astroshot/`.
|
|
5
|
+
|
|
6
|
+
## Start here (no prerequisites)
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Write a real .astroshot/ set: stills + movie poster/video + manifest.json.
|
|
10
|
+
# No Chromium download, no assets of your own; works with the app closed.
|
|
11
|
+
npx astroshot demo
|
|
12
|
+
|
|
13
|
+
# Check Node, watched folders, app install/run state, Chromium, and macOS
|
|
14
|
+
# Screen Recording. Each failure prints the exact fix command. Read-only.
|
|
15
|
+
npx astroshot doctor
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`demo` accepts `--feature <name>`, `--root <dir>`, and `--json`. `doctor`
|
|
19
|
+
accepts `--root <dir>`, `--json`, and `--skip-screen`, and exits non-zero when a
|
|
20
|
+
required check fails. Watched-folder coverage comes from the Astroshots app's
|
|
21
|
+
own live configuration, so an "empty tray" resolves to one of: first-launch
|
|
22
|
+
setup never completed, this project is outside every watched folder, or the
|
|
23
|
+
project is watched and the problem is elsewhere.
|
|
24
|
+
|
|
25
|
+
## Capture
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx astroshot init react
|
|
29
|
+
npx astroshot init ink
|
|
30
|
+
npx astroshot init pty
|
|
31
|
+
|
|
32
|
+
npx astroshot react ./react.shot.tsx -o ./react.png
|
|
33
|
+
npx astroshot ink ./ink.shot.tsx -o ./ink.png
|
|
34
|
+
npx astroshot pty ./pty.shot.yaml -o ./terminal.png
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Movies (`astroshot movie`)
|
|
38
|
+
|
|
39
|
+
Same binary. Agents: **run `astroshot movie which-source "…"` first**.
|
|
40
|
+
|
|
41
|
+
| You need to record… | `--source` |
|
|
42
|
+
|---------------------|------------|
|
|
43
|
+
| Web / SPA / agent-browser | `browser` |
|
|
44
|
+
| TUI / CLI / truecolor terminal | `pty` (never desktop of Terminal.app) |
|
|
45
|
+
| Native macOS app window | `desktop.window` |
|
|
46
|
+
| Your own PNG sequence | `frames` |
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
astroshot movie --help
|
|
50
|
+
astroshot movie which-source "ratatui truecolor dashboard"
|
|
51
|
+
astroshot movie run --source browser --feature web --slug home --url https://example.com
|
|
52
|
+
astroshot movie run --source desktop.window --feature app --slug onboard \
|
|
53
|
+
--bundle-id com.example.App --duration-ms 4000
|
|
54
|
+
astroshot movie list-windows # macOS
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`desktop.window` uses macOS `/usr/sbin/screencapture` (already on the system)
|
|
58
|
+
plus a Swift window list shipped in the package — no separate capture binary
|
|
59
|
+
download. Requires Screen Recording permission for your terminal/IDE.
|
|
60
|
+
|
|
61
|
+
Use `react` for isolated browser components, `ink` for in-process Ink fixture
|
|
62
|
+
trees, and `pty` for executable terminal applications such as Ratatui, Bubble
|
|
63
|
+
Tea, Textual, and curses programs. `tui` remains an alias for `ink` for
|
|
64
|
+
compatibility.
|
|
65
|
+
|
|
66
|
+
Ink fixtures require project-local peers:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install --save-dev ink@^7.1 react@^19
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Install the shared Chromium runtime once:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx astroshot install-browser
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Use `react batch <manifest>` or `ink batch <manifest>` for maintained fixture
|
|
79
|
+
sets. Run `<mode> --help` for mode-specific options.
|
|
80
|
+
|
|
81
|
+
Fixture types are available from the unified package:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import type { ReactShotFixture } from "@archastro/astroshot/react";
|
|
85
|
+
import type { InkShotFixture } from "@archastro/astroshot/ink";
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
PTY YAML and JSON files launch `command` directly, without a shell. Their
|
|
89
|
+
`actions` can wait for visible text, send named keys or literal text, and
|
|
90
|
+
pause for bounded durations. Paths in `cwd` are relative to the fixture.
|
|
91
|
+
On Windows, point `command` at an `.exe`; `.cmd` and `.bat` files are rejected
|
|
92
|
+
because running them would introduce an implicit shell.
|
|
93
|
+
|
|
94
|
+
Fixtures, imported modules, and PTY commands execute with the current user's
|
|
95
|
+
permissions. Review untrusted files before capture and never include
|
|
96
|
+
credentials or private customer data in fixtures or generated images.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
import { writeFixtureTemplate } from "./templates.mjs";
|
|
9
|
+
import { demoHelp, runDemo } from "./demo.mjs";
|
|
10
|
+
import { doctorHelp, runDoctor } from "./doctor.mjs";
|
|
11
|
+
|
|
12
|
+
function help() {
|
|
13
|
+
console.log(`astroshot — one CLI for React, Ink, PTY stills, and movies
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
astroshot demo [--feature <name>] [--root <dir>]
|
|
17
|
+
astroshot doctor [--root <dir>] [--json]
|
|
18
|
+
astroshot init react [fixture.tsx] [--force]
|
|
19
|
+
astroshot init ink [fixture.tsx] [--force]
|
|
20
|
+
astroshot init pty [fixture.yaml] [--force]
|
|
21
|
+
astroshot react <fixture.tsx> -o <out.png> [options]
|
|
22
|
+
astroshot react shot <fixture.tsx> -o <out.png> [options]
|
|
23
|
+
astroshot react batch <manifest.yaml|json> [options]
|
|
24
|
+
astroshot ink <fixture.tsx> -o <out.png> [options]
|
|
25
|
+
astroshot ink batch <manifest.yaml|json> [options]
|
|
26
|
+
astroshot pty <fixture.yaml|json> -o <out.png> [options]
|
|
27
|
+
astroshot movie <command> [options]
|
|
28
|
+
astroshot install-browser [--with-deps]
|
|
29
|
+
|
|
30
|
+
Start here:
|
|
31
|
+
demo Write a complete .astroshot/ example set (no prerequisites)
|
|
32
|
+
doctor Check Node, watched folders, app, Chromium, permissions
|
|
33
|
+
|
|
34
|
+
Commands:
|
|
35
|
+
react Capture an isolated React component (still PNG)
|
|
36
|
+
ink Capture an Ink component fixture (still PNG)
|
|
37
|
+
pty Capture any executable in a pseudoterminal (still PNG)
|
|
38
|
+
movie Record a journey movie into .astroshot/ (poster + video)
|
|
39
|
+
init Generate a React, Ink, or PTY fixture template
|
|
40
|
+
install-browser Install the shared Chromium runtime
|
|
41
|
+
|
|
42
|
+
Movie sources (see "astroshot movie which-source"):
|
|
43
|
+
browser Web / agent-browser / Playwright viewport
|
|
44
|
+
pty Truecolor TUI/CLI (never screenshot Terminal.app)
|
|
45
|
+
desktop.window Native macOS app window (uses OS screencapture)
|
|
46
|
+
frames Push your own PNG/JPEG sequence
|
|
47
|
+
|
|
48
|
+
Compatibility: "astroshot tui" remains an alias for "astroshot ink".
|
|
49
|
+
Run "astroshot <mode> --help" for mode options.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function modeHelp(mode) {
|
|
53
|
+
if (mode === "react") {
|
|
54
|
+
console.log(`astroshot react — deterministic React component screenshots
|
|
55
|
+
|
|
56
|
+
Usage:
|
|
57
|
+
astroshot init react [fixture.tsx] [--force]
|
|
58
|
+
astroshot react <fixture.tsx> -o <out.png> [options]
|
|
59
|
+
astroshot react batch <manifest.yaml|json> [options]
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
-o, --out <path> Output PNG path
|
|
63
|
+
--root <dir> Package root for imports and aliases
|
|
64
|
+
--config <path> Fixture configuration path
|
|
65
|
+
--width <px> Override viewport width
|
|
66
|
+
--height <px> Override viewport height
|
|
67
|
+
--headed Show Chromium for debugging
|
|
68
|
+
-h, --help Show this help`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (mode === "ink") {
|
|
73
|
+
console.log(`astroshot ink — deterministic Ink component screenshots
|
|
74
|
+
|
|
75
|
+
Usage:
|
|
76
|
+
astroshot init ink [fixture.tsx] [--force]
|
|
77
|
+
astroshot ink <fixture.tsx> -o <out.png> [options]
|
|
78
|
+
astroshot ink batch <manifest.yaml|json> [options]
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
-o, --out <path> Output PNG path
|
|
82
|
+
--cols <count> Override terminal columns
|
|
83
|
+
--rows <count> Override terminal rows
|
|
84
|
+
--scale <factor> Override PNG device scale factor
|
|
85
|
+
--out-dir <path> Override batch output directory
|
|
86
|
+
--headed Show Chromium for debugging
|
|
87
|
+
-h, --help Show this help`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(`astroshot pty — screenshots of arbitrary terminal programs
|
|
92
|
+
|
|
93
|
+
Usage:
|
|
94
|
+
astroshot init pty [fixture.yaml] [--force]
|
|
95
|
+
astroshot pty <fixture.yaml|json> -o <out.png> [options]
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
-o, --out <path> Output PNG path
|
|
99
|
+
--cols <count> Override terminal columns
|
|
100
|
+
--rows <count> Override terminal rows
|
|
101
|
+
--scale <factor> Override PNG device scale factor
|
|
102
|
+
--headed Show Chromium for debugging
|
|
103
|
+
-h, --help Show this help`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function engineBin(mode) {
|
|
107
|
+
if (mode === "movie") {
|
|
108
|
+
const entry = fileURLToPath(import.meta.resolve("@archastro/movie-harness"));
|
|
109
|
+
// package exports "." → dist/index.js → package root is two levels up from dist
|
|
110
|
+
const packageRoot = path.dirname(path.dirname(entry));
|
|
111
|
+
return path.join(packageRoot, "bin", "astroshot-movie.mjs");
|
|
112
|
+
}
|
|
113
|
+
const packageName =
|
|
114
|
+
mode === "react" ? "@archastro/react-shot" : "@archastro/tui-shot";
|
|
115
|
+
const executable = mode === "react" ? "react-shot.mjs" : "tui-shot.mjs";
|
|
116
|
+
const entry = fileURLToPath(import.meta.resolve(packageName));
|
|
117
|
+
const packageRoot = path.dirname(path.dirname(entry));
|
|
118
|
+
return path.join(packageRoot, "bin", executable);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function runEngine(mode, arguments_) {
|
|
122
|
+
const engineMode = mode === "react" ? "react" : "tui";
|
|
123
|
+
const engineArguments =
|
|
124
|
+
mode === "pty" ? ["pty", ...arguments_] : arguments_;
|
|
125
|
+
const normalized =
|
|
126
|
+
mode !== "pty" &&
|
|
127
|
+
engineArguments[0] &&
|
|
128
|
+
/\.[cm]?tsx?$/.test(engineArguments[0])
|
|
129
|
+
? ["shot", ...engineArguments]
|
|
130
|
+
: engineArguments;
|
|
131
|
+
const result = spawnSync(
|
|
132
|
+
process.execPath,
|
|
133
|
+
[engineBin(engineMode), ...normalized],
|
|
134
|
+
{ stdio: "inherit" },
|
|
135
|
+
);
|
|
136
|
+
if (result.error) {
|
|
137
|
+
console.error(`astroshot could not start ${mode} capture: ${result.error.message}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
if (result.signal) process.kill(process.pid, result.signal);
|
|
141
|
+
process.exit(result.status ?? 1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function initHelp() {
|
|
145
|
+
console.log(`astroshot init — generate a fixture template
|
|
146
|
+
|
|
147
|
+
Usage:
|
|
148
|
+
astroshot init react [fixture.tsx] [--force]
|
|
149
|
+
astroshot init ink [fixture.tsx] [--force]
|
|
150
|
+
astroshot init pty [fixture.yaml] [--force]
|
|
151
|
+
|
|
152
|
+
Defaults:
|
|
153
|
+
react.shot.tsx
|
|
154
|
+
ink.shot.tsx
|
|
155
|
+
pty.shot.yaml
|
|
156
|
+
|
|
157
|
+
Existing files are never replaced unless --force is passed.`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function runInit(arguments_) {
|
|
161
|
+
if (
|
|
162
|
+
arguments_.length === 0 ||
|
|
163
|
+
arguments_[0] === "help" ||
|
|
164
|
+
arguments_[0] === "-h" ||
|
|
165
|
+
arguments_[0] === "--help"
|
|
166
|
+
) {
|
|
167
|
+
initHelp();
|
|
168
|
+
process.exit(arguments_.length === 0 ? 1 : 0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const mode = arguments_[0];
|
|
172
|
+
const rest = arguments_.slice(1);
|
|
173
|
+
const force = rest.includes("--force") || rest.includes("-f");
|
|
174
|
+
const unknownFlags = rest.filter(
|
|
175
|
+
(value) => value.startsWith("-") && value !== "--force" && value !== "-f",
|
|
176
|
+
);
|
|
177
|
+
if (unknownFlags.length) {
|
|
178
|
+
throw new Error(`Unknown init flag: ${unknownFlags[0]}`);
|
|
179
|
+
}
|
|
180
|
+
const positionals = rest.filter((value) => !value.startsWith("-"));
|
|
181
|
+
if (positionals.length > 1) {
|
|
182
|
+
throw new Error("init accepts at most one output path");
|
|
183
|
+
}
|
|
184
|
+
const result = writeFixtureTemplate({
|
|
185
|
+
mode,
|
|
186
|
+
outputPath: positionals[0],
|
|
187
|
+
force,
|
|
188
|
+
});
|
|
189
|
+
console.log(`Created ${result.label} fixture: ${result.absolutePath}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const [command, ...arguments_] = process.argv.slice(2);
|
|
193
|
+
|
|
194
|
+
if (command === "-v" || command === "--version") {
|
|
195
|
+
const packageJSON = JSON.parse(
|
|
196
|
+
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
197
|
+
);
|
|
198
|
+
console.log(packageJSON.version);
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!command || command === "help" || command === "-h" || command === "--help") {
|
|
203
|
+
help();
|
|
204
|
+
process.exit(command ? 0 : 1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (command === "demo") {
|
|
208
|
+
try {
|
|
209
|
+
process.exit(runDemo(arguments_));
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error(error instanceof Error ? error.message : error);
|
|
212
|
+
console.error("");
|
|
213
|
+
console.error(demoHelp());
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (command === "doctor") {
|
|
219
|
+
try {
|
|
220
|
+
process.exit(runDoctor(arguments_));
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error(error instanceof Error ? error.message : error);
|
|
223
|
+
console.error("");
|
|
224
|
+
console.error(doctorHelp());
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (command === "install-browser") {
|
|
230
|
+
runEngine("react", ["install-browser", ...arguments_]);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (command === "init") {
|
|
234
|
+
try {
|
|
235
|
+
runInit(arguments_);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error(error instanceof Error ? error.message : error);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
process.exit(0);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (command === "react" || command === "ink" || command === "tui" || command === "pty") {
|
|
244
|
+
const canonicalMode = command === "tui" ? "ink" : command;
|
|
245
|
+
if (
|
|
246
|
+
arguments_.length === 0 ||
|
|
247
|
+
arguments_[0] === "help" ||
|
|
248
|
+
arguments_[0] === "-h" ||
|
|
249
|
+
arguments_[0] === "--help"
|
|
250
|
+
) {
|
|
251
|
+
modeHelp(canonicalMode);
|
|
252
|
+
process.exit(arguments_.length === 0 ? 1 : 0);
|
|
253
|
+
}
|
|
254
|
+
runEngine(canonicalMode, arguments_);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (command === "movie") {
|
|
258
|
+
// Always forward to movie-harness (including --help / which-source).
|
|
259
|
+
const result = spawnSync(
|
|
260
|
+
process.execPath,
|
|
261
|
+
[engineBin("movie"), ...arguments_],
|
|
262
|
+
{ stdio: "inherit" },
|
|
263
|
+
);
|
|
264
|
+
if (result.error) {
|
|
265
|
+
console.error(
|
|
266
|
+
`astroshot could not start movie harness: ${result.error.message}`,
|
|
267
|
+
);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
if (result.signal) process.kill(process.pid, result.signal);
|
|
271
|
+
process.exit(result.status ?? 1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
console.error(`Unknown command: ${command}`);
|
|
275
|
+
help();
|
|
276
|
+
process.exit(1);
|