pi-agent-browser-native 0.2.37 → 0.2.39

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.
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Provide the Crabbox-backed platform smoke CLI for pi-agent-browser-native releases.
4
+ * Responsibilities: Load the project platform smoke config, validate target/suite names, run doctor, and fan out target suites.
5
+ * Scope: Maintainer release verification only; target command rendering and artifact assertions live under scripts/platform-smoke/.
6
+ */
7
+
8
+ import { createRequire } from "node:module";
9
+ import { dirname, resolve } from "node:path";
10
+ import { fileURLToPath, pathToFileURL } from "node:url";
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+ const repoRoot = resolve(__dirname, "..");
15
+ const require = createRequire(import.meta.url);
16
+
17
+ let config;
18
+ try {
19
+ config = require(resolve(repoRoot, "platform-smoke.config.mjs"));
20
+ if (config.default) config = config.default;
21
+ } catch {
22
+ config = null;
23
+ }
24
+
25
+ function printHelp() {
26
+ console.log(`Usage: node scripts/platform-smoke.mjs <command> [options]
27
+
28
+ Commands:
29
+ doctor Validate Crabbox and platform prerequisites
30
+ run --target <names> Run one or more comma-separated targets concurrently
31
+ run --suite <name> Run one suite on all or specified targets
32
+
33
+ Package scripts:
34
+ check:platform-smoke Syntax-check harness scripts and run cheap harness invariant tests
35
+ smoke:platform:ubuntu-image Build the local Ubuntu image used by default
36
+ smoke:platform:all Runs doctor first, then the full macOS/Ubuntu/Windows matrix
37
+
38
+ Targets:
39
+ macos, ubuntu, windows-native
40
+
41
+ Suites:
42
+ platform-build npm ci, npm run verify -- platform-target, npm pack, packed pi install, pi list
43
+ browser-dogfood-smoke model-free native agent_browser smoke with real agent-browser/browser
44
+
45
+ Options:
46
+ --target <names> Comma-separated target names; defaults to configured required targets
47
+ --suite <name> Suite name; defaults to configured required suites
48
+ --help, -h Show this help
49
+
50
+ Examples:
51
+ npm run check:platform-smoke
52
+ npm run smoke:platform:doctor
53
+ npm run smoke:platform:all
54
+ node scripts/platform-smoke.mjs doctor
55
+ node scripts/platform-smoke.mjs run --target macos
56
+ node scripts/platform-smoke.mjs run --target ubuntu --suite platform-build
57
+ node scripts/platform-smoke.mjs run --target macos,ubuntu,windows-native
58
+
59
+ Environment:
60
+ PLATFORM_SMOKE_CRABBOX Optional Crabbox binary override; defaults to crabbox on PATH
61
+ PLATFORM_SMOKE_MAC_HOST macOS SSH host; default localhost
62
+ PLATFORM_SMOKE_MAC_USER macOS SSH user; default $USER
63
+ PLATFORM_SMOKE_MAC_WORK_ROOT macOS Crabbox work root
64
+ PLATFORM_SMOKE_UBUNTU_IMAGE Ubuntu local-container image; default pi-agent-browser-native-platform:node24-agent-browser0.27.1
65
+ PLATFORM_SMOKE_WINDOWS_VM Parallels Windows template VM
66
+ PLATFORM_SMOKE_WINDOWS_SNAPSHOT Parallels snapshot name
67
+ PLATFORM_SMOKE_WINDOWS_USER Windows SSH user
68
+ PLATFORM_SMOKE_WINDOWS_WORK_ROOT Windows work root, for example C:\\crabbox\\pi-agent-browser-native
69
+ PLATFORM_SMOKE_AUTH_ENV Optional comma-separated secret env names to redact/forward for future live suites
70
+ `);
71
+ }
72
+
73
+ export function parseArgs(argv = process.argv.slice(2)) {
74
+ const parsed = { command: null, target: null, suite: null };
75
+ for (let index = 0; index < argv.length; index += 1) {
76
+ const arg = argv[index];
77
+ if (arg === "--help" || arg === "-h") {
78
+ parsed.command = "help";
79
+ return parsed;
80
+ }
81
+ if (arg === "doctor" || arg === "run") {
82
+ if (parsed.command) throw new Error(`multiple commands provided: ${parsed.command}, ${arg}`);
83
+ parsed.command = arg;
84
+ continue;
85
+ }
86
+ if (arg === "--target") {
87
+ const value = argv[index + 1];
88
+ if (!value || value.startsWith("-")) throw new Error("--target requires a value");
89
+ parsed.target = value;
90
+ index += 1;
91
+ continue;
92
+ }
93
+ if (arg === "--suite") {
94
+ const value = argv[index + 1];
95
+ if (!value || value.startsWith("-")) throw new Error("--suite requires a value");
96
+ parsed.suite = value;
97
+ index += 1;
98
+ continue;
99
+ }
100
+ throw new Error(`unknown argument: ${arg}`);
101
+ }
102
+ return parsed;
103
+ }
104
+
105
+ function validateNames(kind, names, allowed) {
106
+ const invalid = names.filter((name) => !allowed.includes(name));
107
+ if (invalid.length > 0) throw new Error(`unknown ${kind}: ${invalid.join(", ")}`);
108
+ }
109
+
110
+ export async function main(argv = process.argv.slice(2)) {
111
+ const args = parseArgs(argv);
112
+ if (!args.command || args.command === "help") {
113
+ printHelp();
114
+ return args.command === "help" ? 0 : 2;
115
+ }
116
+ if (!config) throw new Error("platform-smoke.config.mjs not found or invalid");
117
+
118
+ if (args.command === "doctor") {
119
+ const { runDoctor } = await import("./platform-smoke/doctor.mjs");
120
+ await runDoctor(config);
121
+ return process.exitCode ?? 0;
122
+ }
123
+
124
+ if (args.command === "run") {
125
+ const { runTargetSuite, runTargetSuites } = await import("./platform-smoke/targets.mjs");
126
+ const targets = args.target ? args.target.split(",").map((name) => name.trim()).filter(Boolean) : config.requiredTargets;
127
+ const suites = args.suite ? [args.suite] : config.requiredSuites;
128
+ const supportedTargets = config.supportedTargets ?? config.requiredTargets;
129
+ validateNames("target", targets, supportedTargets);
130
+ validateNames("suite", suites, config.requiredSuites);
131
+ const runs = targets.map(async (targetName) => {
132
+ console.log(`\n=== Target: ${targetName} ===`);
133
+ const result = args.suite
134
+ ? await runTargetSuite(config, targetName, suites[0])
135
+ : await runTargetSuites(config, targetName, suites);
136
+ return { targetName, result };
137
+ });
138
+ const results = await Promise.all(runs);
139
+ const failed = results.filter(({ result }) => !result.ok);
140
+ if (failed.length > 0) {
141
+ console.error(`\nPlatform smoke failed for ${failed.map(({ targetName }) => targetName).join(", ")}. See ${config.artifactRoot}.`);
142
+ return 1;
143
+ }
144
+ console.log(`\nPlatform smoke passed for ${results.map(({ targetName }) => targetName).join(", ")}.`);
145
+ return 0;
146
+ }
147
+
148
+ throw new Error(`unknown command: ${args.command}`);
149
+ }
150
+
151
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
152
+ main().then(
153
+ (exitCode) => {
154
+ process.exitCode = exitCode;
155
+ },
156
+ (error) => {
157
+ console.error(error instanceof Error ? error.message : String(error));
158
+ process.exitCode = 1;
159
+ },
160
+ );
161
+ }