agent-scenario-loop 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/app/profile-session.ts +812 -0
- package/core/config-template.json +41 -0
- package/dist/core/agent-summary.d.ts +15 -0
- package/dist/core/agent-summary.js +177 -0
- package/dist/core/artifact-contract.d.ts +151 -0
- package/dist/core/artifact-contract.js +897 -0
- package/dist/core/artifact-layout.d.ts +56 -0
- package/dist/core/artifact-layout.js +61 -0
- package/dist/core/artifact-writer.d.ts +44 -0
- package/dist/core/artifact-writer.js +55 -0
- package/dist/core/comparison.d.ts +133 -0
- package/dist/core/comparison.js +294 -0
- package/dist/core/evidence-interpreter.d.ts +28 -0
- package/dist/core/evidence-interpreter.js +69 -0
- package/dist/core/execution-plan.d.ts +44 -0
- package/dist/core/execution-plan.js +95 -0
- package/dist/core/planner.d.ts +132 -0
- package/dist/core/planner.js +812 -0
- package/dist/core/ports.d.ts +198 -0
- package/dist/core/ports.js +146 -0
- package/dist/core/run-index.d.ts +62 -0
- package/dist/core/run-index.js +143 -0
- package/dist/core/schema-validator.d.ts +86 -0
- package/dist/core/schema-validator.js +407 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +27 -0
- package/dist/runner/agent-device-driver.d.ts +126 -0
- package/dist/runner/agent-device-driver.js +168 -0
- package/dist/runner/agent-device.d.ts +295 -0
- package/dist/runner/agent-device.js +1271 -0
- package/dist/runner/android-adb-driver.d.ts +175 -0
- package/dist/runner/android-adb-driver.js +399 -0
- package/dist/runner/android-adb.d.ts +254 -0
- package/dist/runner/android-adb.js +1618 -0
- package/dist/runner/argent-driver.d.ts +183 -0
- package/dist/runner/argent-driver.js +297 -0
- package/dist/runner/argent.d.ts +349 -0
- package/dist/runner/argent.js +1211 -0
- package/dist/runner/check-plan.d.ts +45 -0
- package/dist/runner/check-plan.js +210 -0
- package/dist/runner/cli.d.ts +20 -0
- package/dist/runner/cli.js +23 -0
- package/dist/runner/compare-latest.d.ts +99 -0
- package/dist/runner/compare-latest.js +233 -0
- package/dist/runner/compare.d.ts +58 -0
- package/dist/runner/compare.js +157 -0
- package/dist/runner/demo-loop.d.ts +45 -0
- package/dist/runner/demo-loop.js +170 -0
- package/dist/runner/example-android-live.d.ts +137 -0
- package/dist/runner/example-android-live.js +454 -0
- package/dist/runner/example-ios-live.d.ts +137 -0
- package/dist/runner/example-ios-live.js +471 -0
- package/dist/runner/host-doctor.d.ts +131 -0
- package/dist/runner/host-doctor.js +628 -0
- package/dist/runner/init-project.d.ts +88 -0
- package/dist/runner/init-project.js +263 -0
- package/dist/runner/ios-simctl-driver.d.ts +69 -0
- package/dist/runner/ios-simctl-driver.js +97 -0
- package/dist/runner/ios-simctl.d.ts +254 -0
- package/dist/runner/ios-simctl.js +1415 -0
- package/dist/runner/live-android.d.ts +137 -0
- package/dist/runner/live-android.js +539 -0
- package/dist/runner/live-comparison.d.ts +67 -0
- package/dist/runner/live-comparison.js +147 -0
- package/dist/runner/live-ios.d.ts +137 -0
- package/dist/runner/live-ios.js +460 -0
- package/dist/runner/live-proof-summary.d.ts +263 -0
- package/dist/runner/live-proof-summary.js +465 -0
- package/dist/runner/live-proof.d.ts +467 -0
- package/dist/runner/live-proof.js +920 -0
- package/dist/runner/local-env.d.ts +64 -0
- package/dist/runner/local-env.js +155 -0
- package/dist/runner/profile-android.d.ts +82 -0
- package/dist/runner/profile-android.js +671 -0
- package/dist/runner/profile-ios.d.ts +108 -0
- package/dist/runner/profile-ios.js +532 -0
- package/dist/runner/profile-mobile.d.ts +254 -0
- package/dist/runner/profile-mobile.js +1307 -0
- package/dist/runner/validate-project.d.ts +273 -0
- package/dist/runner/validate-project.js +1501 -0
- package/docs/adapters.md +145 -0
- package/docs/api.md +94 -0
- package/docs/authoring.md +196 -0
- package/docs/concepts.md +136 -0
- package/docs/consumer-rehearsal.md +115 -0
- package/docs/contracts.md +267 -0
- package/docs/live-proofs.md +270 -0
- package/docs/principles.md +46 -0
- package/examples/event-logs/app-startup-baseline.log +4 -0
- package/examples/event-logs/app-startup-current.log +4 -0
- package/examples/minimal-app/README.md +70 -0
- package/examples/mobile-app/README.md +302 -0
- package/examples/mobile-app/app.json +22 -0
- package/examples/mobile-app/asl/package-scripts.json +32 -0
- package/examples/mobile-app/asl.config.json +37 -0
- package/examples/mobile-app/event-logs/android-app-startup.log +4 -0
- package/examples/mobile-app/event-logs/android-open-close-cycle.log +12 -0
- package/examples/mobile-app/event-logs/android-scroll-settle.log +12 -0
- package/examples/mobile-app/event-logs/app-startup.log +4 -0
- package/examples/mobile-app/event-logs/open-close-cycle.log +12 -0
- package/examples/mobile-app/event-logs/scroll-settle.log +12 -0
- package/examples/mobile-app/index.ts +20 -0
- package/examples/mobile-app/metro.config.js +20 -0
- package/examples/mobile-app/package.json +62 -0
- package/examples/mobile-app/patches/expo-modules-jsi@56.0.10.patch +19 -0
- package/examples/mobile-app/plugins/with-ios-build-compat.js +271 -0
- package/examples/mobile-app/pnpm-lock.yaml +4440 -0
- package/examples/mobile-app/runner-manifests/evidence-provider.json +79 -0
- package/examples/mobile-app/runner-manifests/primary-runner.json +19 -0
- package/examples/mobile-app/scenarios/android/app-startup-video.json +73 -0
- package/examples/mobile-app/scenarios/android/app-startup.json +44 -0
- package/examples/mobile-app/scenarios/android/open-close-cycle.json +54 -0
- package/examples/mobile-app/scenarios/android/scroll-settle.json +49 -0
- package/examples/mobile-app/scenarios/ios/app-startup.json +44 -0
- package/examples/mobile-app/scenarios/ios/open-close-cycle.json +54 -0
- package/examples/mobile-app/scenarios/ios/scroll-settle.json +49 -0
- package/examples/mobile-app/scenarios/mobile/app-startup.json +91 -0
- package/examples/mobile-app/scenarios/mobile/open-close-cycle.json +160 -0
- package/examples/mobile-app/scenarios/mobile/scroll-settle.json +148 -0
- package/examples/mobile-app/scripts/asl-capture-accessibility-provider.mjs +112 -0
- package/examples/mobile-app/scripts/asl-capture-profiler-provider.mjs +127 -0
- package/examples/mobile-app/src/devtools/profile-session.ts +7 -0
- package/examples/mobile-app/src/example-screen.tsx +322 -0
- package/examples/mobile-app/tsconfig.json +16 -0
- package/examples/mobile-app/tsconfig.typecheck.json +13 -0
- package/examples/runners/README.md +44 -0
- package/examples/runners/adb-android.json +25 -0
- package/examples/runners/agent-device-android.json +27 -0
- package/examples/runners/agent-device-ios.json +27 -0
- package/examples/runners/argent-android.json +32 -0
- package/examples/runners/argent-ios.json +32 -0
- package/examples/runners/argent-react-profiler-provider.json +15 -0
- package/examples/runners/axe-accessibility-provider.json +24 -0
- package/examples/runners/manual-log-ingest.json +9 -0
- package/examples/runners/rozenite-profiler-provider.json +9 -0
- package/examples/runners/script-accessibility-provider.json +24 -0
- package/examples/runners/script-memory-provider.json +24 -0
- package/examples/runners/script-network-provider.json +24 -0
- package/examples/runners/script-profiler-provider.json +30 -0
- package/examples/runners/xcodebuildmcp-ios.json +29 -0
- package/examples/scenarios/ios/app-startup.json +28 -0
- package/examples/scenarios/ios/open-close-cycle.json +35 -0
- package/examples/scenarios/mobile/app-startup.json +72 -0
- package/examples/scenarios/mobile/media-open-close.json +141 -0
- package/examples/scenarios/mobile/open-close-cycle.json +135 -0
- package/examples/scenarios/mobile/scroll-settle.json +106 -0
- package/package.json +240 -0
- package/schemas/budget-verdict.schema.json +115 -0
- package/schemas/causal-run.schema.json +279 -0
- package/schemas/comparison.schema.json +196 -0
- package/schemas/health.schema.json +108 -0
- package/schemas/live-proof-set.schema.json +195 -0
- package/schemas/live-proof.schema.json +413 -0
- package/schemas/manifest.schema.json +204 -0
- package/schemas/metrics.schema.json +137 -0
- package/schemas/project-validation.schema.json +343 -0
- package/schemas/runner-capabilities.schema.json +217 -0
- package/schemas/scenario.schema.json +400 -0
- package/schemas/verdict.schema.json +88 -0
- package/templates/evidence-provider.json +83 -0
- package/templates/gitignore-snippet +9 -0
- package/templates/integration-readme.md +125 -0
- package/templates/mobile-scenario.json +133 -0
- package/templates/package-scripts.json +32 -0
- package/templates/primary-runner.json +19 -0
- package/templates/project.config.json +37 -0
- package/templates/scripts/asl-capture-accessibility-provider.mjs +112 -0
- package/templates/scripts/asl-capture-profiler-provider.mjs +127 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.assertNoRegressedComparison = assertNoRegressedComparison;
|
|
5
|
+
exports.isEnabledFlag = isEnabledFlag;
|
|
6
|
+
exports.main = main;
|
|
7
|
+
exports.parseArgs = parseArgs;
|
|
8
|
+
exports.resolveOutput = resolveOutput;
|
|
9
|
+
exports.usage = usage;
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const { buildAgentSummaryMarkdown } = require('../core/agent-summary');
|
|
12
|
+
const { compareRunDirectories, readRunArtifacts } = require('../core/comparison');
|
|
13
|
+
const { createArtifactLayout } = require('../core/artifact-layout');
|
|
14
|
+
const { writeJsonArtifact, writeTextArtifact } = require('../core/artifact-writer');
|
|
15
|
+
const { SCHEMAS } = require('../core/schema-validator');
|
|
16
|
+
const { hasHelpFlag, writeUsage } = require('./cli');
|
|
17
|
+
/**
|
|
18
|
+
* Prints CLI usage to stderr.
|
|
19
|
+
*
|
|
20
|
+
* @returns {void}
|
|
21
|
+
*/
|
|
22
|
+
function usage(output = process.stderr) {
|
|
23
|
+
writeUsage([
|
|
24
|
+
'Usage: asl-compare --baseline <run-dir> --current <run-dir> [--out <comparison.json|run-dir>] [--fail-on-regression]',
|
|
25
|
+
'',
|
|
26
|
+
'Without --out, prints comparison.json to stdout.',
|
|
27
|
+
'When --out points at a directory, writes comparison.json and agent-summary.md there.',
|
|
28
|
+
'Use --fail-on-regression to exit nonzero after writing evidence when comparisonStatus is worse.',
|
|
29
|
+
], output);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parses `--key value` arguments for the comparison CLI.
|
|
33
|
+
*
|
|
34
|
+
* @param {string[]} argv
|
|
35
|
+
* @returns {CliArgs}
|
|
36
|
+
*/
|
|
37
|
+
function parseArgs(argv) {
|
|
38
|
+
const args = {};
|
|
39
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
40
|
+
const token = argv[index];
|
|
41
|
+
if (!token || !token.startsWith('--')) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const key = token.slice(2);
|
|
45
|
+
const value = argv[index + 1];
|
|
46
|
+
if (value && !value.startsWith('--')) {
|
|
47
|
+
args[key] = value;
|
|
48
|
+
index += 1;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
args[key] = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return args;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolves `--out` as either an explicit JSON file or a run directory.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} out
|
|
60
|
+
* @returns {{comparisonPath: string, summaryPath: string | null, printedPath: string}}
|
|
61
|
+
*/
|
|
62
|
+
function resolveOutput(out) {
|
|
63
|
+
const resolved = path.resolve(out);
|
|
64
|
+
if (path.extname(resolved) === '.json') {
|
|
65
|
+
return {
|
|
66
|
+
comparisonPath: resolved,
|
|
67
|
+
summaryPath: null,
|
|
68
|
+
printedPath: resolved,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const layout = createArtifactLayout({ outputDir: resolved });
|
|
72
|
+
return {
|
|
73
|
+
comparisonPath: layout.comparison,
|
|
74
|
+
summaryPath: layout.agentSummary,
|
|
75
|
+
printedPath: resolved,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Returns whether a boolean CLI flag was provided.
|
|
80
|
+
*
|
|
81
|
+
* @param {unknown} value
|
|
82
|
+
* @returns {boolean}
|
|
83
|
+
*/
|
|
84
|
+
function isEnabledFlag(value) {
|
|
85
|
+
return value === true || value === 'true';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Throws when a comparison result should fail a strict regression gate.
|
|
89
|
+
*
|
|
90
|
+
* @param {{comparison: Record<string, unknown>, evidencePath?: string}} options
|
|
91
|
+
* @returns {void}
|
|
92
|
+
*/
|
|
93
|
+
function assertNoRegressedComparison({ comparison, evidencePath, }) {
|
|
94
|
+
if (comparison.comparisonStatus !== 'worse') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const runId = typeof comparison.runId === 'string' ? comparison.runId : 'current run';
|
|
98
|
+
const evidenceHint = evidencePath ? ` Inspect ${evidencePath}.` : '';
|
|
99
|
+
throw new Error(`Comparison regressed for ${runId}.${evidenceHint}`);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Runs the compare CLI.
|
|
103
|
+
*
|
|
104
|
+
* @returns {Promise<void>}
|
|
105
|
+
*/
|
|
106
|
+
async function main() {
|
|
107
|
+
const argv = process.argv.slice(2);
|
|
108
|
+
if (hasHelpFlag(argv)) {
|
|
109
|
+
usage(process.stdout);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const args = parseArgs(argv);
|
|
113
|
+
if (typeof args.baseline !== 'string' || typeof args.current !== 'string') {
|
|
114
|
+
usage();
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const baselineDir = path.resolve(args.baseline);
|
|
119
|
+
const currentDir = path.resolve(args.current);
|
|
120
|
+
const comparison = compareRunDirectories({ baselineDir, currentDir });
|
|
121
|
+
const failOnRegression = isEnabledFlag(args['fail-on-regression']);
|
|
122
|
+
if (typeof args.out === 'string' && args.out.length > 0) {
|
|
123
|
+
const { comparisonPath, summaryPath, printedPath } = resolveOutput(args.out);
|
|
124
|
+
await writeJsonArtifact({
|
|
125
|
+
filePath: comparisonPath,
|
|
126
|
+
value: comparison,
|
|
127
|
+
schema: SCHEMAS.comparison,
|
|
128
|
+
label: 'Comparison artifact',
|
|
129
|
+
});
|
|
130
|
+
if (summaryPath) {
|
|
131
|
+
const current = readRunArtifacts(currentDir);
|
|
132
|
+
await writeTextArtifact({
|
|
133
|
+
filePath: summaryPath,
|
|
134
|
+
content: buildAgentSummaryMarkdown({
|
|
135
|
+
health: current.health,
|
|
136
|
+
verdict: current.verdict,
|
|
137
|
+
comparison,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
process.stdout.write(`${printedPath}\n`);
|
|
142
|
+
if (failOnRegression) {
|
|
143
|
+
assertNoRegressedComparison({ comparison, evidencePath: printedPath });
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
process.stdout.write(`${JSON.stringify(comparison, null, 2)}\n`);
|
|
148
|
+
if (failOnRegression) {
|
|
149
|
+
assertNoRegressedComparison({ comparison });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (require.main === module) {
|
|
153
|
+
main().catch((error) => {
|
|
154
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
155
|
+
process.exitCode = 1;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type CliArgs = {
|
|
3
|
+
out?: string | boolean;
|
|
4
|
+
[key: string]: string | boolean | undefined;
|
|
5
|
+
};
|
|
6
|
+
type DemoLoopResult = {
|
|
7
|
+
baselineRunDir: string;
|
|
8
|
+
comparison: Record<string, unknown>;
|
|
9
|
+
currentRunDir: string;
|
|
10
|
+
outputDir: string;
|
|
11
|
+
preflightDir: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Prints CLI usage.
|
|
15
|
+
*
|
|
16
|
+
* @param {{write: (message: string) => unknown}} [output]
|
|
17
|
+
* @returns {void}
|
|
18
|
+
*/
|
|
19
|
+
declare function usage(output?: {
|
|
20
|
+
write: (message: string) => unknown;
|
|
21
|
+
}): void;
|
|
22
|
+
/**
|
|
23
|
+
* Parses `--key value` arguments for the fixture demo loop.
|
|
24
|
+
*
|
|
25
|
+
* @param {string[]} argv
|
|
26
|
+
* @returns {CliArgs}
|
|
27
|
+
*/
|
|
28
|
+
declare function parseArgs(argv: string[]): CliArgs;
|
|
29
|
+
/**
|
|
30
|
+
* Writes a fixture-backed preflight, profile history, current profile, and latest-trusted comparison.
|
|
31
|
+
*
|
|
32
|
+
* @param {{outputDir?: string}} options
|
|
33
|
+
* @returns {Promise<DemoLoopResult>}
|
|
34
|
+
*/
|
|
35
|
+
declare function runDemoLoop({ outputDir }?: {
|
|
36
|
+
outputDir?: string;
|
|
37
|
+
}): Promise<DemoLoopResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Runs the fixture demo CLI.
|
|
40
|
+
*
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
declare function main(): Promise<void>;
|
|
44
|
+
export { main, parseArgs, runDemoLoop, usage, };
|
|
45
|
+
export type { CliArgs, DemoLoopResult, };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.main = main;
|
|
5
|
+
exports.parseArgs = parseArgs;
|
|
6
|
+
exports.runDemoLoop = runDemoLoop;
|
|
7
|
+
exports.usage = usage;
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const { buildAgentSummaryMarkdown } = require('../core/agent-summary');
|
|
10
|
+
const { createArtifactLayout } = require('../core/artifact-layout');
|
|
11
|
+
const { writeJsonArtifact, writeTextArtifact } = require('../core/artifact-writer');
|
|
12
|
+
const { readRunArtifacts } = require('../core/comparison');
|
|
13
|
+
const { SCHEMAS } = require('../core/schema-validator');
|
|
14
|
+
const { buildPlanArtifacts } = require('./check-plan');
|
|
15
|
+
const { hasHelpFlag, writeUsage } = require('./cli');
|
|
16
|
+
const { compareLatestTrustedRun } = require('./compare-latest');
|
|
17
|
+
const { runProfileIos } = require('./profile-ios');
|
|
18
|
+
/**
|
|
19
|
+
* Prints CLI usage.
|
|
20
|
+
*
|
|
21
|
+
* @param {{write: (message: string) => unknown}} [output]
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
function usage(output = process.stderr) {
|
|
25
|
+
writeUsage([
|
|
26
|
+
'Usage: asl-demo-loop [--out <dir>]',
|
|
27
|
+
'',
|
|
28
|
+
'Runs the fixture preflight, baseline/current profile logs, and comparison without a simulator.',
|
|
29
|
+
], output);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parses `--key value` arguments for the fixture demo loop.
|
|
33
|
+
*
|
|
34
|
+
* @param {string[]} argv
|
|
35
|
+
* @returns {CliArgs}
|
|
36
|
+
*/
|
|
37
|
+
function parseArgs(argv) {
|
|
38
|
+
const args = {};
|
|
39
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
40
|
+
const token = argv[index];
|
|
41
|
+
if (!token || !token.startsWith('--')) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const key = token.slice(2);
|
|
45
|
+
const value = argv[index + 1];
|
|
46
|
+
if (value && !value.startsWith('--')) {
|
|
47
|
+
args[key] = value;
|
|
48
|
+
index += 1;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
args[key] = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return args;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Writes a fixture-backed preflight, profile history, current profile, and latest-trusted comparison.
|
|
58
|
+
*
|
|
59
|
+
* @param {{outputDir?: string}} options
|
|
60
|
+
* @returns {Promise<DemoLoopResult>}
|
|
61
|
+
*/
|
|
62
|
+
async function runDemoLoop({ outputDir = path.resolve('artifacts/demo-loop') } = {}) {
|
|
63
|
+
const root = process.cwd();
|
|
64
|
+
const resolvedOutputDir = path.resolve(outputDir);
|
|
65
|
+
const preflightDir = path.join(resolvedOutputDir, 'preflight', 'app-startup');
|
|
66
|
+
const profileRoot = path.join(resolvedOutputDir, 'profile-runs');
|
|
67
|
+
const configPath = path.join(root, 'core/config-template.json');
|
|
68
|
+
const profileScenarioPath = path.join(root, 'examples/scenarios/ios/app-startup.json');
|
|
69
|
+
const mobileScenarioPath = path.join(root, 'examples/scenarios/mobile/app-startup.json');
|
|
70
|
+
const runnerPath = path.join(root, 'examples/runners/xcodebuildmcp-ios.json');
|
|
71
|
+
const baselineLogPath = path.join(root, 'examples/event-logs/app-startup-baseline.log');
|
|
72
|
+
const currentLogPath = path.join(root, 'examples/event-logs/app-startup-current.log');
|
|
73
|
+
const preflight = await buildPlanArtifacts({
|
|
74
|
+
scenarioPath: mobileScenarioPath,
|
|
75
|
+
runnerPath,
|
|
76
|
+
platform: 'ios',
|
|
77
|
+
runId: 'demo-preflight',
|
|
78
|
+
});
|
|
79
|
+
const preflightLayout = createArtifactLayout({ outputDir: preflightDir });
|
|
80
|
+
await writeJsonArtifact({
|
|
81
|
+
filePath: preflightLayout.health,
|
|
82
|
+
value: preflight.health,
|
|
83
|
+
schema: SCHEMAS.health,
|
|
84
|
+
label: 'Health artifact',
|
|
85
|
+
});
|
|
86
|
+
await writeJsonArtifact({
|
|
87
|
+
filePath: preflightLayout.verdict,
|
|
88
|
+
value: preflight.verdict,
|
|
89
|
+
schema: SCHEMAS.verdict,
|
|
90
|
+
label: 'Verdict artifact',
|
|
91
|
+
});
|
|
92
|
+
await writeTextArtifact({
|
|
93
|
+
filePath: preflightLayout.agentSummary,
|
|
94
|
+
content: preflight.agentSummary,
|
|
95
|
+
});
|
|
96
|
+
await writeJsonArtifact({
|
|
97
|
+
filePath: preflightLayout.plannerCompatibility,
|
|
98
|
+
value: preflight.compatibility,
|
|
99
|
+
schema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
additionalProperties: true,
|
|
102
|
+
},
|
|
103
|
+
label: 'Planner compatibility artifact',
|
|
104
|
+
});
|
|
105
|
+
await runProfileIos({
|
|
106
|
+
config: configPath,
|
|
107
|
+
events: baselineLogPath,
|
|
108
|
+
out: profileRoot,
|
|
109
|
+
scenario: profileScenarioPath,
|
|
110
|
+
'run-id': 'demo-baseline',
|
|
111
|
+
});
|
|
112
|
+
const current = await runProfileIos({
|
|
113
|
+
config: configPath,
|
|
114
|
+
events: currentLogPath,
|
|
115
|
+
out: profileRoot,
|
|
116
|
+
scenario: profileScenarioPath,
|
|
117
|
+
'run-id': 'demo-current',
|
|
118
|
+
});
|
|
119
|
+
const latestComparison = compareLatestTrustedRun({
|
|
120
|
+
rootDir: profileRoot,
|
|
121
|
+
scenarioId: 'app-startup',
|
|
122
|
+
currentDir: current.runDir,
|
|
123
|
+
});
|
|
124
|
+
const currentLayout = createArtifactLayout({ outputDir: current.runDir });
|
|
125
|
+
await writeJsonArtifact({
|
|
126
|
+
filePath: currentLayout.comparison,
|
|
127
|
+
value: latestComparison.comparison,
|
|
128
|
+
schema: SCHEMAS.comparison,
|
|
129
|
+
label: 'Comparison artifact',
|
|
130
|
+
});
|
|
131
|
+
const currentArtifacts = readRunArtifacts(current.runDir);
|
|
132
|
+
await writeTextArtifact({
|
|
133
|
+
filePath: currentLayout.agentSummary,
|
|
134
|
+
content: buildAgentSummaryMarkdown({
|
|
135
|
+
health: currentArtifacts.health,
|
|
136
|
+
verdict: currentArtifacts.verdict,
|
|
137
|
+
comparison: latestComparison.comparison,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
baselineRunDir: latestComparison.baselineDir,
|
|
142
|
+
comparison: latestComparison.comparison,
|
|
143
|
+
currentRunDir: current.runDir,
|
|
144
|
+
outputDir: resolvedOutputDir,
|
|
145
|
+
preflightDir,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Runs the fixture demo CLI.
|
|
150
|
+
*
|
|
151
|
+
* @returns {Promise<void>}
|
|
152
|
+
*/
|
|
153
|
+
async function main() {
|
|
154
|
+
const argv = process.argv.slice(2);
|
|
155
|
+
if (hasHelpFlag(argv)) {
|
|
156
|
+
usage(process.stdout);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const args = parseArgs(argv);
|
|
160
|
+
const result = await runDemoLoop({
|
|
161
|
+
...(typeof args.out === 'string' ? { outputDir: args.out } : {}),
|
|
162
|
+
});
|
|
163
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
164
|
+
}
|
|
165
|
+
if (require.main === module) {
|
|
166
|
+
main().catch((error) => {
|
|
167
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
168
|
+
process.exitCode = 1;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type CliArgs = import('./android-adb').CliArgs;
|
|
3
|
+
type LiveComparisonResult = import('./live-comparison').LiveComparisonResult;
|
|
4
|
+
type LiveProofSummaryResult = import('./live-proof-summary').LiveProofSummaryResult;
|
|
5
|
+
type AndroidLiveProofOptions = {
|
|
6
|
+
agentDeviceExecutor?: import('./agent-device').CommandExecutor;
|
|
7
|
+
argentExecutor?: import('./argent').CommandExecutor;
|
|
8
|
+
delay?: (ms: number) => Promise<void>;
|
|
9
|
+
executor?: import('./android-adb').CommandExecutor;
|
|
10
|
+
packageRoot?: string;
|
|
11
|
+
};
|
|
12
|
+
type AndroidInteractionProof = {
|
|
13
|
+
label: string;
|
|
14
|
+
runDir: string;
|
|
15
|
+
runId: string;
|
|
16
|
+
runnerId: string;
|
|
17
|
+
scenarioId: string;
|
|
18
|
+
};
|
|
19
|
+
type AndroidSkippedInteractionProof = import('./live-proof-summary').LiveProofSkippedInteractionProofPointer;
|
|
20
|
+
type AndroidLiveProfile = {
|
|
21
|
+
healthStatus?: string;
|
|
22
|
+
label: string;
|
|
23
|
+
runDir: string;
|
|
24
|
+
runId: string;
|
|
25
|
+
scenario: string;
|
|
26
|
+
scenarioId: string;
|
|
27
|
+
verdictStatus?: string;
|
|
28
|
+
};
|
|
29
|
+
type AndroidLiveProofResult = {
|
|
30
|
+
aggregateSummary: LiveProofSummaryResult;
|
|
31
|
+
comparisons: LiveComparisonResult[];
|
|
32
|
+
interactionProofs: AndroidInteractionProof[];
|
|
33
|
+
outputDir: string;
|
|
34
|
+
preflightDir: string;
|
|
35
|
+
profiles: AndroidLiveProfile[];
|
|
36
|
+
skippedInteractionProofs: AndroidSkippedInteractionProof[];
|
|
37
|
+
};
|
|
38
|
+
type RegressionGateOptions = {
|
|
39
|
+
platformLabel: string;
|
|
40
|
+
result: AndroidLiveProofResult;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Prints CLI usage.
|
|
44
|
+
*
|
|
45
|
+
* @param {{write: (message: string) => unknown}} [output]
|
|
46
|
+
* @returns {void}
|
|
47
|
+
*/
|
|
48
|
+
declare function usage(output?: {
|
|
49
|
+
write: (message: string) => unknown;
|
|
50
|
+
}): void;
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the Android target used by every example proof lane.
|
|
53
|
+
*
|
|
54
|
+
* @param {CliArgs} args
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
declare function resolveAndroidSerial(args: CliArgs): string;
|
|
58
|
+
/**
|
|
59
|
+
* Converts a caller-provided run suffix into a path-safe run-id segment.
|
|
60
|
+
*
|
|
61
|
+
* @param {unknown} value
|
|
62
|
+
* @returns {string | null}
|
|
63
|
+
*/
|
|
64
|
+
declare function normalizeRunSuffix(value: unknown): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Applies the optional run suffix while preserving deterministic defaults.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} baseRunId
|
|
69
|
+
* @param {string | null} suffix
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
declare function buildLiveRunId(baseRunId: string, suffix: string | null): string;
|
|
73
|
+
/**
|
|
74
|
+
* Builds the comparison lane suffix for enabled interaction proofs.
|
|
75
|
+
*
|
|
76
|
+
* @param {string[]} runnerIds
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
79
|
+
declare function buildInteractionComparisonLane(runnerIds: string[]): string;
|
|
80
|
+
/**
|
|
81
|
+
* Reports whether profile evidence is healthy enough to trust sidecar proofs and comparisons.
|
|
82
|
+
*
|
|
83
|
+
* @param {{health: Record<string, unknown>, verdict: Record<string, unknown>}} run
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
declare function isTrustedProfileRun({ health, verdict, }: {
|
|
87
|
+
health: Record<string, unknown>;
|
|
88
|
+
verdict: Record<string, unknown>;
|
|
89
|
+
}): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Builds skipped sidecar pointers for requested example runners when the profile batch failed.
|
|
92
|
+
*
|
|
93
|
+
* @param {{failedProfiles: AndroidLiveProfile[], requestedRunners: string[], runIdsByRunner: Record<string, string>}} options
|
|
94
|
+
* @returns {AndroidSkippedInteractionProof[]}
|
|
95
|
+
*/
|
|
96
|
+
declare function buildSkippedInteractionProofs({ failedProfiles, requestedRunners, runIdsByRunner, }: {
|
|
97
|
+
failedProfiles: AndroidLiveProfile[];
|
|
98
|
+
requestedRunners: string[];
|
|
99
|
+
runIdsByRunner: Record<string, string>;
|
|
100
|
+
}): AndroidSkippedInteractionProof[];
|
|
101
|
+
/**
|
|
102
|
+
* Throws after aggregate proof writing when the live proof itself failed.
|
|
103
|
+
*
|
|
104
|
+
* @param {AndroidLiveProofResult} result
|
|
105
|
+
* @returns {void}
|
|
106
|
+
*/
|
|
107
|
+
declare function assertAggregatePassed(result: AndroidLiveProofResult): void;
|
|
108
|
+
/**
|
|
109
|
+
* Throws after aggregate proof writing when fail-on-regression should gate the run.
|
|
110
|
+
*
|
|
111
|
+
* @param {RegressionGateOptions} options
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
114
|
+
declare function assertNoRegressedComparisons({ platformLabel, result, }: RegressionGateOptions): void;
|
|
115
|
+
/**
|
|
116
|
+
* Runs adb preflight plus all canonical Android example live profiles.
|
|
117
|
+
*
|
|
118
|
+
* @param {CliArgs} args
|
|
119
|
+
* @param {AndroidLiveProofOptions} [options]
|
|
120
|
+
* @returns {Promise<AndroidLiveProofResult>}
|
|
121
|
+
*/
|
|
122
|
+
declare function runExampleAndroidLiveProof(args: CliArgs, options?: AndroidLiveProofOptions): Promise<AndroidLiveProofResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Formats the live proof result for humans and agents.
|
|
125
|
+
*
|
|
126
|
+
* @param {AndroidLiveProofResult} result
|
|
127
|
+
* @returns {string}
|
|
128
|
+
*/
|
|
129
|
+
declare function formatResult(result: AndroidLiveProofResult): string;
|
|
130
|
+
/**
|
|
131
|
+
* Runs the example Android live proof CLI.
|
|
132
|
+
*
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
declare function main(): Promise<void>;
|
|
136
|
+
export { assertAggregatePassed, formatResult, assertNoRegressedComparisons, buildLiveRunId, buildSkippedInteractionProofs, buildInteractionComparisonLane, isTrustedProfileRun, main, normalizeRunSuffix, resolveAndroidSerial, runExampleAndroidLiveProof, usage, };
|
|
137
|
+
export type { AndroidLiveProofOptions, AndroidInteractionProof, AndroidLiveProofResult, AndroidLiveProfile, };
|