super-dsh 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +25 -3
  2. package/agent-agy/cordis.patch.yml +7 -4
  3. package/agent-agy/dist/agent.d.ts +12 -11
  4. package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
  5. package/agent-agy/dist/agy-auth-gateway.js +233 -0
  6. package/agent-agy/dist/agy-auth.d.ts +153 -0
  7. package/agent-agy/dist/agy-auth.js +179 -0
  8. package/agent-agy/dist/agy-cli-client.d.ts +39 -9
  9. package/agent-agy/dist/agy-cli-client.js +82 -18
  10. package/agent-agy/dist/agy-store.d.ts +8 -0
  11. package/agent-agy/dist/index.d.ts +46 -16
  12. package/agent-agy/dist/index.js +82 -56
  13. package/agent-agy/dist/models.d.ts +70 -0
  14. package/agent-agy/dist/models.js +102 -3
  15. package/agent-agy/package.json +7 -5
  16. package/agent-agy-sdk/cordis.patch.yml +58 -0
  17. package/agent-agy-sdk/dist/adapter.d.ts +15 -0
  18. package/agent-agy-sdk/dist/adapter.js +42 -0
  19. package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
  20. package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
  21. package/agent-agy-sdk/dist/agent.d.ts +138 -0
  22. package/agent-agy-sdk/dist/agent.js +494 -0
  23. package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
  24. package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
  25. package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
  26. package/agent-agy-sdk/dist/agy-sessions.js +107 -0
  27. package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
  28. package/agent-agy-sdk/dist/agy-store.js +83 -0
  29. package/agent-agy-sdk/dist/inbox.d.ts +26 -0
  30. package/agent-agy-sdk/dist/inbox.js +53 -0
  31. package/agent-agy-sdk/dist/index.d.ts +93 -0
  32. package/agent-agy-sdk/dist/index.js +476 -0
  33. package/agent-agy-sdk/dist/models.d.ts +41 -0
  34. package/agent-agy-sdk/dist/models.js +74 -0
  35. package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
  36. package/agent-agy-sdk/dist/sdk-venv.js +173 -0
  37. package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
  38. package/agent-agy-sdk/dist/world-plugin.js +82 -0
  39. package/agent-agy-sdk/package.json +64 -0
  40. package/agent-codex/README.md +141 -36
  41. package/agent-codex/cordis.patch.yml +14 -10
  42. package/agent-codex/dist/adapter.js +64 -28
  43. package/agent-codex/dist/agent.js +255 -81
  44. package/agent-codex/dist/app-server-approvals.js +165 -0
  45. package/agent-codex/dist/app-server-client.js +723 -0
  46. package/agent-codex/dist/app-server-events.js +432 -0
  47. package/agent-codex/dist/app-server-protocol.js +95 -0
  48. package/agent-codex/dist/app-server-wire.js +299 -0
  49. package/agent-codex/dist/codex-launch.js +78 -0
  50. package/agent-codex/dist/codex-native-config.js +392 -0
  51. package/agent-codex/dist/codex-provider-gateway.js +402 -0
  52. package/agent-codex/dist/codex-providers.js +376 -0
  53. package/agent-codex/dist/codex-route.js +86 -0
  54. package/agent-codex/dist/index.js +256 -115
  55. package/agent-codex/dist/permission.js +75 -1
  56. package/agent-codex/package.json +1 -2
  57. package/agent-codex-sdk/README.md +79 -0
  58. package/agent-codex-sdk/cordis.patch.yml +81 -0
  59. package/agent-codex-sdk/dist/adapter.js +91 -0
  60. package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
  61. package/agent-codex-sdk/dist/agent.js +1085 -0
  62. package/agent-codex-sdk/dist/codex-native-config.js +392 -0
  63. package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
  64. package/agent-codex-sdk/dist/codex-providers.js +376 -0
  65. package/agent-codex-sdk/dist/codex-route.js +86 -0
  66. package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
  67. package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
  68. package/agent-codex-sdk/dist/codex-store.js +180 -0
  69. package/agent-codex-sdk/dist/inbox.js +53 -0
  70. package/agent-codex-sdk/dist/index.js +739 -0
  71. package/agent-codex-sdk/dist/permission.js +71 -0
  72. package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
  73. package/agent-codex-sdk/dist/session-map.js +167 -0
  74. package/agent-codex-sdk/dist/world-plugin.js +93 -0
  75. package/agent-codex-sdk/package.json +79 -0
  76. package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
  77. package/agent-omp/README.md +72 -55
  78. package/agent-omp/dist/agent.js +36 -11
  79. package/agent-omp/dist/index.js +92 -52
  80. package/agent-omp/dist/lazy-rpc.js +11 -4
  81. package/agent-omp/dist/omp-cli.js +114 -97
  82. package/agent-omp/dist/omp-store.js +12 -4
  83. package/agent-omp/dist/permission.js +70 -5
  84. package/agent-omp/dist/rpc-client.js +409 -0
  85. package/agent-omp/dist/world-plugin.js +36 -3
  86. package/agent-omp/package.json +2 -6
  87. package/agent-omp-sdk/README.md +103 -0
  88. package/agent-omp-sdk/cordis.patch.yml +108 -0
  89. package/agent-omp-sdk/dist/adapter.d.ts +21 -0
  90. package/agent-omp-sdk/dist/adapter.js +36 -0
  91. package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
  92. package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
  93. package/agent-omp-sdk/dist/agent.d.ts +64 -0
  94. package/agent-omp-sdk/dist/agent.js +1178 -0
  95. package/agent-omp-sdk/dist/discovery.d.ts +57 -0
  96. package/agent-omp-sdk/dist/discovery.js +116 -0
  97. package/agent-omp-sdk/dist/inbox.d.ts +28 -0
  98. package/agent-omp-sdk/dist/inbox.js +53 -0
  99. package/agent-omp-sdk/dist/index.d.ts +60 -0
  100. package/agent-omp-sdk/dist/index.js +632 -0
  101. package/agent-omp-sdk/dist/knobs.d.ts +34 -0
  102. package/agent-omp-sdk/dist/knobs.js +50 -0
  103. package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
  104. package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
  105. package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
  106. package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
  107. package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
  108. package/agent-omp-sdk/dist/mobile-boot.js +38 -0
  109. package/agent-omp-sdk/dist/models.d.ts +39 -0
  110. package/agent-omp-sdk/dist/models.js +299 -0
  111. package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
  112. package/agent-omp-sdk/dist/omp-cli.js +164 -0
  113. package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
  114. package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
  115. package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
  116. package/agent-omp-sdk/dist/omp-executable.js +30 -0
  117. package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
  118. package/agent-omp-sdk/dist/omp-store.js +526 -0
  119. package/agent-omp-sdk/dist/pairing.d.ts +7 -0
  120. package/agent-omp-sdk/dist/pairing.js +45 -0
  121. package/agent-omp-sdk/dist/permission.d.ts +138 -0
  122. package/agent-omp-sdk/dist/permission.js +161 -0
  123. package/agent-omp-sdk/dist/protocol.d.ts +189 -0
  124. package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
  125. package/agent-omp-sdk/dist/rpc-types.js +1 -0
  126. package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
  127. package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
  128. package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
  129. package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
  130. package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
  131. package/agent-omp-sdk/dist/sidecar-client.js +197 -0
  132. package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
  133. package/agent-omp-sdk/dist/store/adapter.js +47 -0
  134. package/agent-omp-sdk/dist/store/db.d.ts +70 -0
  135. package/agent-omp-sdk/dist/store/db.js +210 -0
  136. package/agent-omp-sdk/dist/store/index.d.ts +23 -0
  137. package/agent-omp-sdk/dist/store/index.js +59 -0
  138. package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
  139. package/agent-omp-sdk/dist/store/reconcile.js +51 -0
  140. package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
  141. package/agent-omp-sdk/dist/store/schema.js +40 -0
  142. package/agent-omp-sdk/dist/transport.d.ts +49 -0
  143. package/agent-omp-sdk/dist/transport.js +35 -0
  144. package/agent-omp-sdk/dist/world-home.d.ts +4 -0
  145. package/agent-omp-sdk/dist/world-home.js +23 -0
  146. package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
  147. package/agent-omp-sdk/dist/world-plugin.js +137 -0
  148. package/agent-omp-sdk/package.json +87 -0
  149. package/client/index.js +1115 -93
  150. package/cordis.patch.yml +64 -0
  151. package/package.json +17 -7
  152. package/superd-hub/dist/client/agent-settings.d.ts +156 -0
  153. package/superd-hub/dist/client/agent-settings.js +229 -0
  154. package/superd-hub/dist/client/roster.js +6 -0
  155. package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
  156. package/superd-hub/dist/client/runtime-settings-api.js +137 -0
  157. package/superd-hub/dist/client/switch.d.ts +165 -0
  158. package/superd-hub/dist/client/switch.js +295 -0
  159. package/superd-hub/lib/client/index.js +1115 -93
  160. package/agent-codex/dist/models.js +0 -152
  161. package/agent-omp/dist/sidecar-client.js +0 -195
  162. /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
  163. /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
  164. /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
  165. /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
  166. /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
@@ -0,0 +1,294 @@
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 const ZOOM_GUARD_TOKENS = {
41
+ 'maximum-scale': '1',
42
+ 'user-scalable': 'no',
43
+ };
44
+ /**
45
+ * Whether a UA string + touch-capability pair is an iOS-class browser
46
+ * (design D2, mirroring Discourse `capabilities.isIOS`): iPhone/iPod/iPad,
47
+ * plus iPadOS 13+ desktop-Safari masquerade (`Macintosh` UA with a
48
+ * multi-touch digitizer). Deliberately NOT `pointer:coarse` — Android Chrome
49
+ * never focus-zooms and `maximum-scale` has historical side effects there,
50
+ * so the gate is tightened to the iOS family. UA-shape drift degrades
51
+ * benignly: a novel UA simply reads as non-iOS and no rewriting happens.
52
+ *
53
+ * @param ua - `navigator.userAgent`.
54
+ * @param maxTouchPoints - `navigator.maxTouchPoints` (0 when absent).
55
+ * @returns `true` for iOS-class browsers.
56
+ */
57
+ export function isIOSClassUA(ua, maxTouchPoints) {
58
+ return /iPhone|iPod|iPad/.test(ua) || (/Macintosh/.test(ua) && maxTouchPoints > 1);
59
+ }
60
+ /**
61
+ * Token-level merge of viewport directives into a viewport meta `content`
62
+ * string (design D4): existing tokens keep their positions, a token whose key
63
+ * (compared case-insensitively) is in `tokens` is REPLACED by the configured
64
+ * key=value, and configured keys not present are APPENDED in insertion order.
65
+ * Idempotent by construction — merging always re-derives from the input, so
66
+ * repeated evaluation cannot accumulate duplicates.
67
+ *
68
+ * mergeViewportTokens('width=device-width, initial-scale=1', T)
69
+ * → 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'
70
+ * mergeViewportTokens('width=device-width, maximum-scale=5', T)
71
+ * → 'width=device-width, maximum-scale=1, user-scalable=no' // same-key override, position kept
72
+ *
73
+ * @param content - the stock (or stock-equivalent) content string.
74
+ * @param tokens - the directives to merge, keyed lowercase.
75
+ * @returns the merged content string.
76
+ */
77
+ export function mergeViewportTokens(content, tokens) {
78
+ var out = [];
79
+ var seen = {};
80
+ var parts = content.split(',');
81
+ for (var i = 0; i < parts.length; i++) {
82
+ var part = parts[i];
83
+ var raw = (part === undefined ? '' : part).replace(/^\s+|\s+$/g, '');
84
+ if (raw === '')
85
+ continue;
86
+ var eq = raw.indexOf('=');
87
+ var key = eq < 0 ? raw : raw.slice(0, eq).replace(/^\s+|\s+$/g, '');
88
+ var hit = null;
89
+ for (var k in tokens) {
90
+ if (tokens.hasOwnProperty(k) && k.toLowerCase() === key.toLowerCase()) {
91
+ hit = k;
92
+ break;
93
+ }
94
+ }
95
+ if (hit === null) {
96
+ out[out.length] = raw;
97
+ continue;
98
+ }
99
+ out[out.length] = hit + '=' + tokens[hit];
100
+ seen[hit] = true;
101
+ }
102
+ for (var j in tokens) {
103
+ if (tokens.hasOwnProperty(j) && !seen[j])
104
+ out[out.length] = j + '=' + tokens[j];
105
+ }
106
+ return out.join(', ');
107
+ }
108
+ /**
109
+ * The double gate (design D2/D3 + the `zoomGuard` config): rewrite applies
110
+ * only on an iOS-class browser AND a narrow viewport AND a non-`off`
111
+ * `zoomGuard`. An absent payload (or absent key) means the `'meta'` default —
112
+ * the same default-on posture as the mobile leg itself — so only an explicit
113
+ * `'off'` disarms the guard. Unknown non-`off` values read as `'meta'`
114
+ * (schema validation makes them unreachable in production; benign here).
115
+ *
116
+ * @param config - the `__AGENT_OMP_MOBILE__` payload (only `zoomGuard` is read).
117
+ * @param isIOS - {@link isIOSClassUA} verdict for this page load.
118
+ * @param isNarrow - `matchMedia('(max-width: breakpoint-0.02px)')` verdict.
119
+ * @returns `true` when the viewport rewrite should be applied.
120
+ */
121
+ export function shouldApplyZoomGuard(config, isIOS, isNarrow) {
122
+ if (!isIOS || !isNarrow)
123
+ return false;
124
+ if (!config)
125
+ return true;
126
+ return config.zoomGuard !== 'off';
127
+ }
128
+ /**
129
+ * Standalone display-mode verdict (design D4 of change
130
+ * `2026-09-03-zoomguard-standalone-font-floor`): standalone PWAs HONOR
131
+ * `user-scalable=no` (the real-device pinch regression that motivated the
132
+ * display-mode split), so they must never enter the meta-rewrite path. Two
133
+ * sources, strict-`true` OR: the `(display-mode: standalone)` media query
134
+ * (primary) and legacy `navigator.standalone` (older iOS Safari exposes only
135
+ * the latter). Anything else — `undefined` (engine without the source),
136
+ * `false`, or truthy junk — reads as NOT standalone.
137
+ *
138
+ * @param mqMatchesStandalone - `matchMedia('(display-mode: standalone)').matches`.
139
+ * @param navStandalone - `navigator.standalone === true`.
140
+ * @returns `true` in standalone display mode (either source).
141
+ */
142
+ export function isStandaloneDisplay(mqMatchesStandalone, navStandalone) {
143
+ return mqMatchesStandalone === true || navStandalone === true;
144
+ }
145
+ /**
146
+ * The 16px font floor stylesheet (design D3): iOS auto-zooms on focus into
147
+ * ANY control whose computed font-size is below 16px, so in standalone mode
148
+ * — where the meta rewrite is off the table (pinch must stay
149
+ * engine-available) — the floor IS the suppression. Scoped by the same
150
+ * breakpoint band the meta leg uses and derived the same way
151
+ * (`breakpoint - 0.02`: 768 → 767.98, 900 → 899.98); `!important` beats the
152
+ * 13/14px CSS module rules and the body inline var chain;
153
+ * `[contenteditable="true"]` matches only the editable state (React
154
+ * serializes `contentEditable={bool}` to the literal attribute value
155
+ * "true"/"false").
156
+ *
157
+ * @param breakpointPx - the configured `mobile.breakpoint` (raw — this
158
+ * function derives the `-0.02` band itself, do NOT pre-subtract).
159
+ * @returns the complete stylesheet text.
160
+ */
161
+ export function buildFontFloorCss(breakpointPx) {
162
+ var bp = breakpointPx - 0.02;
163
+ return '@media (max-width:' + bp + 'px){ input,textarea,select,[contenteditable="true"]{ font-size:16px !important } }';
164
+ }
165
+ /**
166
+ * Build the boot script's zoomGuard section: the five decision predicates
167
+ * embedded via `toString()` plus the DOM state machine that applies them.
168
+ * The machine implements design D3/D4 with one discovered refinement —
169
+ *
170
+ * **The standalone fork (2026-09-03, change
171
+ * `2026-09-03-zoomguard-standalone-font-floor`).** Real-device datum:
172
+ * standalone (Add to Home Screen) iOS HONORS `user-scalable=no`, so the
173
+ * meta rewrite that is benign in-browser (pinch stays engine-controlled)
174
+ * kills pinch in the PWA — the user's primary surface. The section
175
+ * therefore forks right after the iOS gate, BEFORE any meta machinery: a
176
+ * one-shot startup verdict (display-mode never flips mid-session) via the
177
+ * `(display-mode: standalone)` MQ or legacy `navigator.standalone` (D4).
178
+ * Standalone → inject the `ios-zoom-font-floor` style element into the
179
+ * head (16px floor, media-query-scoped to the same breakpoint band, D3)
180
+ * and RETURN — no provisional meta, no reconcile observer, no ladder
181
+ * timer, no listeners, byte-identical stock meta (D1). The width dimension
182
+ * lives inside the stylesheet's media query, so the injection itself is
183
+ * NOT width-gated: a wide standalone load still gets the element; the rule
184
+ * simply does not match above the breakpoint. Browser mode runs the v0.2.4
185
+ * machinery unchanged.
186
+ * **Why reconciliation exists.** The webserver splices head injections
187
+ * immediately after the opening `<head>` tag, i.e. BEFORE the stock
188
+ * `<meta name="viewport">` in upstream's `index.html`. At boot-script time
189
+ * the stock meta is therefore NOT yet parsed, so the "meta missing"
190
+ * branch is the NORMAL path on the served shell, not an edge case. A
191
+ * provisional meta is created right away (the timing requirement: the
192
+ * suppressive tokens are live before any application bundle can focus an
193
+ * input), and a MutationObserver watches for the parser to insert the stock
194
+ * meta; the moment it appears, the guard records the true stock content,
195
+ * rewrites the STOCK meta (token merge, D4's actual semantics — restore
196
+ * later writes these exact bytes back), and removes the provisional one —
197
+ * leaving a single-meta document instead of relying on engines'
198
+ * unspecified multi-meta merge behavior. Engines without MutationObserver
199
+ * keep the provisional meta for the page's lifetime (degraded but still
200
+ * suppressive); the observer is never started once the stock meta was
201
+ * found synchronously.
202
+ *
203
+ * **Why the re-evaluation ladder exists (2026-09-03 rework, lead CDP
204
+ * finding on the 4999 instance).** The boot script runs during head parsing,
205
+ * BEFORE the engine applies the stock viewport meta — the layout viewport at
206
+ * first evaluation is the pre-meta engine default (980px observed), so
207
+ * `mq.matches` reads false on an initial narrow load, and the narrowing that
208
+ * follows meta application does NOT reliably dispatch `resize` to the page
209
+ * during load (headless Chrome: never). A ~10ms poll ladder therefore
210
+ * re-evaluates until the guard IS applied, `document.readyState` reaches
211
+ * `'complete'`, or ~2s elapse — the first layout always precedes deferred
212
+ * scripts, so the ladder lands the guard before any application bundle can
213
+ * focus an input. Steady-state ticks are idempotent no-ops; a wide load
214
+ * idles to the readyState stop and leaves no timer behind (a pending tick
215
+ * is also cancelled the moment the guard lands). MediaQuery `change` events
216
+ * (with the legacy `addListener` fallback) form a second re-evaluation
217
+ * channel alongside window `resize`.
218
+ *
219
+ * State machine (ES5, zero dependencies, synchronous first evaluation):
220
+ * `meta` is the element under management (provisional or reconciled stock),
221
+ * `stock` its recorded stock content, `mine` whether we created it,
222
+ * `applied` the last applied gate verdict. `apply(on)` is idempotent per
223
+ * state (no-op when the verdict is unchanged); merges always re-derive
224
+ * from the recorded stock, never from the live content, so resize storms
225
+ * cannot accumulate tokens. Non-iOS pages never wire any listener.
226
+ *
227
+ * Emitted only when the mobile payload exists and `zoomGuard !== 'off'`.
228
+ *
229
+ * @returns the inline section text (truthy `var` declarations + IIFE).
230
+ */
231
+ export function buildZoomGuardSection() {
232
+ return [
233
+ `var ZI=${isIOSClassUA.toString()};`,
234
+ `var ZM=${mergeViewportTokens.toString()};`,
235
+ `var ZS=${shouldApplyZoomGuard.toString()};`,
236
+ `var ZD=${isStandaloneDisplay.toString()};`,
237
+ `var ZF=${buildFontFloorCss.toString()};`,
238
+ '(function(){',
239
+ 'var m=window.__AGENT_OMP_MOBILE__;',
240
+ 'var ios=ZI(navigator.userAgent,(navigator.maxTouchPoints||0));',
241
+ 'if(!ios)return;',
242
+ "var bpx=(m&&typeof m.breakpoint==='number'&&m.breakpoint>0)?m.breakpoint:768;",
243
+ 'var bp=bpx-0.02;',
244
+ "var sa=ZD((window.matchMedia&&window.matchMedia('(display-mode: standalone)').matches),(navigator.standalone===true));",
245
+ "if(sa){var f=document.createElement('style');f.setAttribute('id','ios-zoom-font-floor');f.setAttribute('data-plugin','agent-omp');f.setAttribute('data-plugin-css','agent-omp/zoom-font-floor');f.textContent=ZF(bpx);headEl().appendChild(f);return}",
246
+ "var mq=(typeof window.matchMedia==='function')?window.matchMedia('(max-width:'+bp+'px)'):null;",
247
+ "var T={'maximum-scale':'1','user-scalable':'no'};",
248
+ 'var meta=null,stock=null,mine=false,applied=false,obs=null,lad=null,lN=0;',
249
+ "function findStock(){var s=document.getElementsByTagName('meta');for(var i=0;i<s.length;i++){var e=s[i];if(e!==meta&&(e.getAttribute('name')||'').toLowerCase()==='viewport')return e}return null}",
250
+ "function headEl(){return document.head||document.getElementsByTagName('head')[0]||document.documentElement}",
251
+ 'function stopWatch(){if(obs){obs.disconnect();obs=null}}',
252
+ 'function stopLadder(){if(lad){clearTimeout(lad);lad=null}}',
253
+ "function dropMine(){if(meta&&mine){if(meta.parentNode)meta.parentNode.removeChild(meta);meta=null;mine=false}}",
254
+ 'function apply(on){',
255
+ 'if(on===applied)return;',
256
+ 'applied=on;',
257
+ 'if(on)stopLadder();',
258
+ 'if(on){',
259
+ 'var el=findStock();',
260
+ "if(el){meta=el;mine=false;stock=el.getAttribute('content')||''}",
261
+ "else if(!meta){meta=document.createElement('meta');meta.setAttribute('name','viewport');mine=true;stock='';headEl().appendChild(meta)}",
262
+ "meta.setAttribute('content',ZM(stock,T));",
263
+ "if(mine&&typeof MutationObserver==='function'&&!obs){obs=new MutationObserver(check);obs.observe(document.documentElement,{childList:true,subtree:true})}",
264
+ '}else{',
265
+ 'stopWatch();',
266
+ 'if(!meta)return;',
267
+ 'if(mine)dropMine();',
268
+ "else meta.setAttribute('content',stock);", // restore = exact stock bytes (D4)
269
+ '}',
270
+ '}',
271
+ 'function check(){',
272
+ 'var el=findStock();',
273
+ 'if(!el)return;',
274
+ 'stopWatch();',
275
+ "stock=el.getAttribute('content')||'';",
276
+ "if(applied){dropMine();meta=el;mine=false;meta.setAttribute('content',ZM(stock,T))}",
277
+ 'else{dropMine();meta=null;stock=null}',
278
+ '}',
279
+ 'function re(){apply(ZS(m,true,mq?mq.matches:false))}',
280
+ 'function tick(){',
281
+ 'lad=null;',
282
+ 're();',
283
+ 'if(applied)return;',
284
+ 'lN++;',
285
+ "if(document.readyState==='complete'||lN>=200)return;",
286
+ 'lad=setTimeout(tick,10);',
287
+ '}',
288
+ 're();',
289
+ "window.addEventListener('resize',re);",
290
+ "if(mq&&mq.addEventListener)mq.addEventListener('change',re);else if(mq&&mq.addListener)mq.addListener(re);",
291
+ "if(!applied&&typeof setTimeout==='function')lad=setTimeout(tick,10);",
292
+ '})()',
293
+ ].join('');
294
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Mobile page-config boot script (host half of the mobile feature). Delivered
3
+ * as ONE inline `<head>` script through the webserver's public
4
+ * `webserver/index-inject` event (every index render re-emits; row data is
5
+ * read fresh at emit time).
6
+ *
7
+ * The script sets `window.__AGENT_OMP_MOBILE__` — the dual-half plugin's client
8
+ * half carries no loader config, so the page global IS the config channel —
9
+ * then appends the iOS focus auto-zoom suppression section
10
+ * ({@link buildZoomGuardSection}). Both legs ship default-ON; there is no
11
+ * config schema (constants only), so a bare page still carries the mobile
12
+ * global plus the zoom-guard section.
13
+ *
14
+ * Fail-open: an injection failure is logged and the host keeps booting — the
15
+ * mobile feature is additive and must never block the web composition. A
16
+ * composition without a `webServer` service leaves the feature dormant
17
+ * (the `ctx.inject` callback never fires).
18
+ *
19
+ * @module agent-omp/mobile-boot
20
+ */
21
+ import type { Context } from '@deepseek-ai/cordis';
22
+ /** The `webserver/index-inject` row shape this feature pushes. */
23
+ export interface BootScriptRow {
24
+ kind: 'script';
25
+ placement: 'head';
26
+ text: string;
27
+ }
28
+ declare module '@deepseek-ai/cordis' {
29
+ interface Events {
30
+ 'webserver/index-inject'(table: BootScriptRow[]): void;
31
+ }
32
+ }
33
+ /**
34
+ * Build the boot script text. Pure: same constants in, same script out — the
35
+ * unit tests pin the shape (mobile global present, zoom-guard section present,
36
+ * wrapped in a non-throwing IIFE).
37
+ *
38
+ * @returns the script text.
39
+ */
40
+ export declare function buildMobileBootScript(): string;
41
+ /**
42
+ * Mount the boot-script injection: one `webserver/index-inject` listener
43
+ * pushing the rendered row. Conditional on the webServer service, so the
44
+ * plugin loads (with the feature dormant) in compositions without one.
45
+ * Fail-open: a push failure is logged, never thrown.
46
+ *
47
+ * @param ctx - host plugin context.
48
+ */
49
+ export declare function installMobileBootScript(ctx: Context): void;
@@ -0,0 +1,38 @@
1
+ import { buildZoomGuardSection } from './mobile/zoom-guard.js';
2
+ /**
3
+ * Build the boot script text. Pure: same constants in, same script out — the
4
+ * unit tests pin the shape (mobile global present, zoom-guard section present,
5
+ * wrapped in a non-throwing IIFE).
6
+ *
7
+ * @returns the script text.
8
+ */
9
+ export function buildMobileBootScript() {
10
+ const parts = ['(function(){try{'];
11
+ // Ship default ON: a bare page carries the mobile global (the client's
12
+ // `resolveMobileConfig` merges the threshold defaults over `enabled: true`).
13
+ parts.push(`window.__AGENT_OMP_MOBILE__=${JSON.stringify({ enabled: true })};`);
14
+ // The zoom guard rides the mobile leg (default 'meta' mode): emitted always.
15
+ parts.push(buildZoomGuardSection());
16
+ parts.push('}catch(e){}})();');
17
+ return parts.join('');
18
+ }
19
+ /**
20
+ * Mount the boot-script injection: one `webserver/index-inject` listener
21
+ * pushing the rendered row. Conditional on the webServer service, so the
22
+ * plugin loads (with the feature dormant) in compositions without one.
23
+ * Fail-open: a push failure is logged, never thrown.
24
+ *
25
+ * @param ctx - host plugin context.
26
+ */
27
+ export function installMobileBootScript(ctx) {
28
+ ctx.inject(['webServer'], () => {
29
+ ctx.on('webserver/index-inject', (table) => {
30
+ try {
31
+ table.push({ kind: 'script', placement: 'head', text: buildMobileBootScript() });
32
+ }
33
+ catch (error) {
34
+ ctx.logger.warn(`agent-omp: mobile boot script injection failed: ${String(error)}`);
35
+ }
36
+ });
37
+ });
38
+ }
@@ -0,0 +1,39 @@
1
+ import { type LlmModelInfo, type LlmResolvedModelInfo } from "@deepseek-ai/dsh-llm";
2
+ /** One model as OMP's registry describes it (`get_available_models` / model_cache / models.yml). */
3
+ export interface OmpModel {
4
+ id: string;
5
+ name: string;
6
+ provider: string;
7
+ api?: string;
8
+ baseUrl?: string;
9
+ reasoning?: boolean;
10
+ input?: string[];
11
+ contextWindow?: number | null;
12
+ maxTokens?: number | null;
13
+ thinking?: {
14
+ mode?: string;
15
+ efforts?: string[];
16
+ defaultLevel?: string;
17
+ };
18
+ }
19
+ /**
20
+ * Read the AVAILABLE OMP model catalog, memoized. First call prefers the CLI
21
+ * (`omp models --json`, synchronous — the boot route list must be known
22
+ * before `registerAdapter` returns); a CLI failure falls back to the on-disk
23
+ * registry cache with a stderr note. Later refreshes go through
24
+ * `refreshOmpModelsCli` (async, per reconcile tick).
25
+ */
26
+ export declare function loadOmpModels(): OmpModel[];
27
+ /**
28
+ * Re-run the CLI catalog and swap the memo on success.
29
+ * @returns whether the refresh produced a fresh catalog.
30
+ */
31
+ export declare function refreshOmpModelsCli(): Promise<boolean>;
32
+ /** The distinct provider ids across the catalog, modelRoles roles first. */
33
+ export declare function ompProviderIds(models?: OmpModel[]): string[];
34
+ /** Human-readable provider name for `LlmProviderInfo.name`. */
35
+ export declare function providerDisplayName(provider: string): string;
36
+ /** One catalog row: {@link LlmModelInfo} for `listModels`. */
37
+ export declare function toModelInfo(model: OmpModel): LlmModelInfo;
38
+ /** One exact-model resolution: {@link LlmResolvedModelInfo} for `resolveModel`. */
39
+ export declare function toResolvedModelInfo(model: OmpModel): LlmResolvedModelInfo;