audrey 0.23.1 → 1.0.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/CHANGELOG.md +101 -15
- package/LICENSE +21 -21
- package/README.md +232 -6
- package/SECURITY.md +2 -1
- package/benchmarks/adapter-kit.mjs +20 -0
- package/benchmarks/adapter-self-test.mjs +166 -0
- package/benchmarks/adapters/example-allow.mjs +28 -0
- package/benchmarks/adapters/mem0-platform.mjs +267 -0
- package/benchmarks/adapters/registry.json +51 -0
- package/benchmarks/adapters/zep-cloud.mjs +280 -0
- package/benchmarks/baselines.js +169 -0
- package/benchmarks/build-leaderboard.mjs +170 -0
- package/benchmarks/cases.js +537 -0
- package/benchmarks/create-conformance-card.mjs +139 -0
- package/benchmarks/create-submission-bundle.mjs +176 -0
- package/benchmarks/dry-run-external-adapters.mjs +165 -0
- package/benchmarks/guardbench.js +1125 -0
- package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/guardbench-manifest.json +414 -0
- package/benchmarks/output/guardbench-raw.json +1271 -0
- package/benchmarks/output/guardbench-summary.json +2107 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/submission-bundle/guardbench-manifest.json +414 -0
- package/benchmarks/output/submission-bundle/guardbench-raw.json +1271 -0
- package/benchmarks/output/submission-bundle/guardbench-summary.json +2107 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +184 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +249 -0
- package/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/benchmarks/output/summary.json +2354 -0
- package/benchmarks/perf-snapshot.js +304 -0
- package/benchmarks/perf.bench.js +161 -0
- package/benchmarks/public-paths.mjs +78 -0
- package/benchmarks/reference-results.js +70 -0
- package/benchmarks/report.js +259 -0
- package/benchmarks/run-external-guardbench.mjs +281 -0
- package/benchmarks/run.js +682 -0
- package/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/schemas/guardbench-raw.schema.json +184 -0
- package/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/schemas/guardbench-summary.schema.json +249 -0
- package/benchmarks/snapshots/perf-0.22.2.json +123 -0
- package/benchmarks/snapshots/perf-0.23.0.json +123 -0
- package/benchmarks/validate-adapter-module.mjs +104 -0
- package/benchmarks/validate-adapter-registry.mjs +134 -0
- package/benchmarks/validate-adapter-self-test.mjs +96 -0
- package/benchmarks/validate-guardbench-artifacts.mjs +343 -0
- package/benchmarks/verify-external-evidence.mjs +296 -0
- package/benchmarks/verify-publication-artifacts.mjs +286 -0
- package/benchmarks/verify-submission-bundle.mjs +167 -0
- package/dist/mcp-server/config.d.ts +1 -1
- package/dist/mcp-server/config.d.ts.map +1 -1
- package/dist/mcp-server/config.js +1 -1
- package/dist/mcp-server/config.js.map +1 -1
- package/dist/mcp-server/index.d.ts +65 -3
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +675 -157
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/action-key.d.ts +9 -0
- package/dist/src/action-key.d.ts.map +1 -0
- package/dist/src/action-key.js +49 -0
- package/dist/src/action-key.js.map +1 -0
- package/dist/src/adaptive.js +5 -5
- package/dist/src/affect.js +8 -8
- package/dist/src/audrey.d.ts +13 -0
- package/dist/src/audrey.d.ts.map +1 -1
- package/dist/src/audrey.js +68 -3
- package/dist/src/audrey.js.map +1 -1
- package/dist/src/capsule.js +4 -4
- package/dist/src/causal.js +3 -3
- package/dist/src/consolidate.js +48 -48
- package/dist/src/controller.d.ts +78 -6
- package/dist/src/controller.d.ts.map +1 -1
- package/dist/src/controller.js +273 -53
- package/dist/src/controller.js.map +1 -1
- package/dist/src/db.js +172 -172
- package/dist/src/decay.js +8 -8
- package/dist/src/embedding.d.ts +2 -1
- package/dist/src/embedding.d.ts.map +1 -1
- package/dist/src/embedding.js +39 -29
- package/dist/src/embedding.js.map +1 -1
- package/dist/src/encode.js +6 -6
- package/dist/src/feedback.d.ts +6 -0
- package/dist/src/feedback.d.ts.map +1 -1
- package/dist/src/feedback.js +6 -0
- package/dist/src/feedback.js.map +1 -1
- package/dist/src/forget.js +12 -12
- package/dist/src/hybrid-recall.js +9 -9
- package/dist/src/impact.js +6 -6
- package/dist/src/import.d.ts +3 -3
- package/dist/src/import.js +41 -41
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/interference.js +14 -14
- package/dist/src/introspect.js +18 -18
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js +41 -0
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/promote.js +7 -7
- package/dist/src/prompts.js +118 -118
- package/dist/src/recall.js +30 -30
- package/dist/src/reflexes.d.ts +1 -0
- package/dist/src/reflexes.d.ts.map +1 -1
- package/dist/src/reflexes.js +3 -0
- package/dist/src/reflexes.js.map +1 -1
- package/dist/src/rollback.js +4 -4
- package/dist/src/routes.d.ts.map +1 -1
- package/dist/src/routes.js +71 -2
- package/dist/src/routes.js.map +1 -1
- package/dist/src/validate.js +25 -25
- package/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/MEMORY_BENCHMARKING.md +59 -0
- package/docs/PRODUCTION_BACKLOG.md +304 -0
- package/docs/paper/00-master.md +48 -0
- package/docs/paper/01-introduction.md +27 -0
- package/docs/paper/02-related-work.md +47 -0
- package/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/04-design.md +164 -0
- package/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/06-implementation.md +113 -0
- package/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/claim-register.json +138 -0
- package/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/LICENSE +21 -0
- package/docs/paper/output/submission-bundle/README.md +555 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-manifest.json +414 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +1271 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +2107 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +2354 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +184 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +249 -0
- package/docs/paper/output/submission-bundle/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/paper/output/submission-bundle/docs/paper/00-master.md +48 -0
- package/docs/paper/output/submission-bundle/docs/paper/01-introduction.md +27 -0
- package/docs/paper/output/submission-bundle/docs/paper/02-related-work.md +47 -0
- package/docs/paper/output/submission-bundle/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/output/submission-bundle/docs/paper/04-design.md +164 -0
- package/docs/paper/output/submission-bundle/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/output/submission-bundle/docs/paper/06-implementation.md +113 -0
- package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/output/submission-bundle/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/output/submission-bundle/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/output/submission-bundle/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.json +138 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/output/submission-bundle/docs/paper/references.bib +222 -0
- package/docs/paper/output/submission-bundle/package.json +212 -0
- package/docs/paper/output/submission-bundle/paper-submission-manifest.json +379 -0
- package/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/publication-pack.json +81 -0
- package/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/references.bib +222 -0
- package/package.json +87 -4
- package/scripts/audit-release-completion.mjs +362 -0
- package/scripts/create-arxiv-source.mjs +362 -0
- package/scripts/create-paper-submission-bundle.mjs +210 -0
- package/scripts/finalize-release.mjs +526 -0
- package/scripts/prepare-release-cut.mjs +269 -0
- package/scripts/publish-release-bundle.mjs +209 -0
- package/scripts/publish-release-github-api.mjs +429 -0
- package/scripts/run-vitest.mjs +34 -0
- package/scripts/smoke-cli.js +92 -0
- package/scripts/sync-paper-artifacts.mjs +109 -0
- package/scripts/verify-arxiv-compile.mjs +440 -0
- package/scripts/verify-arxiv-source.mjs +194 -0
- package/scripts/verify-browser-launch-plan.mjs +237 -0
- package/scripts/verify-browser-launch-results.mjs +285 -0
- package/scripts/verify-paper-artifacts.mjs +338 -0
- package/scripts/verify-paper-claims.mjs +226 -0
- package/scripts/verify-paper-submission-bundle.mjs +207 -0
- package/scripts/verify-publication-pack.mjs +196 -0
- package/scripts/verify-python-package.py +201 -0
- package/scripts/verify-release-readiness.mjs +785 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { publicPath } from '../benchmarks/public-paths.mjs';
|
|
5
|
+
import { validateSchema } from '../benchmarks/validate-guardbench-artifacts.mjs';
|
|
6
|
+
import { verifyPublicationPack } from './verify-publication-pack.mjs';
|
|
7
|
+
|
|
8
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const DEFAULT_PLAN = 'docs/paper/browser-launch-plan.json';
|
|
10
|
+
const DEFAULT_SCHEMA = 'docs/paper/browser-launch-plan.schema.json';
|
|
11
|
+
const REQUIRED_TARGETS = [
|
|
12
|
+
'arxiv-preprint',
|
|
13
|
+
'hacker-news-show',
|
|
14
|
+
'reddit-discussion',
|
|
15
|
+
'x-launch-thread',
|
|
16
|
+
'linkedin-launch-post',
|
|
17
|
+
];
|
|
18
|
+
const REQUIRED_PREFLIGHT_COMMANDS = [
|
|
19
|
+
'npm run release:gate:paper',
|
|
20
|
+
'npm run paper:publication-pack',
|
|
21
|
+
'npm run paper:bundle:verify',
|
|
22
|
+
'npm run paper:launch-plan',
|
|
23
|
+
];
|
|
24
|
+
const ALLOWED_HOSTS = {
|
|
25
|
+
arxiv: ['arxiv.org'],
|
|
26
|
+
'hacker-news': ['news.ycombinator.com'],
|
|
27
|
+
reddit: ['www.reddit.com', 'reddit.com'],
|
|
28
|
+
x: ['twitter.com', 'x.com'],
|
|
29
|
+
linkedin: ['www.linkedin.com', 'linkedin.com'],
|
|
30
|
+
};
|
|
31
|
+
const PLATFORM_ENTRY_RULES = {
|
|
32
|
+
arxiv: new Set(['arxiv-title', 'arxiv-abstract']),
|
|
33
|
+
'hacker-news': new Set(['hacker-news-title', 'hacker-news-comment']),
|
|
34
|
+
reddit: new Set(['reddit-title', 'reddit-body']),
|
|
35
|
+
x: new Set(['x-post-1', 'x-post-2']),
|
|
36
|
+
linkedin: new Set(['linkedin-post']),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function fromRoot(path) {
|
|
40
|
+
return resolve(ROOT, path);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function readText(path) {
|
|
44
|
+
const absolute = fromRoot(path);
|
|
45
|
+
if (!existsSync(absolute)) throw new Error(`Missing required file: ${path}`);
|
|
46
|
+
return readFileSync(absolute, 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readJson(path) {
|
|
50
|
+
return JSON.parse(readText(path));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
54
|
+
const args = {
|
|
55
|
+
plan: DEFAULT_PLAN,
|
|
56
|
+
schema: DEFAULT_SCHEMA,
|
|
57
|
+
json: false,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < argv.length; i++) {
|
|
61
|
+
const token = argv[i];
|
|
62
|
+
if (token === '--plan' && argv[i + 1]) args.plan = argv[++i];
|
|
63
|
+
else if (token === '--schema' && argv[i + 1]) args.schema = argv[++i];
|
|
64
|
+
else if (token === '--json') args.json = true;
|
|
65
|
+
else if (token === '--help' || token === '-h') args.help = true;
|
|
66
|
+
else throw new Error(`Unknown argument: ${token}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return args;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function usage() {
|
|
73
|
+
return `Usage: node scripts/verify-browser-launch-plan.mjs [options]
|
|
74
|
+
|
|
75
|
+
Options:
|
|
76
|
+
--plan <path> Browser launch plan JSON. Default: ${DEFAULT_PLAN}.
|
|
77
|
+
--schema <path> Browser launch plan schema. Default: ${DEFAULT_SCHEMA}.
|
|
78
|
+
--json Print the machine-readable verification report.
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isAllowedHost(platform, value) {
|
|
83
|
+
try {
|
|
84
|
+
const url = new URL(value);
|
|
85
|
+
return (ALLOWED_HOSTS[platform] ?? []).includes(url.hostname);
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hasPendingBoundary(text) {
|
|
92
|
+
return /\b(pending|not claim|not claimed|does not report|remain pending|live evidence|strict evidence)\b/i.test(text);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function validateTarget(target, entryMap, sourceIds) {
|
|
96
|
+
const failures = [];
|
|
97
|
+
const allowedEntries = PLATFORM_ENTRY_RULES[target.platform] ?? new Set();
|
|
98
|
+
const targetEntries = [];
|
|
99
|
+
|
|
100
|
+
if (!isAllowedHost(target.platform, target.url)) {
|
|
101
|
+
failures.push(`${target.id}: URL host is not allowed for ${target.platform}`);
|
|
102
|
+
}
|
|
103
|
+
for (const entryId of target.contentEntryIds) {
|
|
104
|
+
const entry = entryMap.get(entryId);
|
|
105
|
+
if (!entry) {
|
|
106
|
+
failures.push(`${target.id}: unknown publication-pack entry ${entryId}`);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (entry.platform !== target.platform) {
|
|
110
|
+
failures.push(`${target.id}: entry ${entryId} belongs to ${entry.platform}, not ${target.platform}`);
|
|
111
|
+
}
|
|
112
|
+
if (!allowedEntries.has(entryId)) {
|
|
113
|
+
failures.push(`${target.id}: entry ${entryId} is not approved for ${target.platform}`);
|
|
114
|
+
}
|
|
115
|
+
if (entry.text.length > entry.maxChars) {
|
|
116
|
+
failures.push(`${target.id}: entry ${entryId} exceeds maxChars`);
|
|
117
|
+
}
|
|
118
|
+
if (/\b(Mem0|Zep)\b/.test(entry.text) && !hasPendingBoundary(entry.text)) {
|
|
119
|
+
failures.push(`${target.id}: entry ${entryId} mentions Mem0/Zep without pending boundary language`);
|
|
120
|
+
}
|
|
121
|
+
targetEntries.push(entry);
|
|
122
|
+
}
|
|
123
|
+
for (const sourceId of target.sourceRefs) {
|
|
124
|
+
if (!sourceIds.has(sourceId)) failures.push(`${target.id}: unknown sourceRef ${sourceId}`);
|
|
125
|
+
}
|
|
126
|
+
for (const artifact of target.artifactRefs) {
|
|
127
|
+
if (!existsSync(fromRoot(artifact))) failures.push(`${target.id}: missing artifactRef ${artifact}`);
|
|
128
|
+
}
|
|
129
|
+
if (target.platform === 'reddit' && target.manualRuleCheckRequired !== true) {
|
|
130
|
+
failures.push(`${target.id}: Reddit target must require a manual subreddit rule check`);
|
|
131
|
+
}
|
|
132
|
+
if (target.platform === 'hacker-news' && target.manualRuleCheckRequired !== true) {
|
|
133
|
+
failures.push(`${target.id}: Hacker News target must require a manual guideline check`);
|
|
134
|
+
}
|
|
135
|
+
if (target.platform === 'arxiv' && target.manualRuleCheckRequired !== true) {
|
|
136
|
+
failures.push(`${target.id}: arXiv target must require a manual category/metadata check`);
|
|
137
|
+
}
|
|
138
|
+
if (!target.humanRequired) failures.push(`${target.id}: browser launch targets must require a human operator`);
|
|
139
|
+
if (!target.authRequired) failures.push(`${target.id}: browser launch targets must require authenticated account review`);
|
|
140
|
+
if (target.operatorChecks.length < 2) failures.push(`${target.id}: operator checklist is too thin`);
|
|
141
|
+
if (target.postSubmitChecks.length < 1) failures.push(`${target.id}: missing post-submit checks`);
|
|
142
|
+
if (
|
|
143
|
+
target.platform === 'x' &&
|
|
144
|
+
target.status === 'blocked-until-artifact-url' &&
|
|
145
|
+
!targetEntries.some(entry => entry.requiresArtifactUrl === true)
|
|
146
|
+
) {
|
|
147
|
+
failures.push(`${target.id}: X artifact-url launch target must include a publication entry with reserved URL budget`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return failures;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function verifyBrowserLaunchPlan(options = {}) {
|
|
154
|
+
const plan = readJson(options.plan ?? DEFAULT_PLAN);
|
|
155
|
+
const schema = readJson(options.schema ?? DEFAULT_SCHEMA);
|
|
156
|
+
const publicationReport = await verifyPublicationPack({ pack: plan.publicationPack });
|
|
157
|
+
const publicationPack = readJson(plan.publicationPack);
|
|
158
|
+
const entryMap = new Map((publicationPack.entries ?? []).map(entry => [entry.id, entry]));
|
|
159
|
+
const sourceIds = new Set((plan.sources ?? []).map(source => source.id));
|
|
160
|
+
const ids = new Set();
|
|
161
|
+
const targetReports = [];
|
|
162
|
+
const failures = [
|
|
163
|
+
...validateSchema(plan, schema, 'audrey-browser-launch-plan').map(failure => `browser launch plan schema: ${failure}`),
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
if (!publicationReport.ok) {
|
|
167
|
+
failures.push(...publicationReport.failures.map(failure => `publication pack: ${failure}`));
|
|
168
|
+
}
|
|
169
|
+
if (plan.publicationPack !== 'docs/paper/publication-pack.json') {
|
|
170
|
+
failures.push('browser launch plan must point at docs/paper/publication-pack.json');
|
|
171
|
+
}
|
|
172
|
+
for (const command of REQUIRED_PREFLIGHT_COMMANDS) {
|
|
173
|
+
if (!(plan.preflightCommands ?? []).includes(command)) failures.push(`Missing browser-launch preflight command: ${command}`);
|
|
174
|
+
}
|
|
175
|
+
for (const target of plan.targets ?? []) {
|
|
176
|
+
const targetFailures = [];
|
|
177
|
+
if (ids.has(target.id)) targetFailures.push(`${target.id}: duplicate target id`);
|
|
178
|
+
ids.add(target.id);
|
|
179
|
+
targetFailures.push(...validateTarget(target, entryMap, sourceIds));
|
|
180
|
+
targetReports.push({
|
|
181
|
+
id: target.id,
|
|
182
|
+
platform: target.platform,
|
|
183
|
+
status: target.status,
|
|
184
|
+
url: target.url,
|
|
185
|
+
contentEntryIds: target.contentEntryIds,
|
|
186
|
+
manualRuleCheckRequired: target.manualRuleCheckRequired,
|
|
187
|
+
ok: targetFailures.length === 0,
|
|
188
|
+
failures: targetFailures,
|
|
189
|
+
});
|
|
190
|
+
failures.push(...targetFailures);
|
|
191
|
+
}
|
|
192
|
+
for (const id of REQUIRED_TARGETS) {
|
|
193
|
+
if (!ids.has(id)) failures.push(`Missing browser-launch target: ${id}`);
|
|
194
|
+
}
|
|
195
|
+
const ordered = [...(plan.targets ?? [])].sort((a, b) => a.order - b.order).map(target => target.id);
|
|
196
|
+
if (ordered.join('|') !== REQUIRED_TARGETS.join('|')) {
|
|
197
|
+
failures.push(`Browser-launch target order must be ${REQUIRED_TARGETS.join(', ')}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
schemaVersion: '1.0.0',
|
|
202
|
+
suite: 'Audrey browser launch plan verification',
|
|
203
|
+
generatedAt: new Date().toISOString(),
|
|
204
|
+
ok: failures.length === 0,
|
|
205
|
+
plan: publicPath(fromRoot(options.plan ?? DEFAULT_PLAN)),
|
|
206
|
+
publicationPack: publicPath(fromRoot(plan.publicationPack)),
|
|
207
|
+
targets: targetReports,
|
|
208
|
+
failures,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function main() {
|
|
213
|
+
const args = parseArgs();
|
|
214
|
+
if (args.help) {
|
|
215
|
+
console.log(usage());
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const report = await verifyBrowserLaunchPlan(args);
|
|
220
|
+
if (args.json) {
|
|
221
|
+
console.log(JSON.stringify(report, null, 2));
|
|
222
|
+
} else if (report.ok) {
|
|
223
|
+
console.log(`Browser launch plan verification passed: ${report.targets.length} target(s)`);
|
|
224
|
+
} else {
|
|
225
|
+
console.error('Browser launch plan verification failed:');
|
|
226
|
+
for (const failure of report.failures) console.error(`- ${failure}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!report.ok) process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
233
|
+
main().catch(error => {
|
|
234
|
+
console.error(error.stack ?? error.message);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { publicPath } from '../benchmarks/public-paths.mjs';
|
|
5
|
+
import { validateSchema } from '../benchmarks/validate-guardbench-artifacts.mjs';
|
|
6
|
+
import { verifyBrowserLaunchPlan } from './verify-browser-launch-plan.mjs';
|
|
7
|
+
|
|
8
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const DEFAULT_RESULTS = 'docs/paper/browser-launch-results.json';
|
|
10
|
+
const DEFAULT_SCHEMA = 'docs/paper/browser-launch-results.schema.json';
|
|
11
|
+
const DEFAULT_PLAN = 'docs/paper/browser-launch-plan.json';
|
|
12
|
+
const SEEDED_SECRET = 'sk-guardbench-secret-0000000000000000000000000000';
|
|
13
|
+
const GITHUB_REPO_URL = 'https://github.com/Evilander/Audrey';
|
|
14
|
+
const TRUSTED_GITHUB_REPO = new URL(GITHUB_REPO_URL);
|
|
15
|
+
const TRUSTED_GITHUB_REPO_PATH = TRUSTED_GITHUB_REPO.pathname.toLowerCase();
|
|
16
|
+
const PLATFORMS_REQUIRING_REPO_LINK = new Set(['hacker-news', 'reddit', 'linkedin', 'x']);
|
|
17
|
+
const PLATFORM_HOSTS = {
|
|
18
|
+
arxiv: ['arxiv.org'],
|
|
19
|
+
'hacker-news': ['news.ycombinator.com'],
|
|
20
|
+
reddit: ['www.reddit.com', 'reddit.com'],
|
|
21
|
+
x: ['twitter.com', 'x.com'],
|
|
22
|
+
linkedin: ['www.linkedin.com', 'linkedin.com'],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function fromRoot(path) {
|
|
26
|
+
return resolve(ROOT, path);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readText(path) {
|
|
30
|
+
const absolute = fromRoot(path);
|
|
31
|
+
if (!existsSync(absolute)) throw new Error(`Missing required file: ${path}`);
|
|
32
|
+
return readFileSync(absolute, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readJson(path) {
|
|
36
|
+
return JSON.parse(readText(path));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
40
|
+
const args = {
|
|
41
|
+
results: DEFAULT_RESULTS,
|
|
42
|
+
schema: DEFAULT_SCHEMA,
|
|
43
|
+
plan: DEFAULT_PLAN,
|
|
44
|
+
strict: false,
|
|
45
|
+
json: false,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < argv.length; i++) {
|
|
49
|
+
const token = argv[i];
|
|
50
|
+
if ((token === '--results' || token === '--file') && argv[i + 1]) args.results = argv[++i];
|
|
51
|
+
else if (token === '--schema' && argv[i + 1]) args.schema = argv[++i];
|
|
52
|
+
else if (token === '--plan' && argv[i + 1]) args.plan = argv[++i];
|
|
53
|
+
else if (token === '--strict') args.strict = true;
|
|
54
|
+
else if (token === '--json') args.json = true;
|
|
55
|
+
else if (token === '--help' || token === '-h') args.help = true;
|
|
56
|
+
else throw new Error(`Unknown argument: ${token}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return args;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function usage() {
|
|
63
|
+
return `Usage: node scripts/verify-browser-launch-results.mjs [options]
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
--results <path> Browser launch results JSON. Default: ${DEFAULT_RESULTS}.
|
|
67
|
+
--schema <path> Browser launch results schema. Default: ${DEFAULT_SCHEMA}.
|
|
68
|
+
--plan <path> Browser launch plan JSON. Default: ${DEFAULT_PLAN}.
|
|
69
|
+
--strict Fail until every launch target is submitted and verified.
|
|
70
|
+
--json Print the machine-readable verification report.
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isAllowedPlatformUrl(platform, value) {
|
|
75
|
+
if (value === null) return true;
|
|
76
|
+
try {
|
|
77
|
+
const url = new URL(value);
|
|
78
|
+
return (PLATFORM_HOSTS[platform] ?? []).includes(url.hostname);
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isHttpsUrl(value) {
|
|
85
|
+
if (value === null) return true;
|
|
86
|
+
try {
|
|
87
|
+
return new URL(value).protocol === 'https:';
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function containsLocalPath(text) {
|
|
94
|
+
return /(^|[^a-z])[A-Z]:\\/i.test(text) || /\\\\\?\\/.test(text) || /file:\/\//i.test(text);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function trimUrlCandidate(value) {
|
|
98
|
+
return value.replace(/[),.;:!?}\]]+$/g, '');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function matchesTrustedGitHubRepoUrl(value) {
|
|
102
|
+
try {
|
|
103
|
+
const url = new URL(value);
|
|
104
|
+
const pathname = url.pathname.toLowerCase();
|
|
105
|
+
return url.protocol === TRUSTED_GITHUB_REPO.protocol
|
|
106
|
+
&& url.hostname === TRUSTED_GITHUB_REPO.hostname
|
|
107
|
+
&& (pathname === TRUSTED_GITHUB_REPO_PATH || pathname.startsWith(`${TRUSTED_GITHUB_REPO_PATH}/`));
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function stringIncludesTrustedGitHubRepoUrl(value) {
|
|
114
|
+
const candidates = value.match(/https?:\/\/[^\s<>"']+/gi) ?? [];
|
|
115
|
+
return candidates.some(candidate => matchesTrustedGitHubRepoUrl(trimUrlCandidate(candidate)));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function includesGitHubRepoUrl(result) {
|
|
119
|
+
function walk(value) {
|
|
120
|
+
if (typeof value === 'string') return stringIncludesTrustedGitHubRepoUrl(value);
|
|
121
|
+
if (Array.isArray(value)) return value.some(item => walk(item));
|
|
122
|
+
if (value && typeof value === 'object') return Object.values(value).some(item => walk(item));
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return walk(result);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function validateResultTarget(result, planTarget) {
|
|
129
|
+
const failures = [];
|
|
130
|
+
const blockers = [];
|
|
131
|
+
const text = JSON.stringify(result);
|
|
132
|
+
|
|
133
|
+
if (!planTarget) {
|
|
134
|
+
failures.push(`${result.id}: no matching launch-plan target`);
|
|
135
|
+
return { failures, blockers };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (result.platform !== planTarget.platform) {
|
|
139
|
+
failures.push(`${result.id}: platform ${result.platform} does not match launch plan ${planTarget.platform}`);
|
|
140
|
+
}
|
|
141
|
+
if (!isAllowedPlatformUrl(result.platform, result.publicUrl)) {
|
|
142
|
+
failures.push(`${result.id}: publicUrl host is not allowed for ${result.platform}`);
|
|
143
|
+
}
|
|
144
|
+
if (!isHttpsUrl(result.artifactUrl)) {
|
|
145
|
+
failures.push(`${result.id}: artifactUrl must be null or https`);
|
|
146
|
+
}
|
|
147
|
+
if (text.includes(SEEDED_SECRET)) failures.push(`${result.id}: contains raw seeded GuardBench secret`);
|
|
148
|
+
if (containsLocalPath(text)) failures.push(`${result.id}: contains local absolute path`);
|
|
149
|
+
|
|
150
|
+
if (result.status === 'pending') {
|
|
151
|
+
if (!result.blocker) failures.push(`${result.id}: pending result must record a blocker`);
|
|
152
|
+
if (result.publicUrl !== null) failures.push(`${result.id}: pending result must not record a publicUrl`);
|
|
153
|
+
if (result.submittedAt !== null) failures.push(`${result.id}: pending result must not record submittedAt`);
|
|
154
|
+
if (result.operatorVerified) failures.push(`${result.id}: pending result must not be operator verified`);
|
|
155
|
+
blockers.push(`${result.id}: ${result.blocker ?? 'pending launch target'}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (result.status === 'submitted') {
|
|
159
|
+
if (!result.publicUrl) failures.push(`${result.id}: submitted result must record publicUrl`);
|
|
160
|
+
if (planTarget.status === 'blocked-until-artifact-url' && !result.artifactUrl) {
|
|
161
|
+
failures.push(`${result.id}: submitted artifact-url target must record artifactUrl`);
|
|
162
|
+
}
|
|
163
|
+
if (!result.submittedAt) failures.push(`${result.id}: submitted result must record submittedAt`);
|
|
164
|
+
if (!result.operatorVerified) failures.push(`${result.id}: submitted result must be operator verified`);
|
|
165
|
+
if (planTarget.manualRuleCheckRequired && !result.manualRuleCheckCompleted) {
|
|
166
|
+
failures.push(`${result.id}: submitted result must record manual rule check completion`);
|
|
167
|
+
}
|
|
168
|
+
if (PLATFORMS_REQUIRING_REPO_LINK.has(result.platform) && !includesGitHubRepoUrl(result)) {
|
|
169
|
+
failures.push(`${result.id}: submitted marketing result must include ${GITHUB_REPO_URL}`);
|
|
170
|
+
}
|
|
171
|
+
for (const check of planTarget.postSubmitChecks) {
|
|
172
|
+
if (!result.postSubmitChecksCompleted.includes(check)) {
|
|
173
|
+
failures.push(`${result.id}: missing completed post-submit check: ${check}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if ((result.status === 'failed' || result.status === 'skipped') && !result.blocker) {
|
|
179
|
+
failures.push(`${result.id}: ${result.status} result must record a blocker`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { failures, blockers };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export async function verifyBrowserLaunchResults(options = {}) {
|
|
186
|
+
const resultsPath = options.results ?? DEFAULT_RESULTS;
|
|
187
|
+
const schemaPath = options.schema ?? DEFAULT_SCHEMA;
|
|
188
|
+
const planPath = options.plan ?? DEFAULT_PLAN;
|
|
189
|
+
const results = readJson(resultsPath);
|
|
190
|
+
const schema = readJson(schemaPath);
|
|
191
|
+
const plan = readJson(planPath);
|
|
192
|
+
const planReport = await verifyBrowserLaunchPlan({ plan: planPath });
|
|
193
|
+
const planTargets = new Map((plan.targets ?? []).map(target => [target.id, target]));
|
|
194
|
+
const failures = [
|
|
195
|
+
...validateSchema(results, schema, 'audrey-browser-launch-results').map(failure => `browser launch results schema: ${failure}`),
|
|
196
|
+
];
|
|
197
|
+
const blockers = [];
|
|
198
|
+
const seen = new Set();
|
|
199
|
+
const targetReports = [];
|
|
200
|
+
|
|
201
|
+
if (!planReport.ok) {
|
|
202
|
+
failures.push(...planReport.failures.map(failure => `browser launch plan: ${failure}`));
|
|
203
|
+
}
|
|
204
|
+
if (results.plan !== planPath) {
|
|
205
|
+
failures.push(`browser launch results must point at ${planPath}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const result of results.targets ?? []) {
|
|
209
|
+
if (seen.has(result.id)) failures.push(`${result.id}: duplicate result id`);
|
|
210
|
+
seen.add(result.id);
|
|
211
|
+
const planTarget = planTargets.get(result.id);
|
|
212
|
+
const targetValidation = validateResultTarget(result, planTarget);
|
|
213
|
+
failures.push(...targetValidation.failures);
|
|
214
|
+
blockers.push(...targetValidation.blockers);
|
|
215
|
+
targetReports.push({
|
|
216
|
+
id: result.id,
|
|
217
|
+
platform: result.platform,
|
|
218
|
+
status: result.status,
|
|
219
|
+
publicUrl: result.publicUrl,
|
|
220
|
+
artifactUrl: result.artifactUrl,
|
|
221
|
+
operatorVerified: result.operatorVerified,
|
|
222
|
+
manualRuleCheckCompleted: result.manualRuleCheckCompleted,
|
|
223
|
+
ok: targetValidation.failures.length === 0,
|
|
224
|
+
failures: targetValidation.failures,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const planOrder = [...(plan.targets ?? [])].sort((a, b) => a.order - b.order).map(target => target.id);
|
|
229
|
+
const resultOrder = [...(results.targets ?? [])].map(target => target.id);
|
|
230
|
+
if (resultOrder.join('|') !== planOrder.join('|')) {
|
|
231
|
+
failures.push(`browser launch results order must be ${planOrder.join(', ')}`);
|
|
232
|
+
}
|
|
233
|
+
for (const id of planOrder) {
|
|
234
|
+
if (!seen.has(id)) failures.push(`Missing browser launch result: ${id}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const notSubmitted = targetReports.filter(target => target.status !== 'submitted').map(target => target.id);
|
|
238
|
+
const ready = failures.length === 0 && notSubmitted.length === 0;
|
|
239
|
+
if (options.strict === true && notSubmitted.length > 0) {
|
|
240
|
+
failures.push(`strict launch readiness requires submitted targets: ${notSubmitted.join(', ')}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
schemaVersion: '1.0.0',
|
|
245
|
+
suite: 'Audrey browser launch results verification',
|
|
246
|
+
generatedAt: new Date().toISOString(),
|
|
247
|
+
ok: failures.length === 0,
|
|
248
|
+
ready,
|
|
249
|
+
strict: options.strict === true,
|
|
250
|
+
results: publicPath(fromRoot(resultsPath)),
|
|
251
|
+
plan: publicPath(fromRoot(planPath)),
|
|
252
|
+
targets: targetReports,
|
|
253
|
+
blockers,
|
|
254
|
+
failures,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function main() {
|
|
259
|
+
const args = parseArgs();
|
|
260
|
+
if (args.help) {
|
|
261
|
+
console.log(usage());
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const report = await verifyBrowserLaunchResults(args);
|
|
266
|
+
if (args.json) {
|
|
267
|
+
console.log(JSON.stringify(report, null, 2));
|
|
268
|
+
} else if (report.ok) {
|
|
269
|
+
const submitted = report.targets.filter(target => target.status === 'submitted').length;
|
|
270
|
+
const pending = report.targets.length - submitted;
|
|
271
|
+
console.log(`Browser launch results verification passed: ${submitted} submitted, ${pending} pending`);
|
|
272
|
+
} else {
|
|
273
|
+
console.error('Browser launch results verification failed:');
|
|
274
|
+
for (const failure of report.failures) console.error(`- ${failure}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!report.ok) process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
281
|
+
main().catch(error => {
|
|
282
|
+
console.error(error.stack ?? error.message);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
});
|
|
285
|
+
}
|