peachsim 0.1.527
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 +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// minimal client for `codex app-server` — a long-lived child process that
|
|
2
|
+
// speaks line-delimited JSON-RPC 2.0 over stdio.
|
|
3
|
+
//
|
|
4
|
+
// scope: just the subset sootsim needs for the attached-projects agent
|
|
5
|
+
// wrapper. each connection owns exactly one spawned app-server child; caller
|
|
6
|
+
// is responsible for lifecycle. bidirectional: client can issue requests +
|
|
7
|
+
// receive server-initiated notifications. we treat every method we don't
|
|
8
|
+
// recognize as an observable event that we pass straight to the handler map.
|
|
9
|
+
|
|
10
|
+
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'
|
|
11
|
+
import readline from 'node:readline'
|
|
12
|
+
|
|
13
|
+
export interface CodexClientOptions {
|
|
14
|
+
/** resolved path to the codex binary (via `which codex` or user override). */
|
|
15
|
+
bin: string
|
|
16
|
+
/** working directory for the spawned process. defaults to process.cwd(). */
|
|
17
|
+
cwd?: string
|
|
18
|
+
/** extra environment overrides forwarded to the child. */
|
|
19
|
+
env?: Record<string, string | undefined>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CodexNotificationHandler = (params: unknown) => void
|
|
23
|
+
|
|
24
|
+
export interface CodexClient {
|
|
25
|
+
/** promise that resolves when the child exits. use to await shutdown. */
|
|
26
|
+
readonly exited: Promise<{ code: number | null; signal: NodeJS.Signals | null }>
|
|
27
|
+
/** register a handler for a server-sent notification method. returns
|
|
28
|
+
* a dispose fn. multiple handlers per method are allowed. */
|
|
29
|
+
on(method: string, handler: CodexNotificationHandler): () => void
|
|
30
|
+
/** send a JSON-RPC request and await its response. rejects on error
|
|
31
|
+
* response or child death. */
|
|
32
|
+
request<TResult = unknown>(method: string, params?: unknown): Promise<TResult>
|
|
33
|
+
/** send a JSON-RPC notification (no id, no response). */
|
|
34
|
+
notify(method: string, params?: unknown): void
|
|
35
|
+
/** close stdin (graceful shutdown), then SIGTERM after timeout. */
|
|
36
|
+
shutdown(timeoutMs?: number): Promise<void>
|
|
37
|
+
/** force-kill immediately. */
|
|
38
|
+
kill(signal?: NodeJS.Signals): void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface JsonRpcResponse {
|
|
42
|
+
jsonrpc?: '2.0'
|
|
43
|
+
id?: number | string | null
|
|
44
|
+
result?: unknown
|
|
45
|
+
error?: { code: number; message: string; data?: unknown }
|
|
46
|
+
method?: string
|
|
47
|
+
params?: unknown
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class CodexRpcError extends Error {
|
|
51
|
+
code: number
|
|
52
|
+
data: unknown
|
|
53
|
+
constructor(message: string, code: number, data?: unknown) {
|
|
54
|
+
super(message)
|
|
55
|
+
this.name = 'CodexRpcError'
|
|
56
|
+
this.code = code
|
|
57
|
+
this.data = data
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function spawnCodexClient(options: CodexClientOptions): CodexClient {
|
|
62
|
+
const child: ChildProcessWithoutNullStreams = spawn(options.bin, ['app-server'], {
|
|
63
|
+
cwd: options.cwd,
|
|
64
|
+
env: { ...process.env, ...options.env },
|
|
65
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const pending = new Map<
|
|
69
|
+
number,
|
|
70
|
+
{
|
|
71
|
+
resolve: (value: unknown) => void
|
|
72
|
+
reject: (err: unknown) => void
|
|
73
|
+
method: string
|
|
74
|
+
}
|
|
75
|
+
>()
|
|
76
|
+
const handlers = new Map<string, Set<CodexNotificationHandler>>()
|
|
77
|
+
let nextId = 1
|
|
78
|
+
let closed = false
|
|
79
|
+
|
|
80
|
+
// the one channel child output reaches a caller on. carries the
|
|
81
|
+
// app-server's own stderr and any pipe failure against it.
|
|
82
|
+
function reportChildText(text: string): void {
|
|
83
|
+
const set = handlers.get('__stderr__')
|
|
84
|
+
if (!set) return
|
|
85
|
+
for (const h of set) {
|
|
86
|
+
try {
|
|
87
|
+
h({ text })
|
|
88
|
+
} catch {}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// an 'error' event with no listener is an uncaught exception, so a child
|
|
93
|
+
// that fails to spawn or a write against a dead app-server would take the
|
|
94
|
+
// hosting process down with exit 1 instead of letting it shut down. a
|
|
95
|
+
// failed spawn is a closed client: requests reject with the real reason
|
|
96
|
+
// rather than hanging until their timeout.
|
|
97
|
+
child.on('error', (err) => {
|
|
98
|
+
closed = true
|
|
99
|
+
reportChildText(`[codex-spawn] ${err.message}\n`)
|
|
100
|
+
})
|
|
101
|
+
child.stdin.on('error', (err) => {
|
|
102
|
+
reportChildText(`[codex-stdin] ${err.message}\n`)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const exited = new Promise<{
|
|
106
|
+
code: number | null
|
|
107
|
+
signal: NodeJS.Signals | null
|
|
108
|
+
}>((resolve) => {
|
|
109
|
+
child.on('close', (code, signal) => {
|
|
110
|
+
closed = true
|
|
111
|
+
const err = new Error(
|
|
112
|
+
`codex app-server exited (code=${code}, signal=${signal ?? ''})`,
|
|
113
|
+
)
|
|
114
|
+
for (const { reject } of pending.values()) reject(err)
|
|
115
|
+
pending.clear()
|
|
116
|
+
resolve({ code, signal })
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// stdout carries JSON-RPC messages, one per line.
|
|
121
|
+
const rl = readline.createInterface({ input: child.stdout, crlfDelay: Infinity })
|
|
122
|
+
rl.on('line', (line) => {
|
|
123
|
+
const trimmed = line.trim()
|
|
124
|
+
if (!trimmed) return
|
|
125
|
+
let msg: JsonRpcResponse
|
|
126
|
+
try {
|
|
127
|
+
msg = JSON.parse(trimmed) as JsonRpcResponse
|
|
128
|
+
} catch {
|
|
129
|
+
// app-server occasionally emits non-JSON warnings; ignore.
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
if (msg.id != null && (msg.result !== undefined || msg.error !== undefined)) {
|
|
133
|
+
const idNum = typeof msg.id === 'string' ? Number(msg.id) : msg.id
|
|
134
|
+
const entry = idNum != null ? pending.get(idNum) : undefined
|
|
135
|
+
if (!entry) return
|
|
136
|
+
pending.delete(idNum!)
|
|
137
|
+
if (msg.error) {
|
|
138
|
+
entry.reject(new CodexRpcError(msg.error.message, msg.error.code, msg.error.data))
|
|
139
|
+
} else {
|
|
140
|
+
entry.resolve(msg.result)
|
|
141
|
+
}
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
if (msg.method) {
|
|
145
|
+
const set = handlers.get(msg.method)
|
|
146
|
+
if (!set) return
|
|
147
|
+
for (const h of set) {
|
|
148
|
+
try {
|
|
149
|
+
h(msg.params)
|
|
150
|
+
} catch (err) {
|
|
151
|
+
// a buggy handler must not kill the bridge, but it MUST be visible —
|
|
152
|
+
// silent swallowing turned a notification-handler typo into a
|
|
153
|
+
// "nothing happens" bug once already.
|
|
154
|
+
console.error(
|
|
155
|
+
`[codex-client] handler for "${msg.method}" threw:`,
|
|
156
|
+
err instanceof Error ? (err.stack ?? err.message) : err,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// stderr is diagnostic only; surfaced via the "stderr" notification channel
|
|
164
|
+
// so callers can forward it into transcripts if they want.
|
|
165
|
+
child.stderr.setEncoding('utf8')
|
|
166
|
+
child.stderr.on('data', (chunk: string) => {
|
|
167
|
+
reportChildText(chunk)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
function write(msg: unknown): void {
|
|
171
|
+
if (closed) return
|
|
172
|
+
try {
|
|
173
|
+
child.stdin.write(JSON.stringify(msg) + '\n')
|
|
174
|
+
} catch {
|
|
175
|
+
// if stdin has been closed, subsequent writes will throw; ignore.
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
exited,
|
|
181
|
+
on(method, handler) {
|
|
182
|
+
let set = handlers.get(method)
|
|
183
|
+
if (!set) {
|
|
184
|
+
set = new Set()
|
|
185
|
+
handlers.set(method, set)
|
|
186
|
+
}
|
|
187
|
+
set.add(handler)
|
|
188
|
+
return () => {
|
|
189
|
+
set?.delete(handler)
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
request<TResult>(method: string, params?: unknown): Promise<TResult> {
|
|
193
|
+
if (closed) {
|
|
194
|
+
return Promise.reject(new Error(`codex app-server closed; cannot call ${method}`))
|
|
195
|
+
}
|
|
196
|
+
const id = nextId++
|
|
197
|
+
return new Promise<TResult>((resolve, reject) => {
|
|
198
|
+
pending.set(id, {
|
|
199
|
+
resolve: (v) => resolve(v as TResult),
|
|
200
|
+
reject,
|
|
201
|
+
method,
|
|
202
|
+
})
|
|
203
|
+
write({ jsonrpc: '2.0', id, method, params })
|
|
204
|
+
})
|
|
205
|
+
},
|
|
206
|
+
notify(method, params) {
|
|
207
|
+
write({ jsonrpc: '2.0', method, params })
|
|
208
|
+
},
|
|
209
|
+
async shutdown(timeoutMs = 1500) {
|
|
210
|
+
if (closed) return
|
|
211
|
+
try {
|
|
212
|
+
child.stdin.end()
|
|
213
|
+
} catch {}
|
|
214
|
+
const t = setTimeout(() => {
|
|
215
|
+
if (!closed) {
|
|
216
|
+
try {
|
|
217
|
+
child.kill('SIGTERM')
|
|
218
|
+
} catch {}
|
|
219
|
+
}
|
|
220
|
+
}, timeoutMs)
|
|
221
|
+
try {
|
|
222
|
+
await exited
|
|
223
|
+
} finally {
|
|
224
|
+
clearTimeout(t)
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
kill(signal = 'SIGTERM') {
|
|
228
|
+
if (closed) return
|
|
229
|
+
try {
|
|
230
|
+
child.kill(signal)
|
|
231
|
+
} catch {}
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// rnx.config.ts — per-app module resolution, turbo modules, env, state, and settings.
|
|
2
|
+
//
|
|
3
|
+
// usage:
|
|
4
|
+
// import { defineConfig } from 'rnxsim/config'
|
|
5
|
+
// export default defineConfig({ modules: { ... }, env: { ... } })
|
|
6
|
+
|
|
7
|
+
import type { RevenueCatTestStoreConfig } from '@sootsim/compat/revenuecat-test-store'
|
|
8
|
+
|
|
9
|
+
export type ModuleResolution =
|
|
10
|
+
// an empty module under `modules`; under `nativeModules` / `turboModules` a
|
|
11
|
+
// present-but-inert native module whose every method call is a no-op.
|
|
12
|
+
| 'noop'
|
|
13
|
+
| false // disable builtin stub, use original
|
|
14
|
+
| { use: string } // redirect to existing compat stub
|
|
15
|
+
| { file: string } // resolve to a file relative to the config
|
|
16
|
+
| { inline: Record<string, any> } // inline stub object
|
|
17
|
+
|
|
18
|
+
export type NativeModuleResolution = ModuleResolution | Record<string, any> // direct native module object for non-url configs
|
|
19
|
+
|
|
20
|
+
export interface RNXConfig<Settings extends Record<string, any> = Record<string, any>> {
|
|
21
|
+
// host-only engine selection. omitted means the current stable runtime.
|
|
22
|
+
runtimeVersion?: string
|
|
23
|
+
modules?: Record<string, ModuleResolution>
|
|
24
|
+
turboModules?: Record<string, NativeModuleResolution>
|
|
25
|
+
nativeModules?: Record<string, NativeModuleResolution>
|
|
26
|
+
env?: Record<string, string>
|
|
27
|
+
// generic per-sim network rewrites for the guest app's runtime fetches.
|
|
28
|
+
// `remap` keys/values are `host:port` (or bare `host`) — a tenant fetch whose
|
|
29
|
+
// url matches a key has its host:port swapped for the value before the
|
|
30
|
+
// request is issued. exists for third-party e2e suites that hardcode a port
|
|
31
|
+
// (e.g. bluesky's flows type `http://localhost:3000`) which collides with a
|
|
32
|
+
// host service; map it to the real bound port without editing the app.
|
|
33
|
+
network?: {
|
|
34
|
+
remap?: Record<string, string>
|
|
35
|
+
}
|
|
36
|
+
settings?: Partial<Settings>
|
|
37
|
+
initialState?: {
|
|
38
|
+
authenticated?: boolean
|
|
39
|
+
locale?: string
|
|
40
|
+
colorScheme?: 'light' | 'dark' | 'auto'
|
|
41
|
+
featureFlags?: Record<string, boolean | string | number>
|
|
42
|
+
// opt-in RevenueCat Test Store catalog consumed by the RNPurchases seam.
|
|
43
|
+
// omitting it preserves the empty-project result with purchases unavailable.
|
|
44
|
+
revenueCat?: RevenueCatTestStoreConfig
|
|
45
|
+
[key: string]: any
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const RNX_CONFIG_QUERY_PARAM = 'rnxConfig'
|
|
50
|
+
|
|
51
|
+
export function defineConfig<Settings extends Record<string, any> = Record<string, any>>(
|
|
52
|
+
config: RNXConfig<Settings>,
|
|
53
|
+
): RNXConfig<Settings> {
|
|
54
|
+
return config
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function hasOwnKeys(value: Record<string, unknown> | undefined): boolean {
|
|
58
|
+
return !!value && Object.keys(value).length > 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function hasRNXConfig<Settings extends Record<string, any> = Record<string, any>>(
|
|
62
|
+
config?: RNXConfig<Settings> | null,
|
|
63
|
+
): config is RNXConfig<Settings> {
|
|
64
|
+
if (!config) return false
|
|
65
|
+
return (
|
|
66
|
+
(typeof config.runtimeVersion === 'string' && config.runtimeVersion.length > 0) ||
|
|
67
|
+
hasOwnKeys(config.modules as Record<string, unknown> | undefined) ||
|
|
68
|
+
hasOwnKeys(config.turboModules as Record<string, unknown> | undefined) ||
|
|
69
|
+
hasOwnKeys(config.nativeModules as Record<string, unknown> | undefined) ||
|
|
70
|
+
hasOwnKeys(config.env as Record<string, unknown> | undefined) ||
|
|
71
|
+
hasOwnKeys(config.network?.remap as Record<string, unknown> | undefined) ||
|
|
72
|
+
hasOwnKeys(config.settings as Record<string, unknown> | undefined) ||
|
|
73
|
+
hasOwnKeys(config.initialState as Record<string, unknown> | undefined)
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function mergeRNXConfig<
|
|
78
|
+
Settings extends Record<string, any> = Record<string, any>,
|
|
79
|
+
>(
|
|
80
|
+
base?: RNXConfig<Settings> | null,
|
|
81
|
+
override?: RNXConfig<Settings> | null,
|
|
82
|
+
): RNXConfig<Settings> | undefined {
|
|
83
|
+
if (!hasRNXConfig(base) && !hasRNXConfig(override)) return undefined
|
|
84
|
+
if (!hasRNXConfig(base)) return override ? { ...override } : undefined
|
|
85
|
+
if (!hasRNXConfig(override)) return base ? { ...base } : undefined
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
runtimeVersion: override.runtimeVersion ?? base.runtimeVersion,
|
|
89
|
+
modules: { ...(base.modules || {}), ...(override.modules || {}) },
|
|
90
|
+
turboModules: { ...(base.turboModules || {}), ...(override.turboModules || {}) },
|
|
91
|
+
nativeModules: {
|
|
92
|
+
...(base.nativeModules || {}),
|
|
93
|
+
...(override.nativeModules || {}),
|
|
94
|
+
},
|
|
95
|
+
env: { ...(base.env || {}), ...(override.env || {}) },
|
|
96
|
+
network: {
|
|
97
|
+
remap: { ...(base.network?.remap || {}), ...(override.network?.remap || {}) },
|
|
98
|
+
},
|
|
99
|
+
settings: {
|
|
100
|
+
...(base.settings || {}),
|
|
101
|
+
...(override.settings || {}),
|
|
102
|
+
} as Partial<Settings>,
|
|
103
|
+
initialState: { ...(base.initialState || {}), ...(override.initialState || {}) },
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function readRNXConfigFromSearchParams<
|
|
108
|
+
Settings extends Record<string, any> = Record<string, any>,
|
|
109
|
+
>(searchParams: URLSearchParams): RNXConfig<Settings> | undefined {
|
|
110
|
+
const raw = searchParams.get(RNX_CONFIG_QUERY_PARAM)
|
|
111
|
+
if (!raw) return undefined
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(raw) as RNXConfig<Settings>
|
|
114
|
+
return hasRNXConfig(parsed) ? parsed : undefined
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
117
|
+
console.warn(`[rnx] invalid ${RNX_CONFIG_QUERY_PARAM}: ${message}`)
|
|
118
|
+
return undefined
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function applyRNXConfigToUrl<
|
|
123
|
+
Settings extends Record<string, any> = Record<string, any>,
|
|
124
|
+
>(url: string, config?: RNXConfig<Settings> | null): string {
|
|
125
|
+
const parsed = new URL(url)
|
|
126
|
+
if (hasRNXConfig(config)) {
|
|
127
|
+
parsed.searchParams.set(RNX_CONFIG_QUERY_PARAM, JSON.stringify(config))
|
|
128
|
+
} else {
|
|
129
|
+
parsed.searchParams.delete(RNX_CONFIG_QUERY_PARAM)
|
|
130
|
+
}
|
|
131
|
+
return parsed.toString()
|
|
132
|
+
}
|
package/src/connect.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// `connect()` — the node entrypoint of the rnxsim SDK. resolves the running
|
|
2
|
+
// bridge world the same way the CLI does (development bridge registry, then
|
|
3
|
+
// daemon, then default port), picks a sim, and returns a connected SimClient
|
|
4
|
+
// over the shared ws transport. node-only by design: sim-client.ts stays
|
|
5
|
+
// browser-safe.
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createCloudBridgeForParsed,
|
|
9
|
+
resolveCloudSessionForParsed,
|
|
10
|
+
} from '../cli/cloud-client'
|
|
11
|
+
import { readCurrentSimId } from '../cli/current-sim'
|
|
12
|
+
import { createBridge, resolveBridgeWorld, type BridgeSimInfo } from '../cli/ws-bridge'
|
|
13
|
+
import { SimClient, SimConnectError } from './sim-client'
|
|
14
|
+
|
|
15
|
+
export interface ConnectOptions {
|
|
16
|
+
/** ws bridge port. default: the resolved bridge world (lockfiles). */
|
|
17
|
+
port?: number
|
|
18
|
+
/** sim id to attach to (as shown by `rnx list`). default: the primary sim. */
|
|
19
|
+
sim?: string
|
|
20
|
+
/** per-command bridge timeout in ms. default 15000. */
|
|
21
|
+
timeoutMs?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function pickSim(
|
|
25
|
+
sims: BridgeSimInfo[],
|
|
26
|
+
wanted: string | undefined,
|
|
27
|
+
port: number,
|
|
28
|
+
): BridgeSimInfo {
|
|
29
|
+
const open = sims.filter((sim) => sim.readyState === 'open')
|
|
30
|
+
if (wanted) {
|
|
31
|
+
const match = open.find((sim) => sim.id === wanted)
|
|
32
|
+
if (!match) {
|
|
33
|
+
throw new SimConnectError(
|
|
34
|
+
`no sim connected with id ${wanted} on bridge :${port}` +
|
|
35
|
+
(open.length
|
|
36
|
+
? ` — connected: ${open.map((sim) => sim.id).join(', ')}`
|
|
37
|
+
: ' — no sims connected; open one with `rnx open <port>`'),
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
return match
|
|
41
|
+
}
|
|
42
|
+
// same session affinity as the CLI: a sim pinned by `rnx open` /
|
|
43
|
+
// `rnx use` in this terminal wins over the primary election, so a script
|
|
44
|
+
// run next to CLI commands drives the sim the terminal is working with. a
|
|
45
|
+
// stale pin (sim gone) falls through to the primary.
|
|
46
|
+
const pinned = readCurrentSimId()
|
|
47
|
+
if (pinned) {
|
|
48
|
+
const match = open.find((sim) => sim.id === pinned)
|
|
49
|
+
if (match) return match
|
|
50
|
+
}
|
|
51
|
+
const primary = open.find((sim) => sim.isPrimary) ?? open[0]
|
|
52
|
+
if (!primary) {
|
|
53
|
+
throw new SimConnectError(
|
|
54
|
+
`no sims connected on bridge :${port} — open one with \`rnx open <port>\``,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
return primary
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function connect(options: ConnectOptions = {}): Promise<SimClient> {
|
|
61
|
+
const target = {
|
|
62
|
+
simId: options.sim,
|
|
63
|
+
simIdSource: options.sim ? 'flag' : 'none',
|
|
64
|
+
} satisfies Parameters<typeof resolveCloudSessionForParsed>[0]
|
|
65
|
+
const cloud = resolveCloudSessionForParsed(target)
|
|
66
|
+
if (cloud) {
|
|
67
|
+
const bridge = createCloudBridgeForParsed(target)
|
|
68
|
+
if (!bridge)
|
|
69
|
+
throw new SimConnectError('remote simulator session disappeared while connecting')
|
|
70
|
+
return new SimClient(bridge, cloud.simId, {
|
|
71
|
+
commandTimeoutMs: options.timeoutMs ?? 15_000,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const port = options.port ?? resolveBridgeWorld().bridgePort
|
|
76
|
+
const commandTimeoutMs = options.timeoutMs ?? 15_000
|
|
77
|
+
|
|
78
|
+
// discovery socket: list sims and pick the target. closed before the pinned
|
|
79
|
+
// client socket is opened so a failed connect never leaks a connection.
|
|
80
|
+
const discovery = createBridge(port, { commandTimeoutMs, cliLabel: 'sdk' })
|
|
81
|
+
let picked: BridgeSimInfo
|
|
82
|
+
try {
|
|
83
|
+
picked = pickSim(await discovery.listSims(), options.sim, port)
|
|
84
|
+
} catch (error) {
|
|
85
|
+
discovery.close()
|
|
86
|
+
if (error instanceof SimConnectError) throw error
|
|
87
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
88
|
+
throw new SimConnectError(`${message} — is the rnx daemon or dev shell running?`)
|
|
89
|
+
}
|
|
90
|
+
discovery.close()
|
|
91
|
+
|
|
92
|
+
// pinned socket: every command targets exactly the picked sim, immune to the
|
|
93
|
+
// CLI's saved-pin re-resolution.
|
|
94
|
+
const bridge = createBridge(port, {
|
|
95
|
+
commandTimeoutMs,
|
|
96
|
+
cliLabel: 'sdk',
|
|
97
|
+
simId: picked.id,
|
|
98
|
+
simIdSource: 'flag',
|
|
99
|
+
})
|
|
100
|
+
return new SimClient(bridge, picked.id, { commandTimeoutMs })
|
|
101
|
+
}
|