@vivipilot/cli 0.1.0 → 0.1.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.
Files changed (67) hide show
  1. package/dist/chunk-FN7FHZ3D.js +1 -0
  2. package/dist/chunk-L3C7EOPY.js +2 -0
  3. package/dist/chunk-RB2L6BY5.js +3 -0
  4. package/dist/chunk-RW7OWVPD.js +5 -0
  5. package/dist/chunk-TZJPBE3B.js +1 -0
  6. package/dist/chunk-ZZ72PPC3.js +1 -0
  7. package/dist/cli.d.ts +5 -4
  8. package/dist/cli.js +53 -493
  9. package/dist/config-DAG58pP-.d.ts +16 -0
  10. package/dist/index.d.ts +121 -7
  11. package/dist/index.js +1 -7
  12. package/dist/manifest-TDCIHZ46.js +1 -0
  13. package/dist/mcp-MRADYIPQ.js +1 -0
  14. package/dist/render-TJGWLKPC.js +1 -0
  15. package/package.json +6 -2
  16. package/dist/api.d.ts +0 -86
  17. package/dist/api.d.ts.map +0 -1
  18. package/dist/api.js +0 -77
  19. package/dist/api.js.map +0 -1
  20. package/dist/args.d.ts +0 -11
  21. package/dist/args.d.ts.map +0 -1
  22. package/dist/args.js +0 -53
  23. package/dist/args.js.map +0 -1
  24. package/dist/browser.d.ts +0 -31
  25. package/dist/browser.d.ts.map +0 -1
  26. package/dist/browser.js +0 -162
  27. package/dist/browser.js.map +0 -1
  28. package/dist/cli.d.ts.map +0 -1
  29. package/dist/cli.js.map +0 -1
  30. package/dist/config.d.ts +0 -15
  31. package/dist/config.d.ts.map +0 -1
  32. package/dist/config.js +0 -58
  33. package/dist/config.js.map +0 -1
  34. package/dist/errors.d.ts +0 -6
  35. package/dist/errors.d.ts.map +0 -1
  36. package/dist/errors.js +0 -12
  37. package/dist/errors.js.map +0 -1
  38. package/dist/index.d.ts.map +0 -1
  39. package/dist/index.js.map +0 -1
  40. package/dist/manifest.d.ts +0 -40
  41. package/dist/manifest.d.ts.map +0 -1
  42. package/dist/manifest.js +0 -90
  43. package/dist/manifest.js.map +0 -1
  44. package/dist/mcp.d.ts +0 -13
  45. package/dist/mcp.d.ts.map +0 -1
  46. package/dist/mcp.js +0 -392
  47. package/dist/mcp.js.map +0 -1
  48. package/dist/render.d.ts +0 -21
  49. package/dist/render.d.ts.map +0 -1
  50. package/dist/render.js +0 -369
  51. package/dist/render.js.map +0 -1
  52. package/src/api.ts +0 -163
  53. package/src/args.test.ts +0 -21
  54. package/src/args.ts +0 -64
  55. package/src/browser.test.ts +0 -103
  56. package/src/browser.ts +0 -174
  57. package/src/cli.ts +0 -656
  58. package/src/config.test.ts +0 -30
  59. package/src/config.ts +0 -71
  60. package/src/errors.ts +0 -14
  61. package/src/index.ts +0 -25
  62. package/src/manifest.test.ts +0 -105
  63. package/src/manifest.ts +0 -126
  64. package/src/mcp.test.ts +0 -48
  65. package/src/mcp.ts +0 -438
  66. package/src/render.ts +0 -424
  67. package/tsconfig.json +0 -26
@@ -1,103 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
2
- import { headlessBrowserArgs, BrowserNotFoundError, resolveHeadlessBrowser } from "./browser.js";
3
-
4
- let mockNoBrowsers = false;
5
-
6
- vi.mock("node:fs/promises", async (importOriginal) => {
7
- const original = await importOriginal<typeof import("node:fs/promises")>();
8
- return {
9
- ...original,
10
- access: async (path: string, mode?: number) => {
11
- if (mockNoBrowsers) {
12
- throw new Error("Mocked: File not executable");
13
- }
14
- return original.access(path, mode);
15
- },
16
- };
17
- });
18
-
19
- describe("headlessBrowserArgs", () => {
20
- it("includes headless flag and render URL", () => {
21
- const args = headlessBrowserArgs("http://localhost:4001/headless-render");
22
- expect(args).toContain("--headless=new");
23
- expect(args).toContain("http://localhost:4001/headless-render");
24
- });
25
-
26
- it("includes GPU/WebGL enablement flags", () => {
27
- const args = headlessBrowserArgs("http://example.com");
28
- expect(args).toContain("--use-gl=angle");
29
- expect(args).toContain("--use-angle=swiftshader");
30
- expect(args).toContain("--enable-unsafe-swiftshader");
31
- expect(args).toContain("--ignore-gpu-blocklist");
32
- });
33
-
34
- it("includes no-sandbox flags for CI", () => {
35
- const args = headlessBrowserArgs("http://example.com");
36
- expect(args).toContain("--no-sandbox");
37
- expect(args).toContain("--disable-gpu-sandbox");
38
- expect(args).toContain("--disable-dev-shm-usage");
39
- });
40
-
41
- it("sets window size from options", () => {
42
- const args = headlessBrowserArgs("http://example.com", {
43
- windowSize: { width: 1920, height: 1080 },
44
- });
45
- expect(args).toContain("--window-size=1920,1080");
46
- });
47
-
48
- it("defaults to 1920x1080", () => {
49
- const args = headlessBrowserArgs("http://example.com");
50
- expect(args).toContain("--window-size=1920,1080");
51
- });
52
-
53
- it("appends extra args", () => {
54
- const args = headlessBrowserArgs("http://example.com", {
55
- extraArgs: ["--remote-debugging-port=9222"],
56
- });
57
- expect(args).toContain("--remote-debugging-port=9222");
58
- });
59
-
60
- it("URL is the last argument", () => {
61
- const url = "http://localhost:1234/render";
62
- const args = headlessBrowserArgs(url);
63
- expect(args[args.length - 1]).toBe(url);
64
- });
65
- });
66
-
67
- describe("BrowserNotFoundError", () => {
68
- it("is an Error subclass", () => {
69
- const err = new BrowserNotFoundError("not found");
70
- expect(err).toBeInstanceOf(Error);
71
- expect(err.name).toBe("BrowserNotFoundError");
72
- expect(err.message).toBe("not found");
73
- });
74
- });
75
-
76
- describe("resolveHeadlessBrowser", () => {
77
- beforeEach(() => {
78
- mockNoBrowsers = false;
79
- });
80
-
81
- afterEach(() => {
82
- mockNoBrowsers = false;
83
- });
84
-
85
- it("throws BrowserNotFoundError when no browser is available", async () => {
86
- mockNoBrowsers = true;
87
- const env: Record<string, string | undefined> = {
88
- VIVIPILOT_HEADLESS_BROWSER: undefined,
89
- PUPPETEER_EXECUTABLE_PATH: undefined,
90
- HOME: "/nonexistent-home-path-for-testing",
91
- };
92
- await expect(resolveHeadlessBrowser(env)).rejects.toBeInstanceOf(BrowserNotFoundError);
93
- });
94
-
95
- it("uses VIVIPILOT_HEADLESS_BROWSER when set to an executable", async () => {
96
- const env: Record<string, string | undefined> = {
97
- VIVIPILOT_HEADLESS_BROWSER: "/bin/true",
98
- };
99
- const result = await resolveHeadlessBrowser(env);
100
- expect(result.executablePath).toBe("/bin/true");
101
- expect(result.source).toBe("env");
102
- });
103
- });
package/src/browser.ts DELETED
@@ -1,174 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { access, constants } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- export type BrowserResolution = {
7
- executablePath: string;
8
- source: "env" | "chrome-headless-shell" | "system-chrome" | "system-chromium";
9
- };
10
-
11
- export class BrowserNotFoundError extends Error {
12
- constructor(message: string) {
13
- super(message);
14
- this.name = "BrowserNotFoundError";
15
- }
16
- }
17
-
18
- /**
19
- * Resolve a browser binary for headless rendering.
20
- *
21
- * Priority:
22
- * 1. `VIVIPILOT_HEADLESS_BROWSER` env var (explicit override)
23
- * 2. `chrome-headless-shell` in PATH or common install locations
24
- * 3. System Chrome / Chromium in common install locations
25
- *
26
- * Returns the path + source. Throws `BrowserNotFoundError` when no browser is found.
27
- */
28
- export async function resolveHeadlessBrowser(env: NodeJS.ProcessEnv = process.env): Promise<BrowserResolution> {
29
- const envPath = env.VIVIPILOT_HEADLESS_BROWSER;
30
- if (envPath && await isExecutable(envPath)) {
31
- return { executablePath: envPath, source: "env" };
32
- }
33
-
34
- const shell = await findChromeHeadlessShell();
35
- if (shell) return { executablePath: shell, source: "chrome-headless-shell" };
36
-
37
- const chrome = await findSystemChrome();
38
- if (chrome) return { executablePath: chrome, source: "system-chrome" };
39
-
40
- const chromium = await findSystemChromium();
41
- if (chromium) return { executablePath: chromium, source: "system-chromium" };
42
-
43
- throw new BrowserNotFoundError(
44
- "No headless browser found. Install chrome-headless-shell or Chrome/Chromium, or set VIVIPILOT_HEADLESS_BROWSER to the binary path.",
45
- );
46
- }
47
-
48
- async function isExecutable(path: string): Promise<boolean> {
49
- try {
50
- await access(path, constants.X_OK);
51
- return true;
52
- } catch {
53
- return false;
54
- }
55
- }
56
-
57
- async function findChromeHeadlessShell(): Promise<string | null> {
58
- const candidates = [
59
- process.env.PUPPETEER_EXECUTABLE_PATH,
60
- join(homedir(), ".cache", "puppeteer", "chrome-headless-shell"),
61
- "/usr/bin/chrome-headless-shell",
62
- "/usr/local/bin/chrome-headless-shell",
63
- "/snap/bin/chrome-headless-shell",
64
- join(homedir(), ".local", "share", "chrome-headless-shell", "chrome-headless-shell"),
65
- "/opt/chrome-headless-shell/chrome-headless-shell",
66
- // macOS
67
- "/Applications/Google Chrome Headless Shell.app/Contents/MacOS/Google Chrome Headless Shell",
68
- // Windows
69
- join(homedir(), "AppData", "Local", "chrome-headless-shell", "chrome-headless-shell.exe"),
70
- ];
71
-
72
- for (const candidate of candidates) {
73
- if (!candidate) continue;
74
- if (await isExecutable(candidate)) return candidate;
75
- // Some install dirs contain a versioned subfolder
76
- if (existsSync(candidate) && !candidate.endsWith("chrome-headless-shell") && !candidate.endsWith(".exe")) {
77
- // Search for the binary inside versioned subdirs
78
- const { readdirSync } = await import("node:fs");
79
- try {
80
- const entries = readdirSync(candidate, { withFileTypes: true });
81
- for (const entry of entries) {
82
- if (!entry.isDirectory()) continue;
83
- const inner = join(candidate, entry.name, "chrome-headless-shell");
84
- if (await isExecutable(inner)) return inner;
85
- const innerExe = join(candidate, entry.name, "chrome-headless-shell.exe");
86
- if (await isExecutable(innerExe)) return innerExe;
87
- }
88
- } catch { /* ignore */ }
89
- }
90
- }
91
- return null;
92
- }
93
-
94
- async function findSystemChrome(): Promise<string | null> {
95
- const candidates = [
96
- "/usr/bin/google-chrome",
97
- "/usr/bin/google-chrome-stable",
98
- "/usr/bin/google-chrome-unstable",
99
- "/usr/local/bin/google-chrome",
100
- "/opt/google/chrome/chrome",
101
- "/snap/bin/google-chrome",
102
- // macOS
103
- "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
104
- // Windows
105
- join(homedir(), "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe"),
106
- "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
107
- "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
108
- ];
109
-
110
- for (const candidate of candidates) {
111
- if (await isExecutable(candidate)) return candidate;
112
- }
113
- return null;
114
- }
115
-
116
- async function findSystemChromium(): Promise<string | null> {
117
- const candidates = [
118
- "/usr/bin/chromium",
119
- "/usr/bin/chromium-browser",
120
- "/usr/local/bin/chromium",
121
- "/snap/bin/chromium",
122
- "/usr/bin/brave-browser",
123
- "/usr/bin/brave",
124
- "/Applications/Chromium.app/Contents/MacOS/Chromium",
125
- join(homedir(), "AppData", "Local", "Chromium", "Application", "chromium.exe"),
126
- "C:\\Program Files\\Chromium\\Application\\chromium.exe",
127
- ];
128
-
129
- for (const candidate of candidates) {
130
- if (await isExecutable(candidate)) return candidate;
131
- }
132
- return null;
133
- }
134
-
135
- /**
136
- * Build the Chrome/Chromium CLI flags for headless rendering with WebGL/WebGPU support.
137
- * These flags ensure the GPU is available (or SwiftShader fallback) so Pixi v8 can
138
- * initialise its renderer inside a headless browser.
139
- */
140
- export function headlessBrowserArgs(renderUrl: string, options?: {
141
- windowSize?: { width: number; height: number };
142
- extraArgs?: string[];
143
- }): string[] {
144
- const width = options?.windowSize?.width ?? 1920;
145
- const height = options?.windowSize?.height ?? 1080;
146
-
147
- return [
148
- "--headless=new",
149
- "--no-sandbox",
150
- "--disable-gpu-sandbox",
151
- "--disable-dev-shm-usage",
152
- "--disable-extensions",
153
- "--disable-background-networking",
154
- "--disable-sync",
155
- "--disable-translate",
156
- "--disable-default-apps",
157
- "--disable-popup-blocking",
158
- "--disable-component-update",
159
- "--disable-metrics",
160
- "--no-first-run",
161
- "--mute-audio",
162
- "--enable-logging=stderr",
163
- "--log-level=0",
164
- "--v=1",
165
- `--window-size=${width},${height}`,
166
- "--enable-features=Vulkan",
167
- "--use-gl=angle",
168
- "--use-angle=swiftshader",
169
- "--enable-unsafe-swiftshader",
170
- "--ignore-gpu-blocklist",
171
- ...(options?.extraArgs ?? []),
172
- renderUrl,
173
- ];
174
- }