@bitkyc08/opencodex 2.10.2 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/bin/ocx.mjs +10 -0
- package/gui/dist/assets/index-Bk-PN-70.css +1 -0
- package/gui/dist/assets/index-BynIEIV-.js +70 -0
- package/gui/dist/index.html +2 -2
- package/package.json +4 -2
- package/src/adapters/cursor/effort-map.ts +11 -0
- package/src/adapters/cursor/live-transport.ts +11 -0
- package/src/adapters/cursor/native-exec-fs.ts +9 -6
- package/src/adapters/cursor/native-exec.ts +4 -2
- package/src/adapters/cursor/protobuf-events.ts +176 -4
- package/src/adapters/cursor/request-builder.ts +15 -4
- package/src/adapters/cursor/tool-definitions.ts +118 -2
- package/src/adapters/google.ts +15 -5
- package/src/adapters/openai-chat.ts +24 -2
- package/src/adapters/openai-responses.ts +2 -1
- package/src/bridge.ts +9 -5
- package/src/chat/outbound.ts +4 -3
- package/src/claude/desktop-3p.ts +222 -2
- package/src/claude/outbound.ts +15 -6
- package/src/cli/account-api.ts +4 -0
- package/src/cli/account-extended.ts +112 -0
- package/src/cli/account.ts +23 -6
- package/src/cli/claude-desktop.ts +26 -3
- package/src/cli/config-command.ts +9 -0
- package/src/cli/help.ts +18 -2
- package/src/cli/index.ts +277 -55
- package/src/cli/models.ts +5 -1
- package/src/cli/provider.ts +8 -2
- package/src/cli/ready.ts +301 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/clients/config-export.ts +12 -19
- package/src/codex/account-lifecycle.ts +3 -0
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/auth-api.ts +83 -0
- package/src/codex/auth-context.ts +5 -2
- package/src/codex/catalog/provider-fetch.ts +11 -0
- package/src/codex/catalog/sync.ts +23 -1
- package/src/codex/codex-write-lock.ts +16 -4
- package/src/codex/desired-state.ts +37 -4
- package/src/codex/history-job.ts +15 -5
- package/src/codex/history-provider.ts +31 -14
- package/src/codex/history-worker.ts +28 -4
- package/src/codex/inject-coordination.ts +13 -1
- package/src/codex/inject.ts +360 -66
- package/src/codex/internal/history-writer.ts +1 -1
- package/src/codex/native-main-lock-file.ts +5 -1
- package/src/codex/native-main-owner.ts +17 -3
- package/src/codex/native-profile-manager.ts +19 -0
- package/src/codex/native-profile-startup.ts +8 -0
- package/src/codex/native-residue.ts +140 -27
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/refresh.ts +7 -0
- package/src/codex/routing.ts +177 -36
- package/src/codex/subagent-model-fallback.ts +34 -4
- package/src/codex/sync.ts +61 -0
- package/src/codex/upstream-host-health.ts +329 -31
- package/src/combos/request.ts +2 -0
- package/src/config.ts +221 -2
- package/src/images/loop.ts +1 -1
- package/src/integrations/native/ownership-preflight.ts +39 -2
- package/src/lib/bun-stream-caps.ts +3 -3
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/windows-secret-acl.ts +141 -39
- package/src/lib/windows-user-principal.ts +283 -0
- package/src/lib/winsw.ts +18 -2
- package/src/oauth/key-providers.ts +12 -0
- package/src/providers/derive.ts +54 -2
- package/src/providers/free-directory.ts +6 -5
- package/src/providers/model-discovery.ts +9 -3
- package/src/providers/quota.ts +592 -0
- package/src/providers/registry.ts +316 -13
- package/src/responses/parser.ts +26 -10
- package/src/responses/reasoning-replay-cache.ts +1 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +2 -1
- package/src/server/auth-cors.ts +44 -13
- package/src/server/chat-completions.ts +0 -4
- package/src/server/claude-messages.ts +73 -15
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/index.ts +328 -111
- package/src/server/lifecycle.ts +36 -0
- package/src/server/management/agent-settings-routes.ts +147 -56
- package/src/server/management/config-routes.ts +7 -2
- package/src/server/management/context.ts +4 -0
- package/src/server/management/native-integration-routes.ts +199 -20
- package/src/server/management/provider-routes.ts +41 -0
- package/src/server/management/routing-profile-routes.ts +234 -5
- package/src/server/management/system-restart.ts +12 -10
- package/src/server/management/system-routes.ts +20 -0
- package/src/server/management-auth.ts +51 -3
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +129 -4
- package/src/server/readiness.ts +99 -0
- package/src/server/relay.ts +113 -97
- package/src/server/request-log.ts +10 -4
- package/src/server/responses/compact.ts +107 -12
- package/src/server/responses/core.ts +220 -39
- package/src/server/responses-item-id-repair.ts +22 -3
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +25 -14
- package/src/server/ws-bridge.ts +27 -22
- package/src/service-manager-probe.ts +520 -10
- package/src/service.ts +134 -2
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +74 -9
- package/src/types.ts +68 -2
- package/src/update/index.ts +12 -0
- package/src/update/job.ts +392 -18
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/usage/log.ts +1 -1
- package/src/vision/index.ts +77 -2
- package/src/web-search/loop.ts +1 -1
- package/src/web-search/parse.ts +4 -1
- package/gui/dist/assets/index-BKVqyYqT.js +0 -70
- package/gui/dist/assets/index-Ca_3269W.css +0 -1
|
@@ -17,6 +17,8 @@ export interface HealthzIdentity {
|
|
|
17
17
|
version?: unknown;
|
|
18
18
|
uptime?: unknown;
|
|
19
19
|
pid?: unknown;
|
|
20
|
+
port?: unknown;
|
|
21
|
+
restartCapability?: unknown;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export interface LivenessIo {
|
|
@@ -47,6 +49,9 @@ export interface LivenessIo {
|
|
|
47
49
|
nowFn?: () => number;
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
/** Default per-probe fetch ceiling shared by liveness and readiness probes. */
|
|
53
|
+
export const DEFAULT_PROBE_TIMEOUT_MS = 750;
|
|
54
|
+
|
|
50
55
|
/** Default probe options for service stop / orphan cleanup — a just-bound proxy can miss a single 750ms probe. */
|
|
51
56
|
export const SERVICE_STOP_LIVENESS: Pick<LivenessIo, "timeoutMs" | "attempts"> = {
|
|
52
57
|
timeoutMs: 1500,
|
|
@@ -95,7 +100,7 @@ export async function proxyIdentityAt(
|
|
|
95
100
|
const fetchFn = io.fetchFn ?? fetch;
|
|
96
101
|
const sleepFn = io.sleepFn ?? ((ms: number) => new Promise<void>(r => setTimeout(r, ms)));
|
|
97
102
|
const nowFn = io.nowFn ?? Date.now;
|
|
98
|
-
const baseTimeoutMs = io.timeoutMs ??
|
|
103
|
+
const baseTimeoutMs = io.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
99
104
|
const requestedAttempts = Math.trunc(io.attempts ?? 1);
|
|
100
105
|
const attempts = Number.isNaN(requestedAttempts)
|
|
101
106
|
? 1
|
|
@@ -138,6 +143,11 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
138
143
|
const verifyPidFn = io.verifyPidFn ?? verifyPidIdentity;
|
|
139
144
|
const readRuntimeFn = io.readRuntimeFn ?? readRuntimePort;
|
|
140
145
|
const configFn = io.configFn ?? loadConfig;
|
|
146
|
+
const nowFn = io.nowFn ?? Date.now;
|
|
147
|
+
const deadlineAt = io.deadlineAt;
|
|
148
|
+
const probeIo: LivenessIo = io;
|
|
149
|
+
const budgetExhausted = (): boolean =>
|
|
150
|
+
deadlineAt !== undefined && nowFn() >= deadlineAt;
|
|
141
151
|
|
|
142
152
|
// The cheap pid is discovery-only. Before it can appear in a returned (killable) result
|
|
143
153
|
// it must pass the full identity check AND the verifier must echo the exact candidate —
|
|
@@ -160,8 +170,9 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
160
170
|
if (pid) {
|
|
161
171
|
const runtime = readRuntimeFn(pid);
|
|
162
172
|
if (runtime?.port) {
|
|
173
|
+
if (budgetExhausted()) return null;
|
|
163
174
|
probedPort = runtime.port;
|
|
164
|
-
const identity = await proxyIdentityAt(runtime.port, { hostname: runtime.hostname, expectedPid: pid },
|
|
175
|
+
const identity = await proxyIdentityAt(runtime.port, { hostname: runtime.hostname, expectedPid: pid }, probeIo);
|
|
165
176
|
if (identity) {
|
|
166
177
|
// healthz confirmed the pid itself → trusted; a pidless legacy body did not,
|
|
167
178
|
// so the cheap pid must pass full identity verification before it is returned.
|
|
@@ -176,8 +187,9 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
176
187
|
// identity-probe it so ensure/update/stop see the live proxy instead of shadowing it.
|
|
177
188
|
const record = readRuntimeFn();
|
|
178
189
|
if (record?.port && record.port !== probedPort) {
|
|
190
|
+
if (budgetExhausted()) return null;
|
|
179
191
|
const expectedPid = typeof record.pid === "number" ? record.pid : undefined;
|
|
180
|
-
const identity = await proxyIdentityAt(record.port, { hostname: record.hostname, expectedPid },
|
|
192
|
+
const identity = await proxyIdentityAt(record.port, { hostname: record.hostname, expectedPid }, probeIo);
|
|
181
193
|
// Only the healthz-reported pid is authoritative here. The record's pid may be stale
|
|
182
194
|
// (its process dead, the port reused by a pidless legacy proxy) — synthesizing it
|
|
183
195
|
// would hand destructive callers (stopProxy → kill fallback) a reusable pid.
|
|
@@ -188,7 +200,8 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
188
200
|
|
|
189
201
|
const config = configFn();
|
|
190
202
|
const port = config.port ?? 10100;
|
|
191
|
-
|
|
203
|
+
if (budgetExhausted()) return null;
|
|
204
|
+
const identity = await proxyIdentityAt(port, { hostname: config.hostname }, probeIo);
|
|
192
205
|
if (identity) {
|
|
193
206
|
return {
|
|
194
207
|
pid: verifiedReportedPid(identity.pid) ?? killablePid(pid),
|
|
@@ -199,3 +212,115 @@ export async function findLiveProxy(io: LivenessIo = {}): Promise<LiveProxy | nu
|
|
|
199
212
|
}
|
|
200
213
|
return null;
|
|
201
214
|
}
|
|
215
|
+
|
|
216
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
217
|
+
// Readiness (/readyz) strict probe.
|
|
218
|
+
//
|
|
219
|
+
// Liveness (/healthz) confirms the process answers; readiness confirms the
|
|
220
|
+
// post-startup Codex sync has settled. A readiness probe is identity-checked the
|
|
221
|
+
// same way liveness is, AND additionally enforces the full /readyz contract so
|
|
222
|
+
// an adversarial or malformed body can never count as ready:
|
|
223
|
+
//
|
|
224
|
+
// - HTTP 200 is required for status="ready"; HTTP 503 is required for pending
|
|
225
|
+
// or failed. Any other HTTP/body-status pairing is an invalid contract.
|
|
226
|
+
// - body.service must be exactly "opencodex".
|
|
227
|
+
// - body.version must be a non-empty string.
|
|
228
|
+
// - body.uptime must be a finite nonnegative number.
|
|
229
|
+
// - body.pid must be a positive integer; when `expectedPid` is supplied it must
|
|
230
|
+
// match exactly.
|
|
231
|
+
// - body.port must be an integer in 1..65535 and equal the probed port.
|
|
232
|
+
// - body.status must be exactly one of pending|ready|failed.
|
|
233
|
+
//
|
|
234
|
+
// Any unreachable, foreign, legacy, malformed, mismatched, or self-inconsistent
|
|
235
|
+
// response returns `null` so callers can never treat an invalid identity/contract
|
|
236
|
+
// as ready.
|
|
237
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
interface ReadyzBody {
|
|
240
|
+
service?: unknown;
|
|
241
|
+
version?: unknown;
|
|
242
|
+
uptime?: unknown;
|
|
243
|
+
pid?: unknown;
|
|
244
|
+
port?: unknown;
|
|
245
|
+
status?: unknown;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface ReadinessProbeResult {
|
|
249
|
+
/** True ONLY for a valid 200 + status="ready" body with a matching pid. */
|
|
250
|
+
ready: boolean;
|
|
251
|
+
/** Fixed sanitized status. A foreign/unreadable body yields a `null` RESULT, never a `null` status. */
|
|
252
|
+
status: "ready" | "pending" | "failed";
|
|
253
|
+
/** Positive integer pid from a valid body. */
|
|
254
|
+
pid: number;
|
|
255
|
+
/** Integer port from a valid body. */
|
|
256
|
+
port: number;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface ReadinessProbeIo {
|
|
260
|
+
fetchFn?: typeof fetch;
|
|
261
|
+
timeoutMs?: number;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const READYZ_STATUS_VALUES = new Set<"ready" | "pending" | "failed">(["ready", "pending", "failed"]);
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Validate a parsed /readyz body against the strict contract. Returns the
|
|
268
|
+
* sanitized probe result, or `null` when the body is foreign, legacy,
|
|
269
|
+
* malformed, or fails the pid/port checks. Pure (no I/O) so it is fully
|
|
270
|
+
* deterministic and unit-testable.
|
|
271
|
+
*/
|
|
272
|
+
export function validateReadyzBody(
|
|
273
|
+
body: unknown,
|
|
274
|
+
port: number,
|
|
275
|
+
opts: { expectedPid?: number } = {},
|
|
276
|
+
): ReadinessProbeResult | null {
|
|
277
|
+
if (!body || typeof body !== "object") return null;
|
|
278
|
+
const b = body as ReadyzBody;
|
|
279
|
+
if (b.service !== "opencodex") return null;
|
|
280
|
+
if (typeof b.version !== "string" || b.version.length === 0) return null;
|
|
281
|
+
if (typeof b.uptime !== "number" || !Number.isFinite(b.uptime) || b.uptime < 0) return null;
|
|
282
|
+
if (typeof b.pid !== "number" || !Number.isInteger(b.pid) || b.pid <= 0) return null;
|
|
283
|
+
if (
|
|
284
|
+
typeof b.port !== "number"
|
|
285
|
+
|| !Number.isInteger(b.port)
|
|
286
|
+
|| b.port < 1
|
|
287
|
+
|| b.port > 65535
|
|
288
|
+
|| b.port !== port
|
|
289
|
+
) return null;
|
|
290
|
+
if (typeof b.status !== "string" || !READYZ_STATUS_VALUES.has(b.status as "ready" | "pending" | "failed")) return null;
|
|
291
|
+
const status = b.status as "ready" | "pending" | "failed";
|
|
292
|
+
if (opts.expectedPid !== undefined && b.pid !== opts.expectedPid) return null;
|
|
293
|
+
return { ready: status === "ready", status, pid: b.pid, port: b.port };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Identity- and contract-checked /readyz probe. Returns `null` when the
|
|
298
|
+
* endpoint is unreachable or the body fails the strict contract (foreign 200,
|
|
299
|
+
* legacy health-only body, non-JSON, missing/malformed/mismatched fields,
|
|
300
|
+
* wrong port/pid, or an HTTP/body-status inconsistency). Returns
|
|
301
|
+
* `{ready:false, ...}` when the body is ours but pending or failed. Returns
|
|
302
|
+
* `{ready:true, ...}` ONLY for a valid 200 body with `status:"ready"` and (when
|
|
303
|
+
* requested) a matching pid.
|
|
304
|
+
*/
|
|
305
|
+
export async function probeReadiness(
|
|
306
|
+
port: number,
|
|
307
|
+
opts: { hostname?: string; expectedPid?: number } = {},
|
|
308
|
+
io: ReadinessProbeIo = {},
|
|
309
|
+
): Promise<ReadinessProbeResult | null> {
|
|
310
|
+
const fetchFn = io.fetchFn ?? fetch;
|
|
311
|
+
try {
|
|
312
|
+
const res = await fetchFn(`http://${probeHostname(opts.hostname)}:${port}/readyz`, {
|
|
313
|
+
signal: AbortSignal.timeout(io.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS),
|
|
314
|
+
});
|
|
315
|
+
// Parse even on 503: /readyz returns JSON with a sanitized status while pending.
|
|
316
|
+
const body = (await res.json().catch(() => null)) as unknown;
|
|
317
|
+
const parsed = validateReadyzBody(body, port, opts);
|
|
318
|
+
if (!parsed) return null;
|
|
319
|
+
// HTTP/body-status consistency: ready requires 200; pending/failed require 503.
|
|
320
|
+
if (parsed.status === "ready" && res.status !== 200) return null;
|
|
321
|
+
if (parsed.status !== "ready" && res.status !== 503) return null;
|
|
322
|
+
return parsed;
|
|
323
|
+
} catch {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-server readiness gate for the opencodex proxy.
|
|
3
|
+
*
|
|
4
|
+
* `GET /healthz` answers "is the process alive and serving HTTP?" the instant the
|
|
5
|
+
* listener binds. Readiness is stricter: the proxy is "ready" only after the
|
|
6
|
+
* post-startup Codex catalog/config sync (`syncModelsToCodex`) has settled with
|
|
7
|
+
* `ok=true` and no catalog-sync warning. Until then the process is live (Codex can
|
|
8
|
+
* open a socket) but not ready (a request would race the sync or hit a stale
|
|
9
|
+
* catalog), so clients should back off.
|
|
10
|
+
*
|
|
11
|
+
* Design contract (per P1 review):
|
|
12
|
+
* - NO module-global mutable state. Each `startServer` invocation gets its own
|
|
13
|
+
* private gate via `createReadinessGate()`, captured by that listener's
|
|
14
|
+
* closure. Starting/failing a second server in the same process can never
|
|
15
|
+
* reset or mutate the first server's gate.
|
|
16
|
+
* - Only the fixed sanitized status enum `pending | ready | failed` is stored
|
|
17
|
+
* and exposed. There is no `changedAt`, no free-form failure reason, no sync
|
|
18
|
+
* message, no warning text, no catalog path, no provider output, and no
|
|
19
|
+
* account data — those are private diagnostic data and are never exposed by
|
|
20
|
+
* `/readyz`.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** Sanitized readiness state. Exactly these three values, nothing else. */
|
|
24
|
+
export type ReadinessStatus = "pending" | "ready" | "failed";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Private per-server readiness controller. The status starts at `pending` and
|
|
28
|
+
* transitions at most once (to `ready` or `failed`) when the post-startup sync
|
|
29
|
+
* settles. The gate is owned by the listener closure that requested it.
|
|
30
|
+
*/
|
|
31
|
+
export interface ReadinessGate {
|
|
32
|
+
/** Current sanitized status. */
|
|
33
|
+
getStatus(): ReadinessStatus;
|
|
34
|
+
/** Mark the proxy ready (post-startup sync settled cleanly). */
|
|
35
|
+
markReady(): void;
|
|
36
|
+
/** Mark the proxy failed. No reason is stored or exposed. */
|
|
37
|
+
markFailed(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a fresh private gate for one `startServer` invocation. The returned
|
|
42
|
+
* gate is the only way to read or mutate this server's readiness.
|
|
43
|
+
*/
|
|
44
|
+
export function createReadinessGate(): ReadinessGate {
|
|
45
|
+
let status: ReadinessStatus = "pending";
|
|
46
|
+
return {
|
|
47
|
+
getStatus: () => status,
|
|
48
|
+
markReady: () => {
|
|
49
|
+
if (status === "pending") status = "ready";
|
|
50
|
+
},
|
|
51
|
+
markFailed: () => {
|
|
52
|
+
if (status === "pending") status = "failed";
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Minimal shape of the post-startup sync outcome the gate cares about. */
|
|
58
|
+
export interface SyncOutcomeLike {
|
|
59
|
+
ok?: boolean;
|
|
60
|
+
warning?: string;
|
|
61
|
+
/** #1046: whether the sync actually rewrote the on-disk catalog/cache. */
|
|
62
|
+
catalogWritten?: boolean;
|
|
63
|
+
cacheSynced?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Drive the gate from the post-startup sync. Awaits `syncFn`; the gate goes to
|
|
68
|
+
* `ready` ONLY on `ok=true` with no nonempty warning. A throw, `null`, `ok=false`,
|
|
69
|
+
* or a nonempty warning transitions to `failed`. Used directly by `handleStart`
|
|
70
|
+
* so the startup transition is unit-testable without spawning the proxy. Returns
|
|
71
|
+
* the raw sync outcome so a caller that also needs the #1046 write flags (did the
|
|
72
|
+
* sync actually write the catalog/cache?) can keep them without a second call.
|
|
73
|
+
*/
|
|
74
|
+
export async function runStartupReadinessSync(
|
|
75
|
+
gate: ReadinessGate,
|
|
76
|
+
syncFn: () => Promise<SyncOutcomeLike | null>,
|
|
77
|
+
): Promise<SyncOutcomeLike | null> {
|
|
78
|
+
let result: SyncOutcomeLike | null;
|
|
79
|
+
try {
|
|
80
|
+
result = await syncFn();
|
|
81
|
+
} catch {
|
|
82
|
+
gate.markFailed();
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (result === null) {
|
|
86
|
+
gate.markFailed();
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
if (result.ok !== true) {
|
|
90
|
+
gate.markFailed();
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
if (result.warning !== undefined && result.warning !== "") {
|
|
94
|
+
gate.markFailed();
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
gate.markReady();
|
|
98
|
+
return result;
|
|
99
|
+
}
|