super-dsh 0.1.6 → 0.1.10-e
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/README.md +25 -3
- package/agent-agy/cordis.patch.yml +7 -4
- package/agent-agy/dist/agent.d.ts +12 -11
- package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
- package/agent-agy/dist/agy-auth-gateway.js +233 -0
- package/agent-agy/dist/agy-auth.d.ts +153 -0
- package/agent-agy/dist/agy-auth.js +179 -0
- package/agent-agy/dist/agy-cli-client.d.ts +39 -9
- package/agent-agy/dist/agy-cli-client.js +82 -18
- package/agent-agy/dist/agy-store.d.ts +8 -0
- package/agent-agy/dist/index.d.ts +46 -16
- package/agent-agy/dist/index.js +82 -56
- package/agent-agy/dist/models.d.ts +70 -0
- package/agent-agy/dist/models.js +102 -3
- package/agent-agy/package.json +7 -5
- package/agent-agy-sdk/cordis.patch.yml +58 -0
- package/agent-agy-sdk/dist/adapter.d.ts +15 -0
- package/agent-agy-sdk/dist/adapter.js +42 -0
- package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
- package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
- package/agent-agy-sdk/dist/agent.d.ts +138 -0
- package/agent-agy-sdk/dist/agent.js +494 -0
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
- package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
- package/agent-agy-sdk/dist/agy-sessions.js +107 -0
- package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
- package/agent-agy-sdk/dist/agy-store.js +83 -0
- package/agent-agy-sdk/dist/inbox.d.ts +26 -0
- package/agent-agy-sdk/dist/inbox.js +53 -0
- package/agent-agy-sdk/dist/index.d.ts +93 -0
- package/agent-agy-sdk/dist/index.js +476 -0
- package/agent-agy-sdk/dist/models.d.ts +41 -0
- package/agent-agy-sdk/dist/models.js +74 -0
- package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
- package/agent-agy-sdk/dist/sdk-venv.js +173 -0
- package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-agy-sdk/dist/world-plugin.js +82 -0
- package/agent-agy-sdk/package.json +64 -0
- package/agent-claude/dist/adapter.js +106 -31
- package/agent-claude/dist/agent.js +154 -17
- package/agent-claude/dist/claude-client.js +84 -43
- package/agent-claude/dist/claude-launch.js +101 -0
- package/agent-claude/dist/claude-native-config.js +169 -0
- package/agent-claude/dist/claude-provider-gateway.js +340 -0
- package/agent-claude/dist/claude-providers.js +391 -0
- package/agent-claude/dist/claude-route.js +152 -0
- package/agent-claude/dist/index.js +214 -37
- package/agent-claude/dist/models.js +14 -0
- package/agent-claude/dist/sdk-runtime.js +320 -0
- package/agent-claude/package.json +6 -4
- package/agent-codex/README.md +141 -36
- package/agent-codex/cordis.patch.yml +14 -10
- package/agent-codex/dist/adapter.js +64 -28
- package/agent-codex/dist/agent.js +255 -81
- package/agent-codex/dist/app-server-approvals.js +165 -0
- package/agent-codex/dist/app-server-client.js +723 -0
- package/agent-codex/dist/app-server-events.js +432 -0
- package/agent-codex/dist/app-server-protocol.js +95 -0
- package/agent-codex/dist/app-server-wire.js +299 -0
- package/agent-codex/dist/codex-launch.js +78 -0
- package/agent-codex/dist/codex-native-config.js +392 -0
- package/agent-codex/dist/codex-provider-gateway.js +402 -0
- package/agent-codex/dist/codex-providers.js +376 -0
- package/agent-codex/dist/codex-route.js +86 -0
- package/agent-codex/dist/index.js +256 -115
- package/agent-codex/dist/permission.js +75 -1
- package/agent-codex/package.json +1 -2
- package/agent-codex-sdk/README.md +79 -0
- package/agent-codex-sdk/cordis.patch.yml +81 -0
- package/agent-codex-sdk/dist/adapter.js +91 -0
- package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
- package/agent-codex-sdk/dist/agent.js +1085 -0
- package/agent-codex-sdk/dist/codex-native-config.js +392 -0
- package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
- package/agent-codex-sdk/dist/codex-providers.js +376 -0
- package/agent-codex-sdk/dist/codex-route.js +86 -0
- package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
- package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
- package/agent-codex-sdk/dist/codex-store.js +180 -0
- package/agent-codex-sdk/dist/inbox.js +53 -0
- package/agent-codex-sdk/dist/index.js +739 -0
- package/agent-codex-sdk/dist/permission.js +71 -0
- package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
- package/agent-codex-sdk/dist/session-map.js +167 -0
- package/agent-codex-sdk/dist/world-plugin.js +93 -0
- package/agent-codex-sdk/package.json +79 -0
- package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
- package/agent-omp/README.md +72 -55
- package/agent-omp/dist/agent.js +36 -11
- package/agent-omp/dist/index.js +92 -52
- package/agent-omp/dist/lazy-rpc.js +11 -4
- package/agent-omp/dist/omp-cli.js +114 -97
- package/agent-omp/dist/omp-store.js +12 -4
- package/agent-omp/dist/permission.js +70 -5
- package/agent-omp/dist/rpc-client.js +409 -0
- package/agent-omp/dist/world-plugin.js +36 -3
- package/agent-omp/package.json +2 -6
- package/agent-omp-sdk/README.md +103 -0
- package/agent-omp-sdk/cordis.patch.yml +108 -0
- package/agent-omp-sdk/dist/adapter.d.ts +21 -0
- package/agent-omp-sdk/dist/adapter.js +36 -0
- package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
- package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
- package/agent-omp-sdk/dist/agent.d.ts +64 -0
- package/agent-omp-sdk/dist/agent.js +1178 -0
- package/agent-omp-sdk/dist/discovery.d.ts +57 -0
- package/agent-omp-sdk/dist/discovery.js +116 -0
- package/agent-omp-sdk/dist/inbox.d.ts +28 -0
- package/agent-omp-sdk/dist/inbox.js +53 -0
- package/agent-omp-sdk/dist/index.d.ts +60 -0
- package/agent-omp-sdk/dist/index.js +632 -0
- package/agent-omp-sdk/dist/knobs.d.ts +34 -0
- package/agent-omp-sdk/dist/knobs.js +50 -0
- package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
- package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
- package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
- package/agent-omp-sdk/dist/mobile-boot.js +38 -0
- package/agent-omp-sdk/dist/models.d.ts +39 -0
- package/agent-omp-sdk/dist/models.js +299 -0
- package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
- package/agent-omp-sdk/dist/omp-cli.js +164 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
- package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
- package/agent-omp-sdk/dist/omp-executable.js +30 -0
- package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
- package/agent-omp-sdk/dist/omp-store.js +526 -0
- package/agent-omp-sdk/dist/pairing.d.ts +7 -0
- package/agent-omp-sdk/dist/pairing.js +45 -0
- package/agent-omp-sdk/dist/permission.d.ts +138 -0
- package/agent-omp-sdk/dist/permission.js +161 -0
- package/agent-omp-sdk/dist/protocol.d.ts +189 -0
- package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
- package/agent-omp-sdk/dist/rpc-types.js +1 -0
- package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
- package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
- package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
- package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
- package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
- package/agent-omp-sdk/dist/sidecar-client.js +197 -0
- package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
- package/agent-omp-sdk/dist/store/adapter.js +47 -0
- package/agent-omp-sdk/dist/store/db.d.ts +70 -0
- package/agent-omp-sdk/dist/store/db.js +210 -0
- package/agent-omp-sdk/dist/store/index.d.ts +23 -0
- package/agent-omp-sdk/dist/store/index.js +59 -0
- package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
- package/agent-omp-sdk/dist/store/reconcile.js +51 -0
- package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
- package/agent-omp-sdk/dist/store/schema.js +40 -0
- package/agent-omp-sdk/dist/transport.d.ts +49 -0
- package/agent-omp-sdk/dist/transport.js +35 -0
- package/agent-omp-sdk/dist/world-home.d.ts +4 -0
- package/agent-omp-sdk/dist/world-home.js +23 -0
- package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-omp-sdk/dist/world-plugin.js +137 -0
- package/agent-omp-sdk/package.json +87 -0
- package/client/index.js +1883 -287
- package/cordis.patch.yml +80 -0
- package/package.json +23 -9
- package/superd-hub/dist/a2a-delivery.d.ts +189 -0
- package/superd-hub/dist/a2a-delivery.js +240 -0
- package/superd-hub/dist/a2a-host.d.ts +76 -0
- package/superd-hub/dist/a2a-host.js +145 -0
- package/superd-hub/dist/a2a-ingest.d.ts +31 -0
- package/superd-hub/dist/a2a-ingest.js +636 -0
- package/superd-hub/dist/a2a-log.d.ts +17 -0
- package/superd-hub/dist/a2a-log.js +42 -0
- package/superd-hub/dist/a2a-row.d.ts +65 -0
- package/superd-hub/dist/a2a-row.js +162 -0
- package/superd-hub/dist/a2a-service.d.ts +357 -0
- package/superd-hub/dist/a2a-service.js +980 -0
- package/superd-hub/dist/a2a-wire.d.ts +220 -0
- package/superd-hub/dist/a2a-wire.js +305 -0
- package/superd-hub/dist/agent-ids.d.ts +10 -0
- package/superd-hub/dist/agent-ids.js +68 -0
- package/superd-hub/dist/agent-roster.d.ts +29 -18
- package/superd-hub/dist/agent-roster.js +54 -15
- package/superd-hub/dist/agent-status.d.ts +119 -0
- package/superd-hub/dist/agent-status.js +386 -0
- package/superd-hub/dist/client/agent-settings.d.ts +210 -0
- package/superd-hub/dist/client/agent-settings.js +300 -0
- package/superd-hub/dist/client/mesh-api.d.ts +134 -0
- package/superd-hub/dist/client/mesh-api.js +219 -0
- package/superd-hub/dist/client/mesh-groups.d.ts +63 -0
- package/superd-hub/dist/client/mesh-groups.js +66 -0
- package/superd-hub/dist/client/roster.d.ts +48 -0
- package/superd-hub/dist/client/roster.js +102 -0
- package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
- package/superd-hub/dist/client/runtime-settings-api.js +137 -0
- package/superd-hub/dist/client/switch.d.ts +165 -0
- package/superd-hub/dist/client/switch.js +295 -0
- package/superd-hub/dist/exec-pty-channel.d.ts +58 -0
- package/superd-hub/dist/exec-pty-channel.js +162 -0
- package/superd-hub/dist/exec-pty-framing.d.ts +32 -0
- package/superd-hub/dist/exec-pty-framing.js +81 -0
- package/superd-hub/dist/exec-pty-rpc.d.ts +21 -0
- package/superd-hub/dist/exec-pty-rpc.js +128 -0
- package/superd-hub/dist/exec-pty-session.d.ts +76 -0
- package/superd-hub/dist/exec-pty-session.js +234 -0
- package/superd-hub/dist/exec.d.ts +56 -0
- package/superd-hub/dist/exec.js +225 -0
- package/superd-hub/dist/gateway.d.ts +39 -2
- package/superd-hub/dist/gateway.js +62 -3
- package/superd-hub/dist/hub-tool.d.ts +174 -0
- package/superd-hub/dist/hub-tool.js +464 -0
- package/superd-hub/dist/index.d.ts +15 -1
- package/superd-hub/dist/index.js +16 -0
- package/superd-hub/dist/machines.d.ts +45 -0
- package/superd-hub/dist/machines.js +125 -0
- package/superd-hub/dist/mesh-federate.d.ts +138 -0
- package/superd-hub/dist/mesh-federate.js +223 -0
- package/superd-hub/dist/mesh-gateway.d.ts +67 -0
- package/superd-hub/dist/mesh-gateway.js +408 -0
- package/superd-hub/dist/mesh-link.d.ts +274 -0
- package/superd-hub/dist/mesh-link.js +441 -0
- package/superd-hub/dist/mesh-rpc.d.ts +123 -0
- package/superd-hub/dist/mesh-rpc.js +250 -0
- package/superd-hub/dist/mux-client.d.ts +71 -0
- package/superd-hub/dist/mux-client.js +281 -0
- package/superd-hub/dist/pack-version.d.ts +2 -0
- package/superd-hub/dist/pack-version.js +30 -0
- package/superd-hub/dist/roster.d.ts +6 -0
- package/superd-hub/dist/rpc.d.ts +18 -2
- package/superd-hub/dist/rpc.js +34 -4
- package/superd-hub/dist/spawn-world.js +3 -1
- package/superd-hub/dist/switch-core.d.ts +62 -25
- package/superd-hub/dist/switch-core.js +53 -30
- package/superd-hub/dist/system-head.d.ts +22 -12
- package/superd-hub/dist/system-head.js +100 -84
- package/superd-hub/dist/wire-endpoints.d.ts +264 -0
- package/superd-hub/dist/wire-endpoints.js +180 -0
- package/superd-hub/lib/client/index.js +1883 -287
- package/superd-hub/package.json +11 -2
- package/agent-agy/dist/agent-preset-projection.d.ts +0 -31
- package/agent-agy/dist/agent-preset-projection.js +0 -33
- package/agent-claude/dist/agent-preset-projection.js +0 -30
- package/agent-codex/dist/agent-preset-projection.js +0 -37
- package/agent-codex/dist/app-home.js +0 -65
- package/agent-codex/dist/models.js +0 -152
- package/agent-codex/dist/spike.js +0 -46
- package/agent-hermes/dist/agent-preset-projection.js +0 -34
- package/agent-omp/dist/agent-preset-projection.js +0 -36
- package/agent-omp/dist/app-home.js +0 -86
- package/agent-omp/dist/sidecar-client.js +0 -195
- package/agent-pi/dist/agent-preset-projection.js +0 -29
- package/superd-hub/dist/client-shim.d.ts +0 -28
- package/superd-hub/dist/client-shim.js +0 -251
- package/superd-hub/dist/index-pass.d.ts +0 -22
- package/superd-hub/dist/index-pass.js +0 -47
- package/superd-hub/dist/labels.d.ts +0 -45
- package/superd-hub/dist/labels.js +0 -83
- /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
- /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
- /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
- /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
- /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env-tunable knobs.
|
|
3
|
+
*
|
|
4
|
+
* dsh-shape-session-log retired the union-era supervisor cadence and replay
|
|
5
|
+
* cache knobs along with the supervisor and the union persistence.
|
|
6
|
+
*/
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
function parseMs(raw, fallback) {
|
|
10
|
+
if (raw === undefined || raw.trim() === "")
|
|
11
|
+
return fallback;
|
|
12
|
+
const value = Number(raw);
|
|
13
|
+
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
14
|
+
}
|
|
15
|
+
/** Bridge-index tick: workspace attach + model-default sync + model refresh. */
|
|
16
|
+
export const STORAGE_RECONCILE_INTERVAL_MS = parseMs(process.env.OMP_STORAGE_RECONCILE_INTERVAL_MS, 30_000);
|
|
17
|
+
/**
|
|
18
|
+
* Slash-command discovery refresh: the disk scan (omp+claude roots) re-mounts
|
|
19
|
+
* the host `commands` registrations on this cadence — boot once, then hourly.
|
|
20
|
+
* Pure disk reads, never a sidecar spawn. `0` disables the refresh.
|
|
21
|
+
*/
|
|
22
|
+
export const OMP_DISCOVERY_REFRESH_INTERVAL_MS = parseMs(process.env.OMP_DISCOVERY_REFRESH_INTERVAL_MS, 3_600_000);
|
|
23
|
+
/**
|
|
24
|
+
* The OMP home — the SDK runtime app home (`agentDir`): runtime data
|
|
25
|
+
* (agent.db / models.db / sessions) and config live here. NATIVE by default
|
|
26
|
+
* (user ruling 2026-09-17, pi precedent):
|
|
27
|
+
*
|
|
28
|
+
* OMP_HOME = $OMP_HOME (tests / adapter-level isolation) ?? ~/.omp
|
|
29
|
+
*
|
|
30
|
+
* The installed OMP app keeps its own home; the adapter never redirects it at
|
|
31
|
+
* spawn and never seeds config into it. `<dshHome>/agents/omp` remains the
|
|
32
|
+
* world's DSH home (its sessions/storages/settings) — it is NOT the app home
|
|
33
|
+
* anymore. The old nested derivation (`dshHomePath("agents", "omp", ".omp")`)
|
|
34
|
+
* and the config copy-in (`ensureOmpAppHome`) are retired with the same
|
|
35
|
+
* ruling; `OMP_HOME` stays overridable per the 2026-09-15 adapter-level
|
|
36
|
+
* freedom (optional isolation, never the default).
|
|
37
|
+
*/
|
|
38
|
+
export const OMP_HOME = process.env.OMP_HOME ?? resolveOmpNativeHome();
|
|
39
|
+
/**
|
|
40
|
+
* The operator's NATIVE OMP home (`~/.omp`): the TUI/CLI installation owning
|
|
41
|
+
* `agent/config.yml`, `agent/models.yml` and the native session store. Since
|
|
42
|
+
* the 2026-09-17 native-home ruling this is ALSO the default runtime app home
|
|
43
|
+
* ({@link OMP_HOME}); the knob stays as a late env override seam (tests may
|
|
44
|
+
* pin disk-scan roots via `$OMP_NATIVE_HOME` independently of `$OMP_HOME`).
|
|
45
|
+
*/
|
|
46
|
+
export function resolveOmpNativeHome() {
|
|
47
|
+
return process.env.OMP_NATIVE_HOME ?? join(homedir(), ".omp");
|
|
48
|
+
}
|
|
49
|
+
/** Boot-time snapshot of {@link resolveOmpNativeHome}. */
|
|
50
|
+
export const OMP_NATIVE_HOME = resolveOmpNativeHome();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LazyOmpRpc — the create-time placeholder that makes a freshly created Dash
|
|
3
|
+
* session cost NOTHING on the backend (the "backend takes zero part in the
|
|
4
|
+
* UI's draft" contract):
|
|
5
|
+
*
|
|
6
|
+
* - constructing one spawns no OMP child, writes no transcript, no index
|
|
7
|
+
* row, and no session events — the session announces blank, exactly like
|
|
8
|
+
* the native agent-loop factory's in-process agent;
|
|
9
|
+
* - the shared-sidecar session materializes on the FIRST dispatch path
|
|
10
|
+
* (`prompt` / `followUp` / `steer` / `ensureStarted`);
|
|
11
|
+
* - passive queries (`getState` / `getSubagents` / `getSessionStats` /
|
|
12
|
+
* `getSystemPrompt` / `abort` / `sendRaw`) answer synthetically without
|
|
13
|
+
* spawning, so idle-exit revalidation, `whenIdle`, and avoidance checks
|
|
14
|
+
* can never conjure a child;
|
|
15
|
+
* - `close()` on a never-spawned wrapper is a no-op; a close racing an
|
|
16
|
+
* in-flight spawn disposes the child the moment it lands.
|
|
17
|
+
*
|
|
18
|
+
* A model selection made before the child exists (`setModel` from the pre-turn
|
|
19
|
+
* sync) is parked and applied right after the spawn, ahead of the prompt.
|
|
20
|
+
*/
|
|
21
|
+
import type { OmpSessionStats, OmpState, RpcEvent } from "./rpc-types.js";
|
|
22
|
+
import { OmpSdkClient, type OmpSdkSidecarPool } from "./sdk-client.js";
|
|
23
|
+
/**
|
|
24
|
+
* The client surface `OmpAgent` drives. `OmpSdkClient` satisfies this
|
|
25
|
+
* structurally (plus `ensureStarted`/`spawned`, which are no-ops/trues there);
|
|
26
|
+
* `LazyOmpRpc` implements it with deferred spawning.
|
|
27
|
+
*/
|
|
28
|
+
export interface OmpAgentRpc {
|
|
29
|
+
on(listener: (event: RpcEvent) => void): () => void;
|
|
30
|
+
onTitle(listener: (title: string) => void): () => void;
|
|
31
|
+
onFailure(listener: (error: Error) => void): () => void;
|
|
32
|
+
prompt(message: string): Promise<unknown>;
|
|
33
|
+
followUp(message: string): Promise<unknown>;
|
|
34
|
+
steer(message: string): Promise<unknown>;
|
|
35
|
+
compact(instructions?: string): Promise<unknown>;
|
|
36
|
+
contextUsage(): Promise<{
|
|
37
|
+
tokens?: number;
|
|
38
|
+
percent?: number;
|
|
39
|
+
} | undefined>;
|
|
40
|
+
abort(): Promise<unknown>;
|
|
41
|
+
/** Forces the child to exist (first prompt). Never rejects for being live. */
|
|
42
|
+
ensureStarted(): Promise<void>;
|
|
43
|
+
/** Whether the child exists — passive paths key off this, never spawn. */
|
|
44
|
+
readonly spawned: boolean;
|
|
45
|
+
getState(): Promise<OmpState>;
|
|
46
|
+
getSubagents(): Promise<unknown[]>;
|
|
47
|
+
getSessionStats(): Promise<OmpSessionStats>;
|
|
48
|
+
getSystemPrompt(): Promise<string | undefined>;
|
|
49
|
+
setModel(provider: string, modelId: string): Promise<unknown>;
|
|
50
|
+
sendRaw(command: Record<string, unknown>): void;
|
|
51
|
+
close(): void;
|
|
52
|
+
}
|
|
53
|
+
export declare class LazyOmpRpc implements OmpAgentRpc {
|
|
54
|
+
#private;
|
|
55
|
+
/**
|
|
56
|
+
* @param spawnArgs - the session's argv (`--approval-mode …`, optional
|
|
57
|
+
* `--resume …`), or a thunk called AT SPAWN. Use the thunk whenever a
|
|
58
|
+
* launch fact can still change between construction and the first prompt —
|
|
59
|
+
* the new-chat permission pick does, and so does the lazily fetched SDK
|
|
60
|
+
* runtime the spawn depends on.
|
|
61
|
+
* @param cwd - the session cwd.
|
|
62
|
+
* @param pool - the sidecar pool (default: the process-wide one).
|
|
63
|
+
*/
|
|
64
|
+
constructor(spawnArgs: string[] | (() => string[]), cwd?: string, pool?: OmpSdkSidecarPool);
|
|
65
|
+
/**
|
|
66
|
+
* Bridge hook: runs once when the child first exists (the caller writes the
|
|
67
|
+
* index row + supervisor held-baseline there — the create-time counterparts
|
|
68
|
+
* were deliberately skipped). Registered before or after the spawn; both
|
|
69
|
+
* orders fire exactly once.
|
|
70
|
+
*/
|
|
71
|
+
onSpawned(handler: (client: OmpSdkClient) => void): void;
|
|
72
|
+
get spawned(): boolean;
|
|
73
|
+
on(listener: (event: RpcEvent) => void): () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Title frames must survive the deferred spawn: OMP generates the title from
|
|
76
|
+
* the first prompt, which is exactly the moment this RPC materializes, so a
|
|
77
|
+
* listener registered before then would otherwise miss the only frame.
|
|
78
|
+
*/
|
|
79
|
+
onTitle(listener: (title: string) => void): () => void;
|
|
80
|
+
onFailure(listener: (error: Error) => void): () => void;
|
|
81
|
+
prompt(message: string): Promise<unknown>;
|
|
82
|
+
followUp(message: string): Promise<unknown>;
|
|
83
|
+
steer(message: string): Promise<unknown>;
|
|
84
|
+
compact(instructions?: string): Promise<unknown>;
|
|
85
|
+
contextUsage(): Promise<{
|
|
86
|
+
tokens?: number;
|
|
87
|
+
percent?: number;
|
|
88
|
+
} | undefined>;
|
|
89
|
+
abort(): Promise<unknown>;
|
|
90
|
+
ensureStarted(): Promise<void>;
|
|
91
|
+
getState(): Promise<OmpState>;
|
|
92
|
+
getSubagents(): Promise<unknown[]>;
|
|
93
|
+
getSessionStats(): Promise<OmpSessionStats>;
|
|
94
|
+
getSystemPrompt(): Promise<string | undefined>;
|
|
95
|
+
setModel(provider: string, modelId: string): Promise<unknown>;
|
|
96
|
+
sendRaw(command: Record<string, unknown>): void;
|
|
97
|
+
close(): void;
|
|
98
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { defaultOmpSdkSidecarPool } from "./sdk-client.js";
|
|
2
|
+
/** Synthetic state for a not-yet-spawned child: quiescent by definition. */
|
|
3
|
+
const IDLE_STATE = { isStreaming: false };
|
|
4
|
+
export class LazyOmpRpc {
|
|
5
|
+
#spawnArgs;
|
|
6
|
+
#cwd;
|
|
7
|
+
/**
|
|
8
|
+
* The sidecar pool this wrapper rides (the process-wide default unless a test
|
|
9
|
+
* or a second world injects its own). Every session of one pool shares ONE
|
|
10
|
+
* bun child — that singleton IS the reason the SDK row exists.
|
|
11
|
+
*/
|
|
12
|
+
#pool;
|
|
13
|
+
#client;
|
|
14
|
+
#spawn;
|
|
15
|
+
#closed = false;
|
|
16
|
+
#eventListeners = new Set();
|
|
17
|
+
#titleListeners = new Set();
|
|
18
|
+
#failureListeners = new Set();
|
|
19
|
+
#pendingModel;
|
|
20
|
+
#onSpawned;
|
|
21
|
+
/**
|
|
22
|
+
* @param spawnArgs - the session's argv (`--approval-mode …`, optional
|
|
23
|
+
* `--resume …`), or a thunk called AT SPAWN. Use the thunk whenever a
|
|
24
|
+
* launch fact can still change between construction and the first prompt —
|
|
25
|
+
* the new-chat permission pick does, and so does the lazily fetched SDK
|
|
26
|
+
* runtime the spawn depends on.
|
|
27
|
+
* @param cwd - the session cwd.
|
|
28
|
+
* @param pool - the sidecar pool (default: the process-wide one).
|
|
29
|
+
*/
|
|
30
|
+
constructor(spawnArgs, cwd, pool) {
|
|
31
|
+
this.#spawnArgs = spawnArgs;
|
|
32
|
+
this.#cwd = cwd;
|
|
33
|
+
this.#pool = pool ?? defaultOmpSdkSidecarPool();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Bridge hook: runs once when the child first exists (the caller writes the
|
|
37
|
+
* index row + supervisor held-baseline there — the create-time counterparts
|
|
38
|
+
* were deliberately skipped). Registered before or after the spawn; both
|
|
39
|
+
* orders fire exactly once.
|
|
40
|
+
*/
|
|
41
|
+
onSpawned(handler) {
|
|
42
|
+
this.#onSpawned = handler;
|
|
43
|
+
if (this.#client !== undefined)
|
|
44
|
+
handler(this.#client);
|
|
45
|
+
}
|
|
46
|
+
get spawned() {
|
|
47
|
+
return this.#client !== undefined;
|
|
48
|
+
}
|
|
49
|
+
/** Spawn once; concurrent and later callers share the same child. */
|
|
50
|
+
#ensure() {
|
|
51
|
+
if (this.#client !== undefined)
|
|
52
|
+
return Promise.resolve(this.#client);
|
|
53
|
+
if (this.#spawn === undefined) {
|
|
54
|
+
const args = typeof this.#spawnArgs === "function" ? this.#spawnArgs() : this.#spawnArgs;
|
|
55
|
+
this.#spawn = this.#pool.spawnSession(args, this.#cwd).then((client) => {
|
|
56
|
+
// A close() that raced the in-flight spawn wins: dispose immediately.
|
|
57
|
+
if (this.#closed) {
|
|
58
|
+
client.close();
|
|
59
|
+
return client;
|
|
60
|
+
}
|
|
61
|
+
this.#client = client;
|
|
62
|
+
for (const listener of this.#eventListeners)
|
|
63
|
+
client.on(listener);
|
|
64
|
+
for (const listener of this.#titleListeners)
|
|
65
|
+
client.onTitle(listener);
|
|
66
|
+
for (const listener of this.#failureListeners)
|
|
67
|
+
client.onFailure(listener);
|
|
68
|
+
this.#onSpawned?.(client);
|
|
69
|
+
return client;
|
|
70
|
+
}).catch((error) => {
|
|
71
|
+
// Allow a later dispatch to retry the spawn.
|
|
72
|
+
this.#spawn = undefined;
|
|
73
|
+
throw error;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return this.#spawn;
|
|
77
|
+
}
|
|
78
|
+
on(listener) {
|
|
79
|
+
this.#eventListeners.add(listener);
|
|
80
|
+
if (this.#client !== undefined)
|
|
81
|
+
this.#client.on(listener);
|
|
82
|
+
return () => {
|
|
83
|
+
this.#eventListeners.delete(listener);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Title frames must survive the deferred spawn: OMP generates the title from
|
|
88
|
+
* the first prompt, which is exactly the moment this RPC materializes, so a
|
|
89
|
+
* listener registered before then would otherwise miss the only frame.
|
|
90
|
+
*/
|
|
91
|
+
onTitle(listener) {
|
|
92
|
+
this.#titleListeners.add(listener);
|
|
93
|
+
if (this.#client !== undefined)
|
|
94
|
+
this.#client.onTitle(listener);
|
|
95
|
+
return () => {
|
|
96
|
+
this.#titleListeners.delete(listener);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
onFailure(listener) {
|
|
100
|
+
this.#failureListeners.add(listener);
|
|
101
|
+
if (this.#client !== undefined)
|
|
102
|
+
this.#client.onFailure(listener);
|
|
103
|
+
return () => {
|
|
104
|
+
this.#failureListeners.delete(listener);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async prompt(message) {
|
|
108
|
+
const client = await this.#ensure();
|
|
109
|
+
// Apply a pre-spawn model selection now, ahead of the prompt (the sidecar
|
|
110
|
+
// records it as the session's model_change, like a pre-turn set_model).
|
|
111
|
+
const pending = this.#pendingModel;
|
|
112
|
+
if (pending !== undefined) {
|
|
113
|
+
this.#pendingModel = undefined;
|
|
114
|
+
await client.setModel(pending.provider, pending.modelId).catch(() => { });
|
|
115
|
+
}
|
|
116
|
+
return client.prompt(message);
|
|
117
|
+
}
|
|
118
|
+
async followUp(message) {
|
|
119
|
+
return (await this.#ensure()).followUp(message);
|
|
120
|
+
}
|
|
121
|
+
async steer(message) {
|
|
122
|
+
return (await this.#ensure()).steer(message);
|
|
123
|
+
}
|
|
124
|
+
async compact(instructions) {
|
|
125
|
+
return (await this.#ensure()).compact(instructions);
|
|
126
|
+
}
|
|
127
|
+
async contextUsage() {
|
|
128
|
+
if (this.#client === undefined)
|
|
129
|
+
return undefined;
|
|
130
|
+
return this.#client.contextUsage();
|
|
131
|
+
}
|
|
132
|
+
async abort() {
|
|
133
|
+
if (this.#client === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
return this.#client.abort();
|
|
136
|
+
}
|
|
137
|
+
async ensureStarted() {
|
|
138
|
+
await this.#ensure();
|
|
139
|
+
}
|
|
140
|
+
async getState() {
|
|
141
|
+
if (this.#client === undefined)
|
|
142
|
+
return IDLE_STATE;
|
|
143
|
+
return this.#client.getState();
|
|
144
|
+
}
|
|
145
|
+
async getSubagents() {
|
|
146
|
+
if (this.#client === undefined)
|
|
147
|
+
return [];
|
|
148
|
+
return this.#client.getSubagents();
|
|
149
|
+
}
|
|
150
|
+
async getSessionStats() {
|
|
151
|
+
if (this.#client === undefined)
|
|
152
|
+
return {};
|
|
153
|
+
return this.#client.getSessionStats();
|
|
154
|
+
}
|
|
155
|
+
async getSystemPrompt() {
|
|
156
|
+
if (this.#client === undefined)
|
|
157
|
+
return undefined;
|
|
158
|
+
return this.#client.getSystemPrompt();
|
|
159
|
+
}
|
|
160
|
+
async setModel(provider, modelId) {
|
|
161
|
+
if (this.#client === undefined) {
|
|
162
|
+
// Park it: applied by prompt() immediately after the spawn.
|
|
163
|
+
this.#pendingModel = { provider, modelId };
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
return this.#client.setModel(provider, modelId);
|
|
167
|
+
}
|
|
168
|
+
sendRaw(command) {
|
|
169
|
+
if (this.#client !== undefined)
|
|
170
|
+
this.#client.sendRaw(command);
|
|
171
|
+
}
|
|
172
|
+
close() {
|
|
173
|
+
this.#closed = true;
|
|
174
|
+
const client = this.#client;
|
|
175
|
+
this.#client = undefined;
|
|
176
|
+
client?.close();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iOS focus auto-zoom suppression — pure decision core (host half, change
|
|
3
|
+
* `2026-09-03-ios-focus-zoom-suppression`).
|
|
4
|
+
*
|
|
5
|
+
* iOS Safari auto-zooms the page (~115–120%) whenever ANY focusable control
|
|
6
|
+
* with a computed font-size below 16px receives focus; DSH's input surfaces
|
|
7
|
+
* are all 13–14px, so every focus on an iPhone trips it. Solution B (user
|
|
8
|
+
* ruling, 2026-09-03): rewrite the viewport meta early — appending
|
|
9
|
+
* `maximum-scale=1, user-scalable=no` — which suppresses the focus zoom on
|
|
10
|
+
* iOS 10+ WITHOUT disabling pinch zoom (Discourse PR #30877 empirics).
|
|
11
|
+
*
|
|
12
|
+
* v0.2.5 refinement (change `2026-09-03-zoomguard-standalone-font-floor`):
|
|
13
|
+
* that empiric holds only IN-BROWSER. Standalone (Add to Home Screen) iOS
|
|
14
|
+
* HONORS `user-scalable=no` — the meta rewrite kills pinch there, and the
|
|
15
|
+
* user's primary usage IS the PWA (real-device datum, 2026-09-03). The guard
|
|
16
|
+
* therefore forks by display mode: browser keeps the meta rewrite untouched;
|
|
17
|
+
* standalone never touches the meta at all and instead injects a 16px
|
|
18
|
+
* font-floor stylesheet (the font-size mechanism kills the focus zoom while
|
|
19
|
+
* pinch stays fully engine-available).
|
|
20
|
+
*
|
|
21
|
+
* The five exported predicates here are the entire decision surface:
|
|
22
|
+
* everything else (state machine, resize re-evaluation, stock-meta
|
|
23
|
+
* reconciliation) lives in the boot script section {@link buildZoomGuardSection}
|
|
24
|
+
* emits. That section embeds these functions via `Function.prototype.toString`
|
|
25
|
+
* — the unit-tested source IS the shipped source, byte for byte — which
|
|
26
|
+
* constrains their shape:
|
|
27
|
+
*
|
|
28
|
+
* - **ES5 syntax only** (the inline head script targets ancient parsers):
|
|
29
|
+
* `var`, function declarations, string concatenation; no arrows, no
|
|
30
|
+
* let/const, no template literals, no destructuring.
|
|
31
|
+
* - **Fully self-contained bodies**: no module-scope identifiers, no helper
|
|
32
|
+
* calls, no shared constants. A bundler may rename the declaration, but a
|
|
33
|
+
* renamed free reference would be a `ReferenceError` on the page. The
|
|
34
|
+
* eval-style tests in `test/web-trust.spec.ts` execute the real generated
|
|
35
|
+
* script against a stub DOM, so any such leak fails the suite.
|
|
36
|
+
*
|
|
37
|
+
* @module agent-omp/mobile/zoom-guard
|
|
38
|
+
*/
|
|
39
|
+
/** The two zoom tokens the guard merges into the stock viewport content. */
|
|
40
|
+
export declare const ZOOM_GUARD_TOKENS: Readonly<Record<string, string>>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a UA string + touch-capability pair is an iOS-class browser
|
|
43
|
+
* (design D2, mirroring Discourse `capabilities.isIOS`): iPhone/iPod/iPad,
|
|
44
|
+
* plus iPadOS 13+ desktop-Safari masquerade (`Macintosh` UA with a
|
|
45
|
+
* multi-touch digitizer). Deliberately NOT `pointer:coarse` — Android Chrome
|
|
46
|
+
* never focus-zooms and `maximum-scale` has historical side effects there,
|
|
47
|
+
* so the gate is tightened to the iOS family. UA-shape drift degrades
|
|
48
|
+
* benignly: a novel UA simply reads as non-iOS and no rewriting happens.
|
|
49
|
+
*
|
|
50
|
+
* @param ua - `navigator.userAgent`.
|
|
51
|
+
* @param maxTouchPoints - `navigator.maxTouchPoints` (0 when absent).
|
|
52
|
+
* @returns `true` for iOS-class browsers.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isIOSClassUA(ua: string, maxTouchPoints: number): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Token-level merge of viewport directives into a viewport meta `content`
|
|
57
|
+
* string (design D4): existing tokens keep their positions, a token whose key
|
|
58
|
+
* (compared case-insensitively) is in `tokens` is REPLACED by the configured
|
|
59
|
+
* key=value, and configured keys not present are APPENDED in insertion order.
|
|
60
|
+
* Idempotent by construction — merging always re-derives from the input, so
|
|
61
|
+
* repeated evaluation cannot accumulate duplicates.
|
|
62
|
+
*
|
|
63
|
+
* mergeViewportTokens('width=device-width, initial-scale=1', T)
|
|
64
|
+
* → 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'
|
|
65
|
+
* mergeViewportTokens('width=device-width, maximum-scale=5', T)
|
|
66
|
+
* → 'width=device-width, maximum-scale=1, user-scalable=no' // same-key override, position kept
|
|
67
|
+
*
|
|
68
|
+
* @param content - the stock (or stock-equivalent) content string.
|
|
69
|
+
* @param tokens - the directives to merge, keyed lowercase.
|
|
70
|
+
* @returns the merged content string.
|
|
71
|
+
*/
|
|
72
|
+
export declare function mergeViewportTokens(content: string, tokens: Record<string, string>): string;
|
|
73
|
+
/**
|
|
74
|
+
* The double gate (design D2/D3 + the `zoomGuard` config): rewrite applies
|
|
75
|
+
* only on an iOS-class browser AND a narrow viewport AND a non-`off`
|
|
76
|
+
* `zoomGuard`. An absent payload (or absent key) means the `'meta'` default —
|
|
77
|
+
* the same default-on posture as the mobile leg itself — so only an explicit
|
|
78
|
+
* `'off'` disarms the guard. Unknown non-`off` values read as `'meta'`
|
|
79
|
+
* (schema validation makes them unreachable in production; benign here).
|
|
80
|
+
*
|
|
81
|
+
* @param config - the `__AGENT_OMP_MOBILE__` payload (only `zoomGuard` is read).
|
|
82
|
+
* @param isIOS - {@link isIOSClassUA} verdict for this page load.
|
|
83
|
+
* @param isNarrow - `matchMedia('(max-width: breakpoint-0.02px)')` verdict.
|
|
84
|
+
* @returns `true` when the viewport rewrite should be applied.
|
|
85
|
+
*/
|
|
86
|
+
export declare function shouldApplyZoomGuard(config: {
|
|
87
|
+
zoomGuard?: string;
|
|
88
|
+
} | undefined, isIOS: boolean, isNarrow: boolean): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Standalone display-mode verdict (design D4 of change
|
|
91
|
+
* `2026-09-03-zoomguard-standalone-font-floor`): standalone PWAs HONOR
|
|
92
|
+
* `user-scalable=no` (the real-device pinch regression that motivated the
|
|
93
|
+
* display-mode split), so they must never enter the meta-rewrite path. Two
|
|
94
|
+
* sources, strict-`true` OR: the `(display-mode: standalone)` media query
|
|
95
|
+
* (primary) and legacy `navigator.standalone` (older iOS Safari exposes only
|
|
96
|
+
* the latter). Anything else — `undefined` (engine without the source),
|
|
97
|
+
* `false`, or truthy junk — reads as NOT standalone.
|
|
98
|
+
*
|
|
99
|
+
* @param mqMatchesStandalone - `matchMedia('(display-mode: standalone)').matches`.
|
|
100
|
+
* @param navStandalone - `navigator.standalone === true`.
|
|
101
|
+
* @returns `true` in standalone display mode (either source).
|
|
102
|
+
*/
|
|
103
|
+
export declare function isStandaloneDisplay(mqMatchesStandalone: boolean | undefined, navStandalone: boolean | undefined): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* The 16px font floor stylesheet (design D3): iOS auto-zooms on focus into
|
|
106
|
+
* ANY control whose computed font-size is below 16px, so in standalone mode
|
|
107
|
+
* — where the meta rewrite is off the table (pinch must stay
|
|
108
|
+
* engine-available) — the floor IS the suppression. Scoped by the same
|
|
109
|
+
* breakpoint band the meta leg uses and derived the same way
|
|
110
|
+
* (`breakpoint - 0.02`: 768 → 767.98, 900 → 899.98); `!important` beats the
|
|
111
|
+
* 13/14px CSS module rules and the body inline var chain;
|
|
112
|
+
* `[contenteditable="true"]` matches only the editable state (React
|
|
113
|
+
* serializes `contentEditable={bool}` to the literal attribute value
|
|
114
|
+
* "true"/"false").
|
|
115
|
+
*
|
|
116
|
+
* @param breakpointPx - the configured `mobile.breakpoint` (raw — this
|
|
117
|
+
* function derives the `-0.02` band itself, do NOT pre-subtract).
|
|
118
|
+
* @returns the complete stylesheet text.
|
|
119
|
+
*/
|
|
120
|
+
export declare function buildFontFloorCss(breakpointPx: number): string;
|
|
121
|
+
/**
|
|
122
|
+
* Build the boot script's zoomGuard section: the five decision predicates
|
|
123
|
+
* embedded via `toString()` plus the DOM state machine that applies them.
|
|
124
|
+
* The machine implements design D3/D4 with one discovered refinement —
|
|
125
|
+
*
|
|
126
|
+
* **The standalone fork (2026-09-03, change
|
|
127
|
+
* `2026-09-03-zoomguard-standalone-font-floor`).** Real-device datum:
|
|
128
|
+
* standalone (Add to Home Screen) iOS HONORS `user-scalable=no`, so the
|
|
129
|
+
* meta rewrite that is benign in-browser (pinch stays engine-controlled)
|
|
130
|
+
* kills pinch in the PWA — the user's primary surface. The section
|
|
131
|
+
* therefore forks right after the iOS gate, BEFORE any meta machinery: a
|
|
132
|
+
* one-shot startup verdict (display-mode never flips mid-session) via the
|
|
133
|
+
* `(display-mode: standalone)` MQ or legacy `navigator.standalone` (D4).
|
|
134
|
+
* Standalone → inject the `ios-zoom-font-floor` style element into the
|
|
135
|
+
* head (16px floor, media-query-scoped to the same breakpoint band, D3)
|
|
136
|
+
* and RETURN — no provisional meta, no reconcile observer, no ladder
|
|
137
|
+
* timer, no listeners, byte-identical stock meta (D1). The width dimension
|
|
138
|
+
* lives inside the stylesheet's media query, so the injection itself is
|
|
139
|
+
* NOT width-gated: a wide standalone load still gets the element; the rule
|
|
140
|
+
* simply does not match above the breakpoint. Browser mode runs the v0.2.4
|
|
141
|
+
* machinery unchanged.
|
|
142
|
+
* **Why reconciliation exists.** The webserver splices head injections
|
|
143
|
+
* immediately after the opening `<head>` tag, i.e. BEFORE the stock
|
|
144
|
+
* `<meta name="viewport">` in upstream's `index.html`. At boot-script time
|
|
145
|
+
* the stock meta is therefore NOT yet parsed, so the "meta missing"
|
|
146
|
+
* branch is the NORMAL path on the served shell, not an edge case. A
|
|
147
|
+
* provisional meta is created right away (the timing requirement: the
|
|
148
|
+
* suppressive tokens are live before any application bundle can focus an
|
|
149
|
+
* input), and a MutationObserver watches for the parser to insert the stock
|
|
150
|
+
* meta; the moment it appears, the guard records the true stock content,
|
|
151
|
+
* rewrites the STOCK meta (token merge, D4's actual semantics — restore
|
|
152
|
+
* later writes these exact bytes back), and removes the provisional one —
|
|
153
|
+
* leaving a single-meta document instead of relying on engines'
|
|
154
|
+
* unspecified multi-meta merge behavior. Engines without MutationObserver
|
|
155
|
+
* keep the provisional meta for the page's lifetime (degraded but still
|
|
156
|
+
* suppressive); the observer is never started once the stock meta was
|
|
157
|
+
* found synchronously.
|
|
158
|
+
*
|
|
159
|
+
* **Why the re-evaluation ladder exists (2026-09-03 rework, lead CDP
|
|
160
|
+
* finding on the 4999 instance).** The boot script runs during head parsing,
|
|
161
|
+
* BEFORE the engine applies the stock viewport meta — the layout viewport at
|
|
162
|
+
* first evaluation is the pre-meta engine default (980px observed), so
|
|
163
|
+
* `mq.matches` reads false on an initial narrow load, and the narrowing that
|
|
164
|
+
* follows meta application does NOT reliably dispatch `resize` to the page
|
|
165
|
+
* during load (headless Chrome: never). A ~10ms poll ladder therefore
|
|
166
|
+
* re-evaluates until the guard IS applied, `document.readyState` reaches
|
|
167
|
+
* `'complete'`, or ~2s elapse — the first layout always precedes deferred
|
|
168
|
+
* scripts, so the ladder lands the guard before any application bundle can
|
|
169
|
+
* focus an input. Steady-state ticks are idempotent no-ops; a wide load
|
|
170
|
+
* idles to the readyState stop and leaves no timer behind (a pending tick
|
|
171
|
+
* is also cancelled the moment the guard lands). MediaQuery `change` events
|
|
172
|
+
* (with the legacy `addListener` fallback) form a second re-evaluation
|
|
173
|
+
* channel alongside window `resize`.
|
|
174
|
+
*
|
|
175
|
+
* State machine (ES5, zero dependencies, synchronous first evaluation):
|
|
176
|
+
* `meta` is the element under management (provisional or reconciled stock),
|
|
177
|
+
* `stock` its recorded stock content, `mine` whether we created it,
|
|
178
|
+
* `applied` the last applied gate verdict. `apply(on)` is idempotent per
|
|
179
|
+
* state (no-op when the verdict is unchanged); merges always re-derive
|
|
180
|
+
* from the recorded stock, never from the live content, so resize storms
|
|
181
|
+
* cannot accumulate tokens. Non-iOS pages never wire any listener.
|
|
182
|
+
*
|
|
183
|
+
* Emitted only when the mobile payload exists and `zoomGuard !== 'off'`.
|
|
184
|
+
*
|
|
185
|
+
* @returns the inline section text (truthy `var` declarations + IIFE).
|
|
186
|
+
*/
|
|
187
|
+
export declare function buildZoomGuardSection(): string;
|