@farmslot/recipe-harness 0.2.2 → 0.3.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 ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@farmslot/recipe-harness` are tracked here.
4
+
5
+ ## Unreleased
6
+
7
+ _No entries yet. Add Added/Changed/Fixed/Removed bullets here with each PR; date and version only at publish._
8
+
9
+ ## 0.3.1 - 2026-06-26
10
+
11
+ - Add `runtime/orchestrate-up` — generic install → relaunch decision loop (`orchestrateRuntimeUp`) for product runners to wrap with shell/platform actions.
12
+
13
+ ## 0.3.0 - 2026-06-26
14
+
15
+ - Add shared runtime-readiness helpers under `@farmslot/recipe-harness/runtime/*`:
16
+ - `deps-readiness` — install fingerprint, baseline recording, product-marker partial checks, decision state persistence
17
+ - `log-analysis` — Metro/RN bundle log boundaries, unresolved-module scoping, persistent bundle-error detection
18
+ - `metro-probe` — packager `/status` reachability probe
19
+ - `decision-types` — portable `RuntimeDecisionReport` / `RuntimeDecisionAction` shapes
20
+ - Product runners (e.g. MetaMask) should import these modules instead of copying readiness logic locally.
21
+
22
+ ## 0.2.2 - 2026-06-10
23
+
24
+ - Publish with npm-resolvable `@farmslot/protocol` dependency metadata instead of workspace-only protocol references.
25
+
26
+ ## 0.2.1 - 2026-06-10
27
+
28
+ - Drive CDP text inputs with trusted keyboard insertion instead of direct DOM value assignment so React-controlled inputs receive real input/change handling.
29
+ - Drive CDP clicks with real mouse events and expose `ui.key_press` through the standard UI adapter.
30
+
31
+ ## 0.2.0 - 2026-06-02
32
+
33
+ - Define the v0 public harness package surface with explicit core, adapter, node, CLI, and runtime entry points.
34
+ - Publish recipe runner runtime helpers under explicit `runtime/*` subpaths for browser extension, CDP, and React Native bridge clients.
35
+ - Keep CLI and writer implementation details behind explicit subpath exports instead of wildcard package exports.
36
+
37
+ ## 0.1.0 - 2026-05-31
38
+
39
+ - Initial public active-development release.
package/README.md CHANGED
@@ -39,7 +39,7 @@ npm install @farmslot/recipe-harness @farmslot/protocol
39
39
  | `src/index.ts` | Public package export surface. |
40
40
  | `src/core/` | Manifest-aware recipe graph execution, flow calls, predicates, HUD node shaping, and harness-local types. |
41
41
  | `src/adapters/` | Standard core and UI adapter factories. |
42
- | `src/runtime/` | Runtime transports for CDP, browser extensions, and React Native bridge connections. |
42
+ | `src/runtime/` | Runtime transports (CDP, browser extensions, RN bridge) and shared readiness helpers (deps, log analysis, Metro probe). |
43
43
  | `src/node/` | Node-only artifact, trace, and summary writers. |
44
44
  | `src/cli/` | CLI entrypoint, commands, and shared CLI validation helpers. |
45
45
  | `test/` | Harness package and export-boundary tests mirroring public behavior. |
@@ -60,6 +60,11 @@ listed here.
60
60
  | `@farmslot/recipe-harness/runtime/cdp` | CDP browser transport helpers. |
61
61
  | `@farmslot/recipe-harness/runtime/react-native-bridge` | React Native bridge transport helpers. |
62
62
  | `@farmslot/recipe-harness/runtime/browser-extension` | Browser-extension target helpers. |
63
+ | `@farmslot/recipe-harness/runtime/deps-readiness` | Install fingerprint, baseline, product-marker partial checks. |
64
+ | `@farmslot/recipe-harness/runtime/log-analysis` | Bundle-log boundaries, unresolved-module scoping, persistent bundle-error state. |
65
+ | `@farmslot/recipe-harness/runtime/metro-probe` | Metro packager `/status` reachability probe. |
66
+ | `@farmslot/recipe-harness/runtime/decision-types` | Portable `RuntimeDecisionReport` / action shapes for product adapters. |
67
+ | `@farmslot/recipe-harness/runtime/orchestrate-up` | Generic install → relaunch orchestration loop for `recipe up` hosts. |
63
68
  | `@farmslot/recipe-harness/cli` | Programmatic CLI entrypoint. |
64
69
  | `@farmslot/recipe-harness/cli/support` | Shared CLI input validation helpers. |
65
70
  | `@farmslot/recipe-harness/writers` | Node-only JSON artifact writers. |
@@ -68,6 +73,7 @@ listed here.
68
73
 
69
74
  The harness owns generic execution mechanics:
70
75
 
76
+ - runtime-readiness primitives (`runtime/deps-readiness`, `runtime/log-analysis`, `runtime/metro-probe`) — product runners supply adapter-specific markers, log patterns, and shell launch;
71
77
  - manifest-aware runner construction;
72
78
  - graph execution, `call` flow composition, setup/start-state/proof/teardown ordering;
73
79
  - standard core adapters such as `command`, `wait`, `assert_json`, `watch_logs`, and `end`;
@@ -79,6 +85,12 @@ Project-specific behavior stays outside this package. For example,
79
85
  `example.trade.place_order`, `checkout.ensure_cart`, or `backend.seed_user`
80
86
  belong in the project runner that imports this package.
81
87
 
88
+ ## Changelog
89
+
90
+ Update [CHANGELOG.md](./CHANGELOG.md) under `## Unreleased` in the same PR as code changes
91
+ (Added / Changed / Fixed / Removed). Add a dated version section only when publishing
92
+ (`yarn npm publish` — `prepack` checks changelog readiness).
93
+
82
94
  ## Minimal runner
83
95
 
84
96
  ```ts
@@ -0,0 +1,23 @@
1
+ import type { DepsCheck } from './deps-readiness.js';
2
+ /** Stable id a host branches on when executing `actions[]`. */
3
+ export interface RuntimeDecisionAction {
4
+ id: string;
5
+ argv?: string[];
6
+ cwd?: string;
7
+ paths?: string[];
8
+ }
9
+ export type RuntimeReadinessDecision = 'install' | 'build' | 'launch' | 'relaunch' | 'ready' | 'blocked' | 'unknown';
10
+ export interface RuntimeDecisionReport<TChecks extends Record<string, unknown> = Record<string, unknown>> {
11
+ schemaVersion: 1;
12
+ adapter: string;
13
+ target: string;
14
+ decision: RuntimeReadinessDecision;
15
+ reasonCode: string;
16
+ reasons: string[];
17
+ checks: TChecks;
18
+ actions: RuntimeDecisionAction[];
19
+ /** Extension-only: build must clear webpack cache first. */
20
+ clean?: boolean;
21
+ }
22
+ export type { DepsCheck };
23
+ //# sourceMappingURL=decision-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-types.d.ts","sourceRoot":"","sources":["../../src/runtime/decision-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,+DAA+D;AAC/D,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,MAAM,wBAAwB,GAChC,SAAS,GACT,OAAO,GACP,QAAQ,GACR,UAAU,GACV,OAAO,GACP,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,qBAAqB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtG,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,wBAAwB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=decision-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-types.js","sourceRoot":"","sources":["../../src/runtime/decision-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /** Lock/manifest inputs hashed for the deps baseline. */
2
+ export declare const DEPS_INPUTS: string[];
3
+ /** Yarn install-state markers. */
4
+ export declare const INSTALL_MARKERS: string[];
5
+ export interface DepsCheck {
6
+ installed: boolean;
7
+ status: 'current' | 'stale' | 'missing' | 'partial';
8
+ hasBaseline: boolean;
9
+ missingProducts?: string[];
10
+ }
11
+ export declare function depsFingerprint(target: string, extraInputs?: string[]): string;
12
+ /** Record the current deps fingerprint as the install baseline (OS temp dir). */
13
+ export declare function recordDepsBaseline(target: string): void;
14
+ export declare function readDecisionState(target: string, name: string): Record<string, unknown> | null;
15
+ export declare function writeDecisionState(target: string, name: string, value: Record<string, unknown>): void;
16
+ export declare function clearDecisionState(target: string, name: string): void;
17
+ export declare function depsCheck(target: string, options?: {
18
+ productMarkers?: string[];
19
+ }): DepsCheck;
20
+ //# sourceMappingURL=deps-readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps-readiness.d.ts","sourceRoot":"","sources":["../../src/runtime/deps-readiness.ts"],"names":[],"mappings":"AAKA,yDAAyD;AACzD,eAAO,MAAM,WAAW,UAAiE,CAAC;AAE1F,kCAAkC;AAClC,eAAO,MAAM,eAAe,UAA6D,CAAC;AAE1F,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACpD,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAgCD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,EAAO,GAAG,MAAM,CAWlF;AAMD,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAE9F;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAErG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAMrE;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAC1C,SAAS,CAwBX"}
@@ -0,0 +1,93 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ /** Lock/manifest inputs hashed for the deps baseline. */
6
+ export const DEPS_INPUTS = ['package.json', 'yarn.lock', '.yarnrc.yml', '.tool-versions'];
7
+ /** Yarn install-state markers. */
8
+ export const INSTALL_MARKERS = ['node_modules/.yarn-state.yml', '.yarn/install-state.gz'];
9
+ const STATE_NAMESPACE = 'farmslot-recipe-runtime-decision';
10
+ function stateDir(target) {
11
+ const key = crypto.createHash('sha1').update(path.resolve(target)).digest('hex').slice(0, 16);
12
+ return path.join(os.tmpdir(), STATE_NAMESPACE, key);
13
+ }
14
+ function readBaseline(target, name) {
15
+ try {
16
+ return JSON.parse(fs.readFileSync(path.join(stateDir(target), name), 'utf8'));
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ function writeBaseline(target, name, value) {
23
+ const dir = stateDir(target);
24
+ fs.mkdirSync(dir, { recursive: true });
25
+ fs.writeFileSync(path.join(dir, name), `${JSON.stringify(value, null, 2)}\n`);
26
+ }
27
+ function newestMtime(target, rels) {
28
+ let newest = 0;
29
+ for (const rel of rels) {
30
+ const abs = path.join(target, rel);
31
+ if (fs.existsSync(abs))
32
+ newest = Math.max(newest, fs.statSync(abs).mtimeMs);
33
+ }
34
+ return newest;
35
+ }
36
+ export function depsFingerprint(target, extraInputs = []) {
37
+ const hash = crypto.createHash('sha256');
38
+ for (const rel of [...DEPS_INPUTS, ...extraInputs]) {
39
+ const abs = path.join(target, rel);
40
+ if (!fs.existsSync(abs))
41
+ continue;
42
+ hash.update(rel);
43
+ hash.update('\0');
44
+ hash.update(fs.readFileSync(abs));
45
+ hash.update('\0');
46
+ }
47
+ return hash.digest('hex');
48
+ }
49
+ function missingProductMarkers(target, markers) {
50
+ return markers.filter((rel) => !fs.existsSync(path.join(target, rel)));
51
+ }
52
+ /** Record the current deps fingerprint as the install baseline (OS temp dir). */
53
+ export function recordDepsBaseline(target) {
54
+ writeBaseline(target, 'deps-state.json', { fingerprint: depsFingerprint(target) });
55
+ }
56
+ export function readDecisionState(target, name) {
57
+ return readBaseline(target, name);
58
+ }
59
+ export function writeDecisionState(target, name, value) {
60
+ writeBaseline(target, name, value);
61
+ }
62
+ export function clearDecisionState(target, name) {
63
+ try {
64
+ fs.unlinkSync(path.join(stateDir(target), name));
65
+ }
66
+ catch {
67
+ // no prior state
68
+ }
69
+ }
70
+ export function depsCheck(target, options = {}) {
71
+ const productMarkers = options.productMarkers ?? [];
72
+ const inputs = DEPS_INPUTS.filter((rel) => fs.existsSync(path.join(target, rel)));
73
+ const installed = inputs.length > 0 && INSTALL_MARKERS.some((rel) => fs.existsSync(path.join(target, rel)));
74
+ if (!installed)
75
+ return { installed: false, status: 'missing', hasBaseline: false };
76
+ const missingProducts = missingProductMarkers(target, productMarkers);
77
+ if (missingProducts.length > 0) {
78
+ return {
79
+ installed: true,
80
+ status: 'partial',
81
+ hasBaseline: false,
82
+ missingProducts,
83
+ };
84
+ }
85
+ const baseline = readBaseline(target, 'deps-state.json');
86
+ if (!baseline) {
87
+ const drift = newestMtime(target, inputs) > newestMtime(target, INSTALL_MARKERS);
88
+ return { installed: true, status: drift ? 'stale' : 'current', hasBaseline: false };
89
+ }
90
+ const status = baseline.fingerprint === depsFingerprint(target) ? 'current' : 'stale';
91
+ return { installed: true, status, hasBaseline: true };
92
+ }
93
+ //# sourceMappingURL=deps-readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps-readiness.js","sourceRoot":"","sources":["../../src/runtime/deps-readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ export declare function packageRootsForModule(target: string, moduleName: string): string[];
2
+ /** True when the resolved package root contains package.json (ignores empty dirs). */
3
+ export declare function moduleExistsInNodeModules(target: string, moduleName: string): boolean;
4
+ export declare function unresolvedModulesFromLogSlice(lines: string[], startIndex?: number): string[];
5
+ export declare function bundleErrorExcerptHash(excerpt: string): string;
6
+ export interface LogBoundaryScan {
7
+ lastErr: number;
8
+ lastOk: number;
9
+ }
10
+ export declare function scanLogBoundaries(lines: string[], options: {
11
+ errorPattern: RegExp;
12
+ okPattern: RegExp;
13
+ }): LogBoundaryScan;
14
+ /**
15
+ * Return the last capture group from `errorPattern` when the error is not
16
+ * superseded by a later `okPattern` line (e.g. stale native-module errors).
17
+ */
18
+ export declare function supersededErrorCapture(logText: string, options: {
19
+ errorPattern: RegExp;
20
+ okPattern: RegExp;
21
+ }): string | null;
22
+ export interface BundleLogAnalysis {
23
+ status: 'ok' | 'errors' | 'bundling' | 'no-log';
24
+ reason?: 'bundle-error' | 'unresolved-module' | 'stale-bundle-error';
25
+ excerpt?: string;
26
+ unresolvedModules?: string[];
27
+ }
28
+ export interface AnalyzeBundleLogOptions {
29
+ target: string;
30
+ logText: string;
31
+ errorPattern: RegExp;
32
+ okPattern: RegExp;
33
+ bundlingPattern?: RegExp;
34
+ }
35
+ export declare function analyzeBundleLog(options: AnalyzeBundleLogOptions): BundleLogAnalysis;
36
+ export interface PersistentBundleErrorDecision {
37
+ blocked: boolean;
38
+ excerptHash: string;
39
+ }
40
+ /** Block when the same bundle-error excerpt was already recorded for this target. */
41
+ export declare function evaluatePersistentBundleError(target: string, excerpt: string, stateFile?: string): PersistentBundleErrorDecision;
42
+ //# sourceMappingURL=log-analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-analysis.d.ts","sourceRoot":"","sources":["../../src/runtime/log-analysis.ts"],"names":[],"mappings":"AAMA,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAOlF;AAED,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAMrF;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,SAAI,GAAG,MAAM,EAAE,CAOvF;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnD,eAAe,CAQjB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnD,MAAM,GAAG,IAAI,CASf;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;IAChD,MAAM,CAAC,EAAE,cAAc,GAAG,mBAAmB,GAAG,oBAAoB,CAAC;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CA+BpF;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qFAAqF;AACrF,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,SAA4B,GACpC,6BAA6B,CAQ/B"}
@@ -0,0 +1,104 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { readDecisionState, writeDecisionState } from './deps-readiness.js';
5
+ export function packageRootsForModule(target, moduleName) {
6
+ if (moduleName.startsWith('@')) {
7
+ const parts = moduleName.split('/');
8
+ if (parts.length >= 2)
9
+ return [path.join(target, 'node_modules', parts[0], parts[1])];
10
+ return [path.join(target, 'node_modules', parts[0])];
11
+ }
12
+ return [path.join(target, 'node_modules', moduleName.split('/')[0])];
13
+ }
14
+ /** True when the resolved package root contains package.json (ignores empty dirs). */
15
+ export function moduleExistsInNodeModules(target, moduleName) {
16
+ for (const pkgRoot of packageRootsForModule(target, moduleName)) {
17
+ if (!fs.existsSync(pkgRoot))
18
+ continue;
19
+ if (fs.existsSync(path.join(pkgRoot, 'package.json')))
20
+ return true;
21
+ }
22
+ return false;
23
+ }
24
+ export function unresolvedModulesFromLogSlice(lines, startIndex = 0) {
25
+ const found = new Set();
26
+ for (let i = Math.max(0, startIndex); i < lines.length; i += 1) {
27
+ const match = /Unable to resolve "([^"]+)"/u.exec(lines[i]);
28
+ if (match)
29
+ found.add(match[1]);
30
+ }
31
+ return [...found];
32
+ }
33
+ export function bundleErrorExcerptHash(excerpt) {
34
+ return crypto.createHash('sha256').update(excerpt).digest('hex').slice(0, 16);
35
+ }
36
+ export function scanLogBoundaries(lines, options) {
37
+ let lastErr = -1;
38
+ let lastOk = -1;
39
+ for (let i = 0; i < lines.length; i += 1) {
40
+ if (options.errorPattern.test(lines[i]))
41
+ lastErr = i;
42
+ if (options.okPattern.test(lines[i]))
43
+ lastOk = i;
44
+ }
45
+ return { lastErr, lastOk };
46
+ }
47
+ /**
48
+ * Return the last capture group from `errorPattern` when the error is not
49
+ * superseded by a later `okPattern` line (e.g. stale native-module errors).
50
+ */
51
+ export function supersededErrorCapture(logText, options) {
52
+ const lines = logText.split('\n');
53
+ const { lastErr, lastOk } = scanLogBoundaries(lines, options);
54
+ if (lastOk >= 0 && lastOk > lastErr)
55
+ return null;
56
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
57
+ const match = options.errorPattern.exec(lines[i]);
58
+ if (match?.[1])
59
+ return match[1];
60
+ }
61
+ return null;
62
+ }
63
+ export function analyzeBundleLog(options) {
64
+ const lines = options.logText.split('\n');
65
+ const { lastErr, lastOk } = scanLogBoundaries(lines, {
66
+ errorPattern: options.errorPattern,
67
+ okPattern: options.okPattern,
68
+ });
69
+ const sliceStart = lastOk >= 0 ? lastOk + 1 : 0;
70
+ const unresolved = unresolvedModulesFromLogSlice(lines, sliceStart).filter((name) => !moduleExistsInNodeModules(options.target, name));
71
+ if (unresolved.length > 0 && lastErr > lastOk) {
72
+ return {
73
+ status: 'errors',
74
+ reason: 'unresolved-module',
75
+ excerpt: `Missing node_modules entries: ${unresolved.slice(0, 3).join(', ')}`,
76
+ unresolvedModules: unresolved,
77
+ };
78
+ }
79
+ if (lastErr > lastOk) {
80
+ const excerpt = lines.slice(lastErr, lastErr + 3).join(' | ').slice(0, 400);
81
+ const cited = unresolvedModulesFromLogSlice(lines, sliceStart);
82
+ const stillMissing = cited.filter((name) => !moduleExistsInNodeModules(options.target, name));
83
+ if (cited.length > 0 && stillMissing.length === 0) {
84
+ return { status: 'errors', reason: 'stale-bundle-error', excerpt, unresolvedModules: cited };
85
+ }
86
+ return { status: 'errors', reason: 'bundle-error', excerpt };
87
+ }
88
+ if (lastOk >= 0)
89
+ return { status: 'ok' };
90
+ const bundlingPattern = options.bundlingPattern ?? /Bundling|index\.(js|tsx?).*%/u;
91
+ const bundling = lines.some((line) => bundlingPattern.test(line));
92
+ return bundling ? { status: 'bundling' } : { status: 'no-log' };
93
+ }
94
+ /** Block when the same bundle-error excerpt was already recorded for this target. */
95
+ export function evaluatePersistentBundleError(target, excerpt, stateFile = 'bundle-error-state.json') {
96
+ const excerptHash = bundleErrorExcerptHash(excerpt);
97
+ const prev = readDecisionState(target, stateFile);
98
+ if (prev?.excerptHash === excerptHash) {
99
+ return { blocked: true, excerptHash };
100
+ }
101
+ writeDecisionState(target, stateFile, { excerptHash, recordedAt: Date.now() });
102
+ return { blocked: false, excerptHash };
103
+ }
104
+ //# sourceMappingURL=log-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-analysis.js","sourceRoot":"","sources":["../../src/runtime/log-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,MAAM,UAAU,qBAAqB,CAAC,MAAc,EAAE,UAAkB;IACtE,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,UAAkB;IAC1E,KAAK,MAAM,OAAO,IAAI,qBAAqB,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACrE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAe,EAAE,UAAU,GAAG,CAAC;IAC3E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAC/B,KAAe,EACf,OAAoD;IAEpD,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,MAAM,GAAG,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAe,EACf,OAAoD;IAEpD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9D,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,OAAO;QAAE,OAAO,IAAI,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAiBD,MAAM,UAAU,gBAAgB,CAAC,OAAgC;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC,KAAK,EAAE;QACnD,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,6BAA6B,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,MAAM,CACxE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,yBAAyB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAC3D,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC;QAC9C,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,mBAAmB;YAC3B,OAAO,EAAE,iCAAiC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC7E,iBAAiB,EAAE,UAAU;SAC9B,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,6BAA6B,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,yBAAyB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9F,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;QAC/F,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACzC,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,+BAA+B,CAAC;IACnF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAClE,CAAC;AAOD,qFAAqF;AACrF,MAAM,UAAU,6BAA6B,CAC3C,MAAc,EACd,OAAe,EACf,SAAS,GAAG,yBAAyB;IAErC,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,IAAI,EAAE,WAAW,KAAK,WAAW,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACxC,CAAC;IACD,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface MetroReachabilityCheck {
2
+ status: 'up' | 'down' | 'skipped';
3
+ }
4
+ export declare function probeMetroPackager(port: number, timeoutMs?: number): Promise<MetroReachabilityCheck>;
5
+ //# sourceMappingURL=metro-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-probe.d.ts","sourceRoot":"","sources":["../../src/runtime/metro-probe.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmBlG"}
@@ -0,0 +1,22 @@
1
+ import http from 'node:http';
2
+ export function probeMetroPackager(port, timeoutMs = 1500) {
3
+ return new Promise((resolve) => {
4
+ const req = http.get(`http://localhost:${port}/status`, { timeout: timeoutMs }, (res) => {
5
+ let body = '';
6
+ res.on('data', (chunk) => {
7
+ body += chunk;
8
+ });
9
+ res.on('end', () => {
10
+ const up = res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300
11
+ && /packager-status:running/u.test(body);
12
+ resolve({ status: up ? 'up' : 'down' });
13
+ });
14
+ });
15
+ req.on('timeout', () => {
16
+ req.destroy();
17
+ resolve({ status: 'down' });
18
+ });
19
+ req.on('error', () => resolve({ status: 'down' }));
20
+ });
21
+ }
22
+ //# sourceMappingURL=metro-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metro-probe.js","sourceRoot":"","sources":["../../src/runtime/metro-probe.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,SAAS,GAAG,IAAI;IAC/D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAoB,IAAI,SAAS,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;YACtF,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBACvB,IAAI,IAAI,KAAK,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,GAAG,GAAG;uBACnF,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3C,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACrB,GAAG,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { RuntimeDecisionReport, RuntimeReadinessDecision } from './decision-types.js';
2
+ export interface OrchestrateRuntimeUpOptions<T extends RuntimeDecisionReport = RuntimeDecisionReport> {
3
+ decide: () => Promise<T>;
4
+ onInstall: (report: T) => Promise<void>;
5
+ onLaunch: (report: T) => Promise<void>;
6
+ onReady: (report: T) => Promise<void>;
7
+ onBlocked?: (report: T) => Promise<void>;
8
+ /** Shared flag — set true after first install attempt to prevent loops. */
9
+ installAttempted?: {
10
+ value: boolean;
11
+ };
12
+ }
13
+ export interface OrchestrateRuntimeUpResult<T extends RuntimeDecisionReport = RuntimeDecisionReport> {
14
+ report: T;
15
+ exitDecision: RuntimeReadinessDecision;
16
+ }
17
+ /**
18
+ * Generic install → relaunch decision loop for product runners.
19
+ * Hosts supply shell/platform actions via onInstall/onLaunch/onReady callbacks.
20
+ */
21
+ export declare function orchestrateRuntimeUp<T extends RuntimeDecisionReport>(options: OrchestrateRuntimeUpOptions<T>): Promise<OrchestrateRuntimeUpResult<T>>;
22
+ //# sourceMappingURL=orchestrate-up.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrate-up.d.ts","sourceRoot":"","sources":["../../src/runtime/orchestrate-up.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE3F,MAAM,WAAW,2BAA2B,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IAClG,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,WAAW,0BAA0B,CAAC,CAAC,SAAS,qBAAqB,GAAG,qBAAqB;IACjG,MAAM,EAAE,CAAC,CAAC;IACV,YAAY,EAAE,wBAAwB,CAAC;CACxC;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,SAAS,qBAAqB,EACxE,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CA4BxC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Generic install → relaunch decision loop for product runners.
3
+ * Hosts supply shell/platform actions via onInstall/onLaunch/onReady callbacks.
4
+ */
5
+ export async function orchestrateRuntimeUp(options) {
6
+ const installFlag = options.installAttempted ?? { value: false };
7
+ const report = await options.decide();
8
+ switch (report.decision) {
9
+ case 'install': {
10
+ if (installFlag.value) {
11
+ throw new Error(`install did not resolve runtime (${report.reasonCode})`);
12
+ }
13
+ installFlag.value = true;
14
+ await options.onInstall(report);
15
+ return orchestrateRuntimeUp({ ...options, installAttempted: installFlag });
16
+ }
17
+ case 'launch':
18
+ case 'relaunch':
19
+ case 'build':
20
+ await options.onLaunch(report);
21
+ return { report, exitDecision: report.decision };
22
+ case 'ready':
23
+ await options.onReady(report);
24
+ return { report, exitDecision: 'ready' };
25
+ case 'blocked':
26
+ if (options.onBlocked)
27
+ await options.onBlocked(report);
28
+ return { report, exitDecision: 'blocked' };
29
+ default:
30
+ if (options.onBlocked)
31
+ await options.onBlocked(report);
32
+ return { report, exitDecision: report.decision };
33
+ }
34
+ }
35
+ //# sourceMappingURL=orchestrate-up.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrate-up.js","sourceRoot":"","sources":["../../src/runtime/orchestrate-up.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAuC;IAEvC,MAAM,WAAW,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC;IAEtC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;YAC5E,CAAC;YACD,WAAW,CAAC,KAAK,GAAG,IAAI,CAAC;YACzB,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,OAAO,oBAAoB,CAAC,EAAE,GAAG,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO;YACV,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnD,KAAK,OAAO;YACV,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9B,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;QAC3C,KAAK,SAAS;YACZ,IAAI,OAAO,CAAC,SAAS;gBAAE,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;QAC7C;YACE,IAAI,OAAO,CAAC,SAAS;gBAAE,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IACrD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farmslot/recipe-harness",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -62,6 +62,31 @@
62
62
  "types": "./dist/runtime/react-native-bridge.d.ts",
63
63
  "import": "./dist/runtime/react-native-bridge.js",
64
64
  "default": "./dist/runtime/react-native-bridge.js"
65
+ },
66
+ "./runtime/deps-readiness": {
67
+ "types": "./dist/runtime/deps-readiness.d.ts",
68
+ "import": "./dist/runtime/deps-readiness.js",
69
+ "default": "./dist/runtime/deps-readiness.js"
70
+ },
71
+ "./runtime/log-analysis": {
72
+ "types": "./dist/runtime/log-analysis.d.ts",
73
+ "import": "./dist/runtime/log-analysis.js",
74
+ "default": "./dist/runtime/log-analysis.js"
75
+ },
76
+ "./runtime/metro-probe": {
77
+ "types": "./dist/runtime/metro-probe.d.ts",
78
+ "import": "./dist/runtime/metro-probe.js",
79
+ "default": "./dist/runtime/metro-probe.js"
80
+ },
81
+ "./runtime/decision-types": {
82
+ "types": "./dist/runtime/decision-types.d.ts",
83
+ "import": "./dist/runtime/decision-types.js",
84
+ "default": "./dist/runtime/decision-types.js"
85
+ },
86
+ "./runtime/orchestrate-up": {
87
+ "types": "./dist/runtime/orchestrate-up.d.ts",
88
+ "import": "./dist/runtime/orchestrate-up.js",
89
+ "default": "./dist/runtime/orchestrate-up.js"
65
90
  }
66
91
  },
67
92
  "scripts": {
@@ -118,4 +143,4 @@
118
143
  "publishConfig": {
119
144
  "access": "public"
120
145
  }
121
- }
146
+ }