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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/app/profile-session.ts +812 -0
  4. package/core/config-template.json +41 -0
  5. package/dist/core/agent-summary.d.ts +15 -0
  6. package/dist/core/agent-summary.js +177 -0
  7. package/dist/core/artifact-contract.d.ts +151 -0
  8. package/dist/core/artifact-contract.js +897 -0
  9. package/dist/core/artifact-layout.d.ts +56 -0
  10. package/dist/core/artifact-layout.js +61 -0
  11. package/dist/core/artifact-writer.d.ts +44 -0
  12. package/dist/core/artifact-writer.js +55 -0
  13. package/dist/core/comparison.d.ts +133 -0
  14. package/dist/core/comparison.js +294 -0
  15. package/dist/core/evidence-interpreter.d.ts +28 -0
  16. package/dist/core/evidence-interpreter.js +69 -0
  17. package/dist/core/execution-plan.d.ts +44 -0
  18. package/dist/core/execution-plan.js +95 -0
  19. package/dist/core/planner.d.ts +132 -0
  20. package/dist/core/planner.js +812 -0
  21. package/dist/core/ports.d.ts +198 -0
  22. package/dist/core/ports.js +146 -0
  23. package/dist/core/run-index.d.ts +62 -0
  24. package/dist/core/run-index.js +143 -0
  25. package/dist/core/schema-validator.d.ts +86 -0
  26. package/dist/core/schema-validator.js +407 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.js +27 -0
  29. package/dist/runner/agent-device-driver.d.ts +126 -0
  30. package/dist/runner/agent-device-driver.js +168 -0
  31. package/dist/runner/agent-device.d.ts +295 -0
  32. package/dist/runner/agent-device.js +1271 -0
  33. package/dist/runner/android-adb-driver.d.ts +175 -0
  34. package/dist/runner/android-adb-driver.js +399 -0
  35. package/dist/runner/android-adb.d.ts +254 -0
  36. package/dist/runner/android-adb.js +1618 -0
  37. package/dist/runner/argent-driver.d.ts +183 -0
  38. package/dist/runner/argent-driver.js +297 -0
  39. package/dist/runner/argent.d.ts +349 -0
  40. package/dist/runner/argent.js +1211 -0
  41. package/dist/runner/check-plan.d.ts +45 -0
  42. package/dist/runner/check-plan.js +210 -0
  43. package/dist/runner/cli.d.ts +20 -0
  44. package/dist/runner/cli.js +23 -0
  45. package/dist/runner/compare-latest.d.ts +99 -0
  46. package/dist/runner/compare-latest.js +233 -0
  47. package/dist/runner/compare.d.ts +58 -0
  48. package/dist/runner/compare.js +157 -0
  49. package/dist/runner/demo-loop.d.ts +45 -0
  50. package/dist/runner/demo-loop.js +170 -0
  51. package/dist/runner/example-android-live.d.ts +137 -0
  52. package/dist/runner/example-android-live.js +454 -0
  53. package/dist/runner/example-ios-live.d.ts +137 -0
  54. package/dist/runner/example-ios-live.js +471 -0
  55. package/dist/runner/host-doctor.d.ts +131 -0
  56. package/dist/runner/host-doctor.js +628 -0
  57. package/dist/runner/init-project.d.ts +88 -0
  58. package/dist/runner/init-project.js +263 -0
  59. package/dist/runner/ios-simctl-driver.d.ts +69 -0
  60. package/dist/runner/ios-simctl-driver.js +97 -0
  61. package/dist/runner/ios-simctl.d.ts +254 -0
  62. package/dist/runner/ios-simctl.js +1415 -0
  63. package/dist/runner/live-android.d.ts +137 -0
  64. package/dist/runner/live-android.js +539 -0
  65. package/dist/runner/live-comparison.d.ts +67 -0
  66. package/dist/runner/live-comparison.js +147 -0
  67. package/dist/runner/live-ios.d.ts +137 -0
  68. package/dist/runner/live-ios.js +460 -0
  69. package/dist/runner/live-proof-summary.d.ts +263 -0
  70. package/dist/runner/live-proof-summary.js +465 -0
  71. package/dist/runner/live-proof.d.ts +467 -0
  72. package/dist/runner/live-proof.js +920 -0
  73. package/dist/runner/local-env.d.ts +64 -0
  74. package/dist/runner/local-env.js +155 -0
  75. package/dist/runner/profile-android.d.ts +82 -0
  76. package/dist/runner/profile-android.js +671 -0
  77. package/dist/runner/profile-ios.d.ts +108 -0
  78. package/dist/runner/profile-ios.js +532 -0
  79. package/dist/runner/profile-mobile.d.ts +254 -0
  80. package/dist/runner/profile-mobile.js +1307 -0
  81. package/dist/runner/validate-project.d.ts +273 -0
  82. package/dist/runner/validate-project.js +1501 -0
  83. package/docs/adapters.md +145 -0
  84. package/docs/api.md +94 -0
  85. package/docs/authoring.md +196 -0
  86. package/docs/concepts.md +136 -0
  87. package/docs/consumer-rehearsal.md +115 -0
  88. package/docs/contracts.md +267 -0
  89. package/docs/live-proofs.md +270 -0
  90. package/docs/principles.md +46 -0
  91. package/examples/event-logs/app-startup-baseline.log +4 -0
  92. package/examples/event-logs/app-startup-current.log +4 -0
  93. package/examples/minimal-app/README.md +70 -0
  94. package/examples/mobile-app/README.md +302 -0
  95. package/examples/mobile-app/app.json +22 -0
  96. package/examples/mobile-app/asl/package-scripts.json +32 -0
  97. package/examples/mobile-app/asl.config.json +37 -0
  98. package/examples/mobile-app/event-logs/android-app-startup.log +4 -0
  99. package/examples/mobile-app/event-logs/android-open-close-cycle.log +12 -0
  100. package/examples/mobile-app/event-logs/android-scroll-settle.log +12 -0
  101. package/examples/mobile-app/event-logs/app-startup.log +4 -0
  102. package/examples/mobile-app/event-logs/open-close-cycle.log +12 -0
  103. package/examples/mobile-app/event-logs/scroll-settle.log +12 -0
  104. package/examples/mobile-app/index.ts +20 -0
  105. package/examples/mobile-app/metro.config.js +20 -0
  106. package/examples/mobile-app/package.json +62 -0
  107. package/examples/mobile-app/patches/expo-modules-jsi@56.0.10.patch +19 -0
  108. package/examples/mobile-app/plugins/with-ios-build-compat.js +271 -0
  109. package/examples/mobile-app/pnpm-lock.yaml +4440 -0
  110. package/examples/mobile-app/runner-manifests/evidence-provider.json +79 -0
  111. package/examples/mobile-app/runner-manifests/primary-runner.json +19 -0
  112. package/examples/mobile-app/scenarios/android/app-startup-video.json +73 -0
  113. package/examples/mobile-app/scenarios/android/app-startup.json +44 -0
  114. package/examples/mobile-app/scenarios/android/open-close-cycle.json +54 -0
  115. package/examples/mobile-app/scenarios/android/scroll-settle.json +49 -0
  116. package/examples/mobile-app/scenarios/ios/app-startup.json +44 -0
  117. package/examples/mobile-app/scenarios/ios/open-close-cycle.json +54 -0
  118. package/examples/mobile-app/scenarios/ios/scroll-settle.json +49 -0
  119. package/examples/mobile-app/scenarios/mobile/app-startup.json +91 -0
  120. package/examples/mobile-app/scenarios/mobile/open-close-cycle.json +160 -0
  121. package/examples/mobile-app/scenarios/mobile/scroll-settle.json +148 -0
  122. package/examples/mobile-app/scripts/asl-capture-accessibility-provider.mjs +112 -0
  123. package/examples/mobile-app/scripts/asl-capture-profiler-provider.mjs +127 -0
  124. package/examples/mobile-app/src/devtools/profile-session.ts +7 -0
  125. package/examples/mobile-app/src/example-screen.tsx +322 -0
  126. package/examples/mobile-app/tsconfig.json +16 -0
  127. package/examples/mobile-app/tsconfig.typecheck.json +13 -0
  128. package/examples/runners/README.md +44 -0
  129. package/examples/runners/adb-android.json +25 -0
  130. package/examples/runners/agent-device-android.json +27 -0
  131. package/examples/runners/agent-device-ios.json +27 -0
  132. package/examples/runners/argent-android.json +32 -0
  133. package/examples/runners/argent-ios.json +32 -0
  134. package/examples/runners/argent-react-profiler-provider.json +15 -0
  135. package/examples/runners/axe-accessibility-provider.json +24 -0
  136. package/examples/runners/manual-log-ingest.json +9 -0
  137. package/examples/runners/rozenite-profiler-provider.json +9 -0
  138. package/examples/runners/script-accessibility-provider.json +24 -0
  139. package/examples/runners/script-memory-provider.json +24 -0
  140. package/examples/runners/script-network-provider.json +24 -0
  141. package/examples/runners/script-profiler-provider.json +30 -0
  142. package/examples/runners/xcodebuildmcp-ios.json +29 -0
  143. package/examples/scenarios/ios/app-startup.json +28 -0
  144. package/examples/scenarios/ios/open-close-cycle.json +35 -0
  145. package/examples/scenarios/mobile/app-startup.json +72 -0
  146. package/examples/scenarios/mobile/media-open-close.json +141 -0
  147. package/examples/scenarios/mobile/open-close-cycle.json +135 -0
  148. package/examples/scenarios/mobile/scroll-settle.json +106 -0
  149. package/package.json +240 -0
  150. package/schemas/budget-verdict.schema.json +115 -0
  151. package/schemas/causal-run.schema.json +279 -0
  152. package/schemas/comparison.schema.json +196 -0
  153. package/schemas/health.schema.json +108 -0
  154. package/schemas/live-proof-set.schema.json +195 -0
  155. package/schemas/live-proof.schema.json +413 -0
  156. package/schemas/manifest.schema.json +204 -0
  157. package/schemas/metrics.schema.json +137 -0
  158. package/schemas/project-validation.schema.json +343 -0
  159. package/schemas/runner-capabilities.schema.json +217 -0
  160. package/schemas/scenario.schema.json +400 -0
  161. package/schemas/verdict.schema.json +88 -0
  162. package/templates/evidence-provider.json +83 -0
  163. package/templates/gitignore-snippet +9 -0
  164. package/templates/integration-readme.md +125 -0
  165. package/templates/mobile-scenario.json +133 -0
  166. package/templates/package-scripts.json +32 -0
  167. package/templates/primary-runner.json +19 -0
  168. package/templates/project.config.json +37 -0
  169. package/templates/scripts/asl-capture-accessibility-provider.mjs +112 -0
  170. package/templates/scripts/asl-capture-profiler-provider.mjs +127 -0
@@ -0,0 +1,407 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaValidationError = exports.SCHEMAS = void 0;
4
+ exports.assertValidJson = assertValidJson;
5
+ exports.formatValidationErrorMessage = formatValidationErrorMessage;
6
+ exports.validateJson = validateJson;
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+ /**
10
+ * Error thrown when a manifest or generated artifact does not satisfy its schema.
11
+ */
12
+ class SchemaValidationError extends Error {
13
+ label;
14
+ errors;
15
+ /**
16
+ * @param {string} label
17
+ * @param {{code: string, path: string, message: string}[]} errors
18
+ */
19
+ constructor(label, errors) {
20
+ super(formatValidationErrorMessage(label, errors));
21
+ this.name = 'SchemaValidationError';
22
+ this.label = label;
23
+ this.errors = errors;
24
+ }
25
+ }
26
+ exports.SchemaValidationError = SchemaValidationError;
27
+ /**
28
+ * Reads and parses a JSON file.
29
+ *
30
+ * @param {string} filePath
31
+ * @returns {unknown}
32
+ */
33
+ function readJson(filePath) {
34
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
35
+ }
36
+ /**
37
+ * Loads a schema from the repo-local `schemas` directory.
38
+ *
39
+ * @param {string} relativePath
40
+ * @returns {Record<string, unknown>}
41
+ */
42
+ function loadSchema(relativePath) {
43
+ const sourcePath = path.join(__dirname, '..', 'schemas', relativePath);
44
+ const compiledPath = path.join(__dirname, '..', '..', 'schemas', relativePath);
45
+ const schemaPath = fs.existsSync(sourcePath) ? sourcePath : compiledPath;
46
+ return readJson(schemaPath);
47
+ }
48
+ const SCHEMAS = {
49
+ budgetVerdict: loadSchema('budget-verdict.schema.json'),
50
+ causalRun: loadSchema('causal-run.schema.json'),
51
+ comparison: loadSchema('comparison.schema.json'),
52
+ health: loadSchema('health.schema.json'),
53
+ liveProof: loadSchema('live-proof.schema.json'),
54
+ liveProofSet: loadSchema('live-proof-set.schema.json'),
55
+ manifest: loadSchema('manifest.schema.json'),
56
+ metrics: loadSchema('metrics.schema.json'),
57
+ projectValidation: loadSchema('project-validation.schema.json'),
58
+ scenario: loadSchema('scenario.schema.json'),
59
+ runnerCapabilities: loadSchema('runner-capabilities.schema.json'),
60
+ verdict: loadSchema('verdict.schema.json'),
61
+ };
62
+ exports.SCHEMAS = SCHEMAS;
63
+ /**
64
+ * Formats a validation path as a JSONPath-like string.
65
+ *
66
+ * @param {(string | number)[]} pathSegments
67
+ * @returns {string}
68
+ */
69
+ function formatPath(pathSegments) {
70
+ if (pathSegments.length === 0) {
71
+ return '$';
72
+ }
73
+ return pathSegments.reduce((result, segment) => {
74
+ if (typeof segment === 'number') {
75
+ return `${result}[${segment}]`;
76
+ }
77
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(segment)) {
78
+ return `${result}.${segment}`;
79
+ }
80
+ return `${result}[${JSON.stringify(segment)}]`;
81
+ }, '$');
82
+ }
83
+ /**
84
+ * Stringifies object values with stable key ordering for `uniqueItems` checks.
85
+ *
86
+ * @param {unknown} value
87
+ * @returns {string | undefined}
88
+ */
89
+ function stableStringify(value) {
90
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
91
+ return JSON.stringify(value);
92
+ }
93
+ return JSON.stringify(Object.keys(value)
94
+ .sort()
95
+ .reduce((result, key) => {
96
+ const source = value;
97
+ result[key] = source[key];
98
+ return result;
99
+ }, {}));
100
+ }
101
+ /**
102
+ * Formats enum values for validation error messages.
103
+ *
104
+ * @param {unknown[]} values
105
+ * @returns {string}
106
+ */
107
+ function describeAllowedValues(values) {
108
+ return values.map((value) => JSON.stringify(value)).join(', ');
109
+ }
110
+ /**
111
+ * Resolves local JSON Schema references such as `#/$defs/capability`.
112
+ *
113
+ * @param {Record<string, unknown>} rootSchema
114
+ * @param {string} ref
115
+ * @returns {Record<string, unknown>}
116
+ */
117
+ function resolveLocalRef(rootSchema, ref) {
118
+ if (!ref.startsWith('#/')) {
119
+ throw new Error(`Only local schema refs are supported: ${ref}`);
120
+ }
121
+ return ref
122
+ .slice(2)
123
+ .split('/')
124
+ .reduce((current, token) => {
125
+ const key = token.replace(/~1/g, '/').replace(/~0/g, '~');
126
+ if (!current || typeof current !== 'object' || !(key in current)) {
127
+ throw new Error(`Schema ref could not be resolved: ${ref}`);
128
+ }
129
+ return current[key];
130
+ }, rootSchema);
131
+ }
132
+ /**
133
+ * Returns true when a value satisfies a schema without recording validation errors.
134
+ *
135
+ * @param {unknown} value
136
+ * @param {Record<string, unknown>} schema
137
+ * @param {Record<string, unknown>} rootSchema
138
+ * @returns {boolean}
139
+ */
140
+ function matchesSchema(value, schema, rootSchema) {
141
+ return validateSchema(value, schema, rootSchema, [], []).length === 0;
142
+ }
143
+ /**
144
+ * Checks a JavaScript value against one JSON Schema primitive type.
145
+ *
146
+ * @param {unknown} value
147
+ * @param {string} type
148
+ * @returns {boolean}
149
+ */
150
+ function isType(value, type) {
151
+ if (type === 'null') {
152
+ return value === null;
153
+ }
154
+ if (type === 'array') {
155
+ return Array.isArray(value);
156
+ }
157
+ if (type === 'object') {
158
+ return !!value && typeof value === 'object' && !Array.isArray(value);
159
+ }
160
+ if (type === 'integer') {
161
+ return Number.isInteger(value);
162
+ }
163
+ if (type === 'number') {
164
+ return typeof value === 'number' && Number.isFinite(value);
165
+ }
166
+ return typeof value === type;
167
+ }
168
+ /**
169
+ * Validates the `type` keyword and records one error on mismatch.
170
+ *
171
+ * @param {{value: unknown, expectedType: string | string[], pathSegments: (string | number)[], errors: {code: string, path: string, message: string}[]}} options
172
+ * @returns {boolean}
173
+ */
174
+ function validateType({ value, expectedType, pathSegments, errors, }) {
175
+ const expectedTypes = Array.isArray(expectedType) ? expectedType : [expectedType];
176
+ if (!expectedTypes.some((type) => isType(value, type))) {
177
+ errors.push({
178
+ code: 'invalid_type',
179
+ path: formatPath(pathSegments),
180
+ message: `Expected ${expectedTypes.join(' or ')}.`,
181
+ });
182
+ return false;
183
+ }
184
+ return true;
185
+ }
186
+ /**
187
+ * Validates the JSON Schema subset used by this package's public contracts.
188
+ *
189
+ * @param {unknown} value
190
+ * @param {Record<string, unknown>} schema
191
+ * @param {Record<string, unknown>} rootSchema
192
+ * @param {(string | number)[]} [pathSegments]
193
+ * @param {{code: string, path: string, message: string}[]} [errors]
194
+ * @returns {{code: string, path: string, message: string}[]}
195
+ */
196
+ function validateSchema(value, schema, rootSchema, pathSegments = [], errors = []) {
197
+ if (!schema || typeof schema !== 'object') {
198
+ return errors;
199
+ }
200
+ if (schema.$ref) {
201
+ validateSchema(value, resolveLocalRef(rootSchema, schema.$ref), rootSchema, pathSegments, errors);
202
+ }
203
+ for (const childSchema of schema.allOf ?? []) {
204
+ validateSchema(value, childSchema, rootSchema, pathSegments, errors);
205
+ }
206
+ if ('const' in schema && !Object.is(schema.const, value)) {
207
+ errors.push({
208
+ code: 'invalid_const',
209
+ path: formatPath(pathSegments),
210
+ message: `Expected ${JSON.stringify(schema.const)}.`,
211
+ });
212
+ }
213
+ if (schema.if && matchesSchema(value, schema.if, rootSchema)) {
214
+ if (schema.then) {
215
+ validateSchema(value, schema.then, rootSchema, pathSegments, errors);
216
+ }
217
+ }
218
+ else if (schema.if && schema.else) {
219
+ validateSchema(value, schema.else, rootSchema, pathSegments, errors);
220
+ }
221
+ if (schema.not && matchesSchema(value, schema.not, rootSchema)) {
222
+ errors.push({
223
+ code: 'schema_not',
224
+ path: formatPath(pathSegments),
225
+ message: schema.not.description ?? 'Value must not match the disallowed schema.',
226
+ });
227
+ }
228
+ if (schema.type && !validateType({ value, expectedType: schema.type, pathSegments, errors })) {
229
+ return errors;
230
+ }
231
+ if (schema.enum && !schema.enum.some((allowed) => Object.is(allowed, value))) {
232
+ errors.push({
233
+ code: 'invalid_enum',
234
+ path: formatPath(pathSegments),
235
+ message: `Expected one of ${describeAllowedValues(schema.enum)}.`,
236
+ });
237
+ }
238
+ if (typeof schema.pattern === 'string' && typeof value === 'string') {
239
+ const regex = new RegExp(schema.pattern, 'u');
240
+ if (!regex.test(value)) {
241
+ errors.push({
242
+ code: 'invalid_pattern',
243
+ path: formatPath(pathSegments),
244
+ message: `Expected value to match ${schema.pattern}.`,
245
+ });
246
+ }
247
+ }
248
+ if (typeof schema.minLength === 'number' && typeof value === 'string' && value.length < schema.minLength) {
249
+ errors.push({
250
+ code: 'too_short',
251
+ path: formatPath(pathSegments),
252
+ message: `Expected at least ${schema.minLength} character(s).`,
253
+ });
254
+ }
255
+ if (typeof schema.minimum === 'number' && typeof value === 'number' && value < schema.minimum) {
256
+ errors.push({
257
+ code: 'below_minimum',
258
+ path: formatPath(pathSegments),
259
+ message: `Expected value to be >= ${schema.minimum}.`,
260
+ });
261
+ }
262
+ if (Array.isArray(value)) {
263
+ validateArray(value, schema, rootSchema, pathSegments, errors);
264
+ }
265
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
266
+ validateObject(value, schema, rootSchema, pathSegments, errors);
267
+ }
268
+ return errors;
269
+ }
270
+ /**
271
+ * Validates array-specific schema keywords.
272
+ *
273
+ * @param {unknown[]} value
274
+ * @param {Record<string, unknown>} schema
275
+ * @param {Record<string, unknown>} rootSchema
276
+ * @param {(string | number)[]} pathSegments
277
+ * @param {{code: string, path: string, message: string}[]} errors
278
+ * @returns {void}
279
+ */
280
+ function validateArray(value, schema, rootSchema, pathSegments, errors) {
281
+ if (typeof schema.minItems === 'number' && value.length < schema.minItems) {
282
+ errors.push({
283
+ code: 'too_few_items',
284
+ path: formatPath(pathSegments),
285
+ message: `Expected at least ${schema.minItems} item(s).`,
286
+ });
287
+ }
288
+ if (schema.uniqueItems === true) {
289
+ const seen = new Set();
290
+ for (const item of value) {
291
+ const key = stableStringify(item);
292
+ if (seen.has(key)) {
293
+ errors.push({
294
+ code: 'duplicate_item',
295
+ path: formatPath(pathSegments),
296
+ message: 'Expected array items to be unique.',
297
+ });
298
+ break;
299
+ }
300
+ seen.add(key);
301
+ }
302
+ }
303
+ if (schema.items) {
304
+ const itemSchema = schema.items;
305
+ value.forEach((item, index) => validateSchema(item, itemSchema, rootSchema, [...pathSegments, index], errors));
306
+ }
307
+ }
308
+ /**
309
+ * Validates object-specific schema keywords.
310
+ *
311
+ * @param {Record<string, unknown>} value
312
+ * @param {Record<string, unknown>} schema
313
+ * @param {Record<string, unknown>} rootSchema
314
+ * @param {(string | number)[]} pathSegments
315
+ * @param {{code: string, path: string, message: string}[]} errors
316
+ * @returns {void}
317
+ */
318
+ function validateObject(value, schema, rootSchema, pathSegments, errors) {
319
+ if (typeof schema.minProperties === 'number' && Object.keys(value).length < schema.minProperties) {
320
+ errors.push({
321
+ code: 'too_few_properties',
322
+ path: formatPath(pathSegments),
323
+ message: `Expected at least ${schema.minProperties} properties.`,
324
+ });
325
+ }
326
+ for (const requiredKey of schema.required ?? []) {
327
+ if (!(requiredKey in value)) {
328
+ errors.push({
329
+ code: 'missing_required_property',
330
+ path: formatPath([...pathSegments, requiredKey]),
331
+ message: `Missing required property \`${requiredKey}\`.`,
332
+ });
333
+ }
334
+ }
335
+ const definedProperties = schema.properties ?? {};
336
+ for (const [key, propertySchema] of Object.entries(definedProperties)) {
337
+ if (key in value) {
338
+ validateSchema(value[key], propertySchema, rootSchema, [...pathSegments, key], errors);
339
+ }
340
+ }
341
+ for (const key of Object.keys(value)) {
342
+ if (key in definedProperties) {
343
+ continue;
344
+ }
345
+ if (schema.additionalProperties === false) {
346
+ errors.push({
347
+ code: 'additional_property',
348
+ path: formatPath([...pathSegments, key]),
349
+ message: `Unexpected property \`${key}\`.`,
350
+ });
351
+ }
352
+ else if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
353
+ validateSchema(value[key], schema.additionalProperties, rootSchema, [...pathSegments, key], errors);
354
+ }
355
+ }
356
+ }
357
+ /**
358
+ * Validates a value against a schema and returns structured errors instead of throwing.
359
+ *
360
+ * @param {unknown} value
361
+ * @param {Record<string, unknown>} schema
362
+ * @param {string} [label]
363
+ * @returns {{valid: boolean, errors: {code: string, path: string, message: string}[], message: string}}
364
+ */
365
+ function validateJson(value, schema, label = 'JSON document') {
366
+ const errors = validateSchema(value, schema, schema);
367
+ if (errors.length > 0) {
368
+ return {
369
+ valid: false,
370
+ errors,
371
+ message: formatValidationErrorMessage(label, errors),
372
+ };
373
+ }
374
+ return {
375
+ valid: true,
376
+ errors: [],
377
+ message: '',
378
+ };
379
+ }
380
+ /**
381
+ * Validates a value against a schema, throwing `SchemaValidationError` on failure.
382
+ *
383
+ * @param {unknown} value
384
+ * @param {Record<string, unknown>} schema
385
+ * @param {string} label
386
+ * @returns {unknown}
387
+ */
388
+ function assertValidJson(value, schema, label) {
389
+ const result = validateJson(value, schema, label);
390
+ if (!result.valid) {
391
+ throw new SchemaValidationError(label, result.errors);
392
+ }
393
+ return value;
394
+ }
395
+ /**
396
+ * Formats schema errors as a CLI-readable message.
397
+ *
398
+ * @param {string} label
399
+ * @param {{path: string, message: string}[]} errors
400
+ * @returns {string}
401
+ */
402
+ function formatValidationErrorMessage(label, errors) {
403
+ return [
404
+ `${label} failed schema validation:`,
405
+ ...errors.map((error) => `- ${error.path}: ${error.message}`),
406
+ ].join('\n');
407
+ }
@@ -0,0 +1,11 @@
1
+ export * from './core/agent-summary';
2
+ export * from './core/artifact-contract';
3
+ export * from './core/artifact-layout';
4
+ export * from './core/artifact-writer';
5
+ export * from './core/comparison';
6
+ export * from './core/evidence-interpreter';
7
+ export * from './core/execution-plan';
8
+ export * from './core/planner';
9
+ export * from './core/ports';
10
+ export * from './core/run-index';
11
+ export * from './core/schema-validator';
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./core/agent-summary"), exports);
18
+ __exportStar(require("./core/artifact-contract"), exports);
19
+ __exportStar(require("./core/artifact-layout"), exports);
20
+ __exportStar(require("./core/artifact-writer"), exports);
21
+ __exportStar(require("./core/comparison"), exports);
22
+ __exportStar(require("./core/evidence-interpreter"), exports);
23
+ __exportStar(require("./core/execution-plan"), exports);
24
+ __exportStar(require("./core/planner"), exports);
25
+ __exportStar(require("./core/ports"), exports);
26
+ __exportStar(require("./core/run-index"), exports);
27
+ __exportStar(require("./core/schema-validator"), exports);
@@ -0,0 +1,126 @@
1
+ type AgentDevicePlatform = 'android' | 'apple' | 'ios' | 'linux' | 'macos';
2
+ type AgentDeviceCommandResult = {
3
+ action: string;
4
+ args: string[];
5
+ capturePath?: string;
6
+ command: string;
7
+ exitCode: number;
8
+ rawFileName: string;
9
+ stderr: string;
10
+ stdout: string;
11
+ };
12
+ type AgentDeviceCommandExecutor = (command: string, args: string[]) => Promise<{
13
+ args: string[];
14
+ command: string;
15
+ exitCode: number;
16
+ stderr: string;
17
+ stdout: string;
18
+ }>;
19
+ type AgentDeviceDriverOptions = {
20
+ agentDevicePath: string;
21
+ device?: string;
22
+ executor: AgentDeviceCommandExecutor;
23
+ extraArgs?: string[];
24
+ json?: boolean;
25
+ platform: AgentDevicePlatform;
26
+ serial?: string;
27
+ session?: string;
28
+ target?: 'desktop' | 'mobile' | 'tv';
29
+ udid?: string;
30
+ };
31
+ type AgentDeviceSelector = {
32
+ kind: string;
33
+ match?: string;
34
+ value: string;
35
+ };
36
+ type AgentDeviceAlertAction = 'accept' | 'dismiss' | 'get' | 'wait';
37
+ type AgentDeviceAlertOptions = {
38
+ action?: AgentDeviceAlertAction;
39
+ rawFileName?: string;
40
+ timeoutMs?: number;
41
+ };
42
+ type AgentDeviceAssertVisibleOptions = {
43
+ rawFileName?: string;
44
+ selector: AgentDeviceSelector;
45
+ };
46
+ type AgentDeviceInspectTreeOptions = {
47
+ interactive?: boolean;
48
+ rawFileName?: string;
49
+ };
50
+ type AgentDeviceOpenOptions = {
51
+ appOrUrl: string;
52
+ rawFileName?: string;
53
+ url?: string;
54
+ };
55
+ type AgentDeviceReadLogsOptions = {
56
+ rawFileName?: string;
57
+ };
58
+ type AgentDeviceScreenshotOptions = {
59
+ outputPath: string;
60
+ rawFileName?: string;
61
+ };
62
+ type AgentDeviceScrollOptions = {
63
+ amount?: string;
64
+ direction?: string;
65
+ durationMs?: number;
66
+ endX?: number;
67
+ endY?: number;
68
+ pixels?: number;
69
+ rawFileName?: string;
70
+ startX?: number;
71
+ startY?: number;
72
+ };
73
+ type AgentDeviceTapOptions = {
74
+ rawFileName?: string;
75
+ ref?: string;
76
+ selector?: AgentDeviceSelector;
77
+ x?: number;
78
+ y?: number;
79
+ };
80
+ type AgentDeviceDriver = {
81
+ alert: (options?: AgentDeviceAlertOptions) => Promise<AgentDeviceCommandResult>;
82
+ assertVisible: (options: AgentDeviceAssertVisibleOptions) => Promise<AgentDeviceCommandResult>;
83
+ close: (app: string) => Promise<AgentDeviceCommandResult>;
84
+ inspectTree: (options?: AgentDeviceInspectTreeOptions) => Promise<AgentDeviceCommandResult>;
85
+ open: (options: AgentDeviceOpenOptions) => Promise<AgentDeviceCommandResult>;
86
+ readLogs: (options?: AgentDeviceReadLogsOptions) => Promise<AgentDeviceCommandResult>;
87
+ screenshot: (options: AgentDeviceScreenshotOptions) => Promise<AgentDeviceCommandResult>;
88
+ scroll: (options?: AgentDeviceScrollOptions) => Promise<AgentDeviceCommandResult>;
89
+ tap: (options: AgentDeviceTapOptions) => Promise<AgentDeviceCommandResult>;
90
+ };
91
+ /**
92
+ * Builds global CLI flags shared by all agent-device driver actions.
93
+ *
94
+ * @param {AgentDeviceDriverOptions} options
95
+ * @returns {string[]}
96
+ */
97
+ declare function buildAgentDeviceGlobalArgs(options: AgentDeviceDriverOptions): string[];
98
+ /**
99
+ * Formats one portable selector as an agent-device selector expression.
100
+ *
101
+ * @param {AgentDeviceSelector} selector
102
+ * @returns {string}
103
+ */
104
+ declare function formatAgentDeviceSelector(selector: AgentDeviceSelector): string;
105
+ /**
106
+ * Combines stdout and stderr into the raw evidence text written by callers.
107
+ *
108
+ * @param {{stdout: string, stderr: string}} result
109
+ * @returns {string}
110
+ */
111
+ declare function formatAgentDeviceRawOutput(result: {
112
+ stdout: string;
113
+ stderr: string;
114
+ }): string;
115
+ /**
116
+ * Creates an agent-device-backed driver for portable mobile actions.
117
+ *
118
+ * The adapter shells out through an injected executor so consumers can choose
119
+ * local, remote, or test doubles without making agent-device a package dependency.
120
+ *
121
+ * @param {AgentDeviceDriverOptions} options
122
+ * @returns {AgentDeviceDriver}
123
+ */
124
+ declare function createAgentDeviceDriver(options: AgentDeviceDriverOptions): AgentDeviceDriver;
125
+ export { buildAgentDeviceGlobalArgs, createAgentDeviceDriver, formatAgentDeviceRawOutput, formatAgentDeviceSelector, };
126
+ export type { AgentDeviceAlertAction, AgentDeviceAlertOptions, AgentDeviceAssertVisibleOptions, AgentDeviceCommandExecutor, AgentDeviceCommandResult, AgentDeviceDriver, AgentDeviceDriverOptions, AgentDeviceInspectTreeOptions, AgentDeviceOpenOptions, AgentDevicePlatform, AgentDeviceReadLogsOptions, AgentDeviceScreenshotOptions, AgentDeviceScrollOptions, AgentDeviceSelector, AgentDeviceTapOptions, };