@bitkyc08/opencodex 2.77.0 → 2.78.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/bin/ocx.mjs +11 -10
- package/gui/dist/assets/App-BtfG5id-.js +54 -0
- package/gui/dist/assets/App-lCIslZ1L.css +1 -0
- package/gui/dist/assets/{Tray-gloIYNaW.js → Tray-DiJpSub0.js} +1 -1
- package/gui/dist/assets/index-Btc3Ogw4.js +94 -0
- package/gui/dist/assets/index-DmQB8D_R.css +1 -0
- package/gui/dist/assets/quota-summary-B_a96nXj.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic/beta-allowlist.ts +19 -2
- package/src/adapters/anthropic/client-identity.ts +13 -4
- package/src/adapters/anthropic/native-client-preamble.ts +31 -0
- package/src/adapters/anthropic/passthrough.ts +103 -25
- package/src/adapters/devin/cloud-direct/chat.ts +7 -2
- package/src/adapters/devin/trajectory.ts +49 -0
- package/src/adapters/devin.ts +13 -0
- package/src/adapters/ollama-native.ts +35 -19
- package/src/claude/intercept/client-hello.ts +103 -0
- package/src/claude/intercept/model-bindings.ts +3 -2
- package/src/claude/intercept/picker-listener.ts +279 -66
- package/src/cli/access-audio-input.ts +84 -0
- package/src/cli/access-audio-live.ts +99 -0
- package/src/cli/access-audio.ts +123 -0
- package/src/cli/access-data-client.ts +127 -0
- package/src/cli/access-data-plane.ts +104 -0
- package/src/cli/access-data-response.ts +76 -0
- package/src/cli/access.ts +65 -2
- package/src/cli/account-api.ts +30 -6
- package/src/cli/account-auth.ts +111 -42
- package/src/cli/account-key-quota.ts +118 -0
- package/src/cli/account-main.ts +11 -4
- package/src/cli/account-next-actions.ts +63 -0
- package/src/cli/account-policy-dto.ts +68 -0
- package/src/cli/account-policy.ts +167 -0
- package/src/cli/account-target.ts +8 -0
- package/src/cli/account.ts +34 -8
- package/src/cli/agent-runtime-settings.ts +130 -0
- package/src/cli/agent-settings.ts +101 -0
- package/src/cli/agent.ts +19 -2
- package/src/cli/alias.ts +7 -2
- package/src/cli/aside-profiles.ts +2 -2
- package/src/cli/capabilities-access-remote.ts +147 -0
- package/src/cli/capabilities-accounts.ts +195 -0
- package/src/cli/capabilities-agents-routing.ts +414 -0
- package/src/cli/capabilities-base.ts +783 -0
- package/src/cli/capabilities-command.ts +1 -0
- package/src/cli/capabilities-integrations.ts +264 -0
- package/src/cli/capabilities-lab.ts +214 -0
- package/src/cli/capabilities-observe-system.ts +662 -0
- package/src/cli/capabilities-provider-models.ts +302 -0
- package/src/cli/capabilities.ts +30 -1199
- package/src/cli/capability-types.ts +54 -0
- package/src/cli/catalog-command-result.ts +57 -0
- package/src/cli/chatgpt-command.ts +25 -2
- package/src/cli/claude-agent-startup-sync.ts +17 -0
- package/src/cli/claude-desktop-profile.ts +100 -0
- package/src/cli/claude-desktop.ts +39 -6
- package/src/cli/codex-shim-autorestore.ts +2 -1
- package/src/cli/codex-shim-readiness.ts +23 -3
- package/src/cli/combo-input.ts +88 -0
- package/src/cli/combo-result.ts +52 -0
- package/src/cli/combo-stats.ts +123 -0
- package/src/cli/combo.ts +37 -14
- package/src/cli/companion-timeline.ts +142 -0
- package/src/cli/companion-usage.ts +146 -0
- package/src/cli/companion.ts +12 -3
- package/src/cli/config-command.ts +24 -8
- package/src/cli/dispatch.ts +52 -79
- package/src/cli/doctor.ts +22 -4
- package/src/cli/help-catalog.ts +31 -14
- package/src/cli/help-recovery.ts +2 -2
- package/src/cli/help.ts +25 -11
- package/src/cli/index.ts +38 -27
- package/src/cli/injection-follow.ts +35 -0
- package/src/cli/inspect.ts +5 -0
- package/src/cli/integration-aside-sync.ts +69 -0
- package/src/cli/integration-cursor.ts +106 -0
- package/src/cli/integration-input.ts +60 -0
- package/src/cli/integration-journal.ts +49 -0
- package/src/cli/integration-plan-dto.ts +156 -0
- package/src/cli/integration-preview.ts +215 -0
- package/src/cli/integrations.ts +24 -18
- package/src/cli/json-input.ts +134 -0
- package/src/cli/link.ts +32 -4
- package/src/cli/local-sync-result.ts +41 -0
- package/src/cli/log-follow.ts +84 -0
- package/src/cli/log-view-filter.ts +146 -0
- package/src/cli/logout-command.ts +44 -0
- package/src/cli/model-picker-ordering.ts +137 -0
- package/src/cli/models-custom-input.ts +107 -0
- package/src/cli/models-custom-runtime.ts +112 -0
- package/src/cli/models-order.ts +194 -0
- package/src/cli/models-runtime-subcommands.ts +2 -0
- package/src/cli/models-runtime.ts +7 -0
- package/src/cli/models.ts +66 -81
- package/src/cli/observe-stream.ts +142 -0
- package/src/cli/observe.ts +75 -34
- package/src/cli/provider-batch.ts +77 -0
- package/src/cli/provider-lifecycle-runtime.ts +170 -0
- package/src/cli/provider-result.ts +124 -0
- package/src/cli/provider-runtime.ts +15 -12
- package/src/cli/provider-settings.ts +143 -0
- package/src/cli/provider.ts +112 -34
- package/src/cli/registry.ts +62 -20
- package/src/cli/remote-workspace-hub.ts +83 -0
- package/src/cli/remote-workspace.ts +6 -1
- package/src/cli/restart-failure.ts +27 -0
- package/src/cli/root.ts +12 -0
- package/src/cli/route-policy-write.ts +137 -0
- package/src/cli/route-policy.ts +8 -0
- package/src/cli/runtime-api.ts +56 -79
- package/src/cli/secret-args.ts +149 -0
- package/src/cli/settings-result.ts +30 -0
- package/src/cli/storage.ts +77 -7
- package/src/cli/system-command.ts +60 -2
- package/src/cli/system-restart-client.ts +20 -3
- package/src/cli/system-settings-parity.ts +83 -0
- package/src/cli/update-restart-candidate.ts +21 -0
- package/src/cli/update-restart-child.ts +81 -0
- package/src/cli/update-restart-home.ts +38 -0
- package/src/cli/update-restart-transport.ts +193 -0
- package/src/cli/update-restart.ts +260 -0
- package/src/cli/usage-model-search.ts +58 -0
- package/src/cli/usage-report.ts +13 -5
- package/src/cli/v2-input.ts +66 -0
- package/src/cli/v2-local-output.ts +37 -0
- package/src/cli/v2-runtime.ts +90 -0
- package/src/cli/v2.ts +102 -144
- package/src/clients/config-export/dsh.ts +21 -0
- package/src/clients/config-export.ts +7 -1
- package/src/codex/catalog/build-entries.ts +1 -1
- package/src/codex/catalog/bundled.ts +9 -2
- package/src/codex/catalog/heal-observation.ts +66 -0
- package/src/codex/catalog/publication-observer.ts +19 -0
- package/src/codex/catalog/remote.ts +13 -15
- package/src/codex/catalog/restore.ts +19 -6
- package/src/codex/catalog/retained-sync.ts +58 -10
- package/src/codex/catalog/routed-removal.ts +116 -0
- package/src/codex/catalog/write-audit-contract.ts +21 -0
- package/src/codex/catalog/write-audit.ts +171 -0
- package/src/codex/catalog-self-heal.ts +284 -0
- package/src/codex/catalog-write-serialization.ts +71 -7
- package/src/codex/codex-home-owner.ts +124 -0
- package/src/codex/convergence.ts +55 -15
- package/src/codex/features.ts +8 -1
- package/src/codex/inject/restore.ts +46 -4
- package/src/codex/inject.ts +11 -1
- package/src/codex/internal/catalog-writer.ts +120 -13
- package/src/codex/journal.ts +49 -13
- package/src/codex/management-convergence.ts +3 -0
- package/src/codex/quota-types.ts +3 -0
- package/src/codex/quota.ts +13 -3
- package/src/codex/refresh.ts +20 -9
- package/src/codex/runtime.ts +7 -1
- package/src/codex/shim-diagnostics.ts +80 -0
- package/src/codex/shim-fingerprint.ts +7 -2
- package/src/codex/shim-migration.ts +153 -0
- package/src/codex/shim-overlay.ts +509 -0
- package/src/codex/shim-path-resolution.ts +14 -2
- package/src/codex/shim-probe.ts +4 -3
- package/src/codex/shim-state-file.ts +93 -7
- package/src/codex/shim.ts +15 -68
- package/src/codex/sync.ts +24 -4
- package/src/combos/failover.ts +19 -0
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +12 -0
- package/src/config/atomic-write.ts +13 -8
- package/src/config/diagnostics.ts +19 -1
- package/src/config/load-degrade.ts +3 -0
- package/src/config/schema/chatgpt-desktop.ts +22 -0
- package/src/config/schema/config-schema.ts +32 -14
- package/src/config/schema/leaf-validators.ts +3 -2
- package/src/generated/compatibility-version.json +445 -129
- package/src/integrations/merge.ts +13 -5
- package/src/integrations/mutation-plan.ts +46 -3
- package/src/integrations/omp-yaml-source.ts +181 -1
- package/src/integrations/ownership-policy.ts +66 -0
- package/src/integrations/registry.ts +50 -1
- package/src/integrations/state.ts +46 -21
- package/src/integrations/target.ts +25 -2
- package/src/integrations/writer.ts +89 -31
- package/src/lib/package-tree-integrity.ts +42 -1
- package/src/lib/proxy-env.ts +3 -0
- package/src/lib/test-home-guard.ts +2 -1
- package/src/oauth/anthropic-account-refusal.ts +19 -8
- package/src/oauth/anthropic-routing.ts +17 -12
- package/src/oauth/anthropic.ts +27 -2
- package/src/oauth/index.ts +6 -8
- package/src/oauth/pool-settings-capability.ts +9 -2
- package/src/protocols/plan-snapshot.ts +1 -1
- package/src/protocols/settings.ts +28 -4
- package/src/server/caller-session-identity.ts +32 -0
- package/src/server/claude-messages.ts +11 -4
- package/src/server/index/serve-options.ts +12 -7
- package/src/server/index.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +6 -5
- package/src/server/management/context.ts +8 -1
- package/src/server/management/cursor-integration-routes.ts +3 -3
- package/src/server/management/integration-routes.ts +5 -5
- package/src/server/management/model-routes.ts +3 -3
- package/src/server/management/native-integration-routes.ts +2 -2
- package/src/server/management/oauth-account-routes.ts +96 -30
- package/src/server/management/route-registry.ts +25 -24
- package/src/server/messages-native-eligibility.ts +3 -6
- package/src/server/messages-native-oauth.ts +82 -35
- package/src/server/messages-native.ts +78 -16
- package/src/server/responses/adapter-dispatch.ts +53 -28
- package/src/server/responses/core-auth.ts +10 -4
- package/src/server/responses/core-combo.ts +46 -6
- package/src/service/cli.ts +6 -1
- package/src/service/ownership-mutation-lease.d.mts +26 -0
- package/src/service/ownership-mutation-lease.mjs +76 -1
- package/src/types/config.ts +2 -0
- package/src/types/provider.ts +10 -10
- package/src/update/index.ts +2 -1
- package/src/update/update-failure-guidance.d.mts +6 -0
- package/src/update/update-failure-guidance.mjs +30 -5
- package/gui/dist/assets/App-COdEeqSj.css +0 -1
- package/gui/dist/assets/App-DEpCJEP_.js +0 -54
- package/gui/dist/assets/index-Cd7ittMv.css +0 -1
- package/gui/dist/assets/index-DwJKFJm5.js +0 -94
- package/gui/dist/assets/quota-summary-DGcEJU3h.js +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import {
|
|
3
4
|
closeSync,
|
|
@@ -108,6 +109,73 @@ function readIncompleteOwner(path) {
|
|
|
108
109
|
} catch { return null; }
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
/** The current executable at the recorded PID, identity unverified; null if unreadable within a second. */
|
|
113
|
+
function processImage(pid) {
|
|
114
|
+
try {
|
|
115
|
+
if (process.platform === "win32") {
|
|
116
|
+
const listed = spawnSync("tasklist", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"], {
|
|
117
|
+
encoding: "utf8", timeout: 1_000, windowsHide: true,
|
|
118
|
+
});
|
|
119
|
+
const match = /^"([^"]+)","(\d+)"/.exec((listed.stdout ?? "").trim());
|
|
120
|
+
return listed.status === 0 && match && Number(match[2]) === pid ? match[1] : null;
|
|
121
|
+
}
|
|
122
|
+
const listed = spawnSync("ps", ["-o", "comm=", "-p", String(pid)], { encoding: "utf8", timeout: 1_000 });
|
|
123
|
+
const command = (listed.stdout ?? "").trim();
|
|
124
|
+
return listed.status === 0 && command ? basename(command) : null;
|
|
125
|
+
} catch { return null; }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The recorded owner of the lease directory at `path`, read as stale recovery reads it, or null
|
|
130
|
+
* when no lock directory exists. `pid` is null when the directory has no parseable owner; `age`
|
|
131
|
+
* uses the same clock as reclamation (the later of the record's creation and its file mtime).
|
|
132
|
+
* Liveness and image describe the current process at the recorded PID; its identity is not verified.
|
|
133
|
+
*/
|
|
134
|
+
function leaseHolder(path, now, alive, image) {
|
|
135
|
+
if (!existsSync(path)) return null;
|
|
136
|
+
const observed = readOwner(path);
|
|
137
|
+
const incomplete = observed ? null : readIncompleteOwner(path);
|
|
138
|
+
// Neither reader matched: the holder may have released between these reads. Report a free
|
|
139
|
+
// lease then, not an unreadable one.
|
|
140
|
+
if (!observed && !incomplete && !existsSync(path)) return null;
|
|
141
|
+
const pid = observed?.record.pid ?? incomplete?.pid ?? null;
|
|
142
|
+
const since = observed ? Math.max(observed.record.createdAt, observed.mtimeMs) : incomplete?.mtimeMs ?? null;
|
|
143
|
+
const live = pid === null ? null : alive(pid);
|
|
144
|
+
return {
|
|
145
|
+
path,
|
|
146
|
+
pid,
|
|
147
|
+
alive: live,
|
|
148
|
+
image: live ? image(pid) : null,
|
|
149
|
+
ageMs: since === null ? null : Math.max(0, now() - since),
|
|
150
|
+
record: observed ? "complete" : incomplete?.ownerPath ? "incomplete" : incomplete ? "empty" : "unreadable",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function describeHolder(holder) {
|
|
155
|
+
const age = holder.ageMs === null ? "" : `, lease age ${Math.round(holder.ageMs / 1_000)}s`;
|
|
156
|
+
if (holder.record === "unreadable") return "holder unknown: the lock directory does not hold exactly one owner file";
|
|
157
|
+
if (holder.record === "empty") return `no owner file written yet${age}`;
|
|
158
|
+
const state = holder.alive ? ["alive", ...(holder.image ? [holder.image] : [])].join(", ") : "not alive";
|
|
159
|
+
const partial = holder.record === "incomplete" ? ", owner record incomplete" : "";
|
|
160
|
+
return `recorded PID ${holder.pid} [${state}, identity unverified${partial}]${age}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const RECLAIM_HINT = `stale leases are reclaimed after ${STALE_MS / 1_000}s once the recorded PID is no longer alive`;
|
|
164
|
+
|
|
165
|
+
/** The recorded lease owner for `statePaths`, identity unverified, or null if free. Reads only; never reclaims. */
|
|
166
|
+
export function inspectOwnershipMutationLease(statePaths, options = {}) {
|
|
167
|
+
return leaseHolder(leasePath(statePaths), options.now ?? Date.now, options.processAlive ?? processAlive,
|
|
168
|
+
options.processImage ?? processImage);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** One status line naming the recorded PID, identity unverified, or null when the lease is free. */
|
|
172
|
+
export function ownershipMutationLeaseStatusLine(statePaths, options = {}) {
|
|
173
|
+
const holder = inspectOwnershipMutationLease(statePaths, options);
|
|
174
|
+
if (!holder) return null;
|
|
175
|
+
return `Runtime mutation lease busy at ${holder.path} (${describeHolder(holder)}); `
|
|
176
|
+
+ `opencodex waits for it to start or change service state, and ${RECLAIM_HINT}.`;
|
|
177
|
+
}
|
|
178
|
+
|
|
111
179
|
function reclaim(path, now, alive) {
|
|
112
180
|
const observed = readOwner(path);
|
|
113
181
|
const incomplete = observed ? null : readIncompleteOwner(path);
|
|
@@ -182,7 +250,14 @@ export function acquireOwnershipMutationLease(
|
|
|
182
250
|
}
|
|
183
251
|
if (error?.code !== "EEXIST") throw error;
|
|
184
252
|
if (reclaim(path, now, alive)) continue;
|
|
185
|
-
if (now() >= deadline)
|
|
253
|
+
if (now() >= deadline) {
|
|
254
|
+
const holder = leaseHolder(path, now, alive, options.processImage ?? processImage);
|
|
255
|
+
const error = new Error(`another process owns the runtime mutation lease at ${path}`
|
|
256
|
+
+ (holder ? ` (${describeHolder(holder)}; ${RECLAIM_HINT})` : ""));
|
|
257
|
+
error.code = "OWNERSHIP_MUTATION_LEASE_BUSY";
|
|
258
|
+
error.holder = holder;
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
186
261
|
(options.sleep ?? sleep)(POLL_MS);
|
|
187
262
|
}
|
|
188
263
|
}
|
package/src/types/config.ts
CHANGED
|
@@ -1218,6 +1218,8 @@ export interface OcxConfig {
|
|
|
1218
1218
|
*/
|
|
1219
1219
|
anthropicAccountPool?: {
|
|
1220
1220
|
enabled?: boolean;
|
|
1221
|
+
/** Preserve native Claude Messages while the pool is enabled. Default true; false selects legacy translation. */
|
|
1222
|
+
nativeMessages?: boolean;
|
|
1221
1223
|
/** Usage % threshold for new-session auto-pick. Default 80. 0 = disabled (affinity/active only). */
|
|
1222
1224
|
autoSwitchThreshold?: number;
|
|
1223
1225
|
/** New-session rotation strategy. Default quota (today's behaviour). */
|
package/src/types/provider.ts
CHANGED
|
@@ -68,15 +68,15 @@ export interface TransientRetryPolicy {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* Opt-in replacement of a
|
|
71
|
+
* Opt-in replacement of a Responses send whose upstream connection closed while the
|
|
72
72
|
* caller had observed nothing (`providers.<name>.retryOnReset`).
|
|
73
73
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* default.
|
|
74
|
+
* Native Responses covers pre-header resets and post-header SSE carrying only control events.
|
|
75
|
+
* Generic translated dispatch covers initial and rebuilt pre-header sends, sharing the same
|
|
76
|
+
* grant and send budget; adapter-owned transports and translated post-header failures are excluded.
|
|
77
|
+
* Disabled unless present; `{}` opts in. Only self-contained requests qualify (see
|
|
78
|
+
* `src/server/responses/reset-replay.ts`). Replacement inference may still be billed if the
|
|
79
|
+
* origin had already started the first one, so this is opt-in rather than default.
|
|
80
80
|
*/
|
|
81
81
|
export interface ResetReplayPolicy {
|
|
82
82
|
/** Master switch. Presence of the object also enables the policy (default true). */
|
|
@@ -1010,9 +1010,9 @@ export interface OcxProviderConfig {
|
|
|
1010
1010
|
*/
|
|
1011
1011
|
transientRetryOn5xx?: TransientRetryPolicy;
|
|
1012
1012
|
/**
|
|
1013
|
-
* Opt-in replacement of
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1013
|
+
* Opt-in replacement of self-contained Responses sends (`providers.<name>.retryOnReset`).
|
|
1014
|
+
* Disabled unless present; `{}` opts in. Native sends and generic translated initial/rebuilt
|
|
1015
|
+
* pre-header sends share the grant/budget; adapter-owned and translated post-header failures are excluded.
|
|
1016
1016
|
*/
|
|
1017
1017
|
retryOnReset?: ResetReplayPolicy;
|
|
1018
1018
|
/**
|
package/src/update/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { manualUpdateFailureGuidance } from "./update-failure-guidance.mjs";
|
|
2
3
|
import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "./stop-contract.mjs";
|
|
3
4
|
import { proxyIdentityAt } from "../server/proxy-liveness";
|
|
4
5
|
import { probeProxyLiveness } from "./proxy-liveness-probe.mjs";
|
|
@@ -922,7 +923,7 @@ export async function runUpdate(): Promise<void> {
|
|
|
922
923
|
spawnSync(process.execPath, [postUpdateLauncher, "tray", "start"], { stdio: "ignore", windowsHide: true, env: mutation.unprivilegedEnvironment() });
|
|
923
924
|
}
|
|
924
925
|
await recoverStoppedRuntime("package update failed");
|
|
925
|
-
console.error(`\n⚠️ Update failed (${bin} exit ${r.status ?? "?"}).
|
|
926
|
+
console.error(`\n⚠️ Update failed (${bin} exit ${r.status ?? "?"}). ${manualUpdateFailureGuidance({ bin, args: cmdArgs, owner }).join("\n")}`);
|
|
926
927
|
return 1;
|
|
927
928
|
}
|
|
928
929
|
} catch (error) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export function manualUpdateFailureGuidance(command: {
|
|
2
|
+
bin: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
owner?: import("./pnpm-global-install.mjs").PnpmGlobalOwner;
|
|
5
|
+
platform?: NodeJS.Platform;
|
|
6
|
+
}): string[];
|
|
1
7
|
export function npmUpdateFailureGuidance(failure: {
|
|
2
8
|
phase?: string;
|
|
3
9
|
rolledBack?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What to tell the operator after a failed
|
|
2
|
+
* What to tell the operator after a failed self-update (#5624).
|
|
3
3
|
*
|
|
4
4
|
* The transactional updater (`transactional-install.mjs`) either leaves the live package
|
|
5
5
|
* untouched, rolls it back, or — only on a double fault — leaves it moved aside with a recovery
|
|
@@ -10,6 +10,28 @@
|
|
|
10
10
|
* Plain ESM with no Bun APIs: the Node launcher (`bin/ocx.mjs`) imports it.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { pnpmGlobalCommandArgs } from "./pnpm-global-install.mjs";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Manual replacement must wait for recovery and stop the runtime through its owner first.
|
|
17
|
+
* @param {{ bin: string; args: string[]; owner?: import("./pnpm-global-install.mjs").PnpmGlobalOwner; platform?: NodeJS.Platform }} command
|
|
18
|
+
* @returns {string[]}
|
|
19
|
+
*/
|
|
20
|
+
export function manualUpdateFailureGuidance({ bin, args, owner, platform = process.platform }) {
|
|
21
|
+
const windows = platform === "win32";
|
|
22
|
+
const quote = value => /^[a-zA-Z0-9_@./:=-]+$/.test(value) ? value
|
|
23
|
+
: "'" + value.replaceAll("'", windows ? "''" : "'\\''") + "'";
|
|
24
|
+
const commandBin = owner ? owner.commandPath : bin;
|
|
25
|
+
const commandArgs = owner ? pnpmGlobalCommandArgs(args, owner) : args;
|
|
26
|
+
const install = (windows ? "& " : "") + [commandBin, ...commandArgs].map(quote).join(" ");
|
|
27
|
+
return [
|
|
28
|
+
"Next: run 'ocx status' and let any in-progress recovery finish.",
|
|
29
|
+
"If a proxy is running, stop it through its owner ('ocx stop', the owning service, or the desktop app) and confirm it has stopped before installing.",
|
|
30
|
+
(windows ? "Then run in PowerShell: " : "Then run: ") + install,
|
|
31
|
+
"After installation completes, restart through the owning service ('ocx service restart') or desktop app; run 'ocx start' if unmanaged.",
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
13
35
|
/** Phases in which the live package was never touched. */
|
|
14
36
|
const UNTOUCHED_PHASES = new Set(["stage", "verify", "swap-backup"]);
|
|
15
37
|
|
|
@@ -18,14 +40,17 @@ const UNTOUCHED_PHASES = new Set(["stage", "verify", "swap-backup"]);
|
|
|
18
40
|
* @returns {{ previousVersionKept: boolean; lines: string[] }}
|
|
19
41
|
*/
|
|
20
42
|
export function npmUpdateFailureGuidance({ phase, rolledBack, pkgName, version, tag }) {
|
|
21
|
-
const
|
|
43
|
+
const manual = manualUpdateFailureGuidance({
|
|
44
|
+
bin: "npm", args: ["install", "-g", "--allow-scripts=bun", pkgName + "@" + (version || tag || "latest")],
|
|
45
|
+
});
|
|
22
46
|
const kept = UNTOUCHED_PHASES.has(phase ?? "") || rolledBack === true;
|
|
23
47
|
if (!kept) {
|
|
24
48
|
return {
|
|
25
49
|
previousVersionKept: false,
|
|
26
50
|
lines: [
|
|
27
51
|
"The previous version was moved aside and could not be put back automatically.",
|
|
28
|
-
"Next: run the \"restore\" command recorded in .ocx-recovery.json next to the package, or
|
|
52
|
+
"Next: run the \"restore\" command recorded in .ocx-recovery.json next to the package, or follow the manual reinstall steps below.",
|
|
53
|
+
...manual,
|
|
29
54
|
],
|
|
30
55
|
};
|
|
31
56
|
}
|
|
@@ -33,8 +58,8 @@ export function npmUpdateFailureGuidance({ phase, rolledBack, pkgName, version,
|
|
|
33
58
|
previousVersionKept: true,
|
|
34
59
|
lines: [
|
|
35
60
|
"The previous version is still installed.",
|
|
36
|
-
"Next: run 'ocx update' again. If it fails the same way,
|
|
37
|
-
|
|
61
|
+
"Next: run 'ocx update' again. If it fails the same way, reinstall manually:",
|
|
62
|
+
...manual,
|
|
38
63
|
],
|
|
39
64
|
};
|
|
40
65
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.codex-account-controls{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:12px;min-width:0;display:flex}.codex-account-auto-switch{flex:none;align-items:center;gap:7px;min-width:0;display:flex}.codex-account-auto-switch-label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);white-space:nowrap}.codex-account-auto-switch-input-wrap{align-items:stretch;display:inline-flex;position:relative}.codex-account-auto-switch-input{width:76px;height:30px;font-size:var(--text-label);text-align:right;padding:4px 38px 4px 8px}.codex-account-auto-switch-unit{color:var(--muted);font-size:var(--text-label);pointer-events:none;position:absolute;top:50%;right:25px;transform:translateY(-50%)}.codex-account-auto-switch-input-wrap .ocx-stepper{width:22px}.codex-account-auto-switch-toggle{transform-origin:50%;margin-inline:-3px;transform:scale(.8)}.quota-row--codex-credits .quota-val{white-space:nowrap}.quota-compact:has(>.quota-row--codex-credits){grid-template-columns:minmax(34px,max-content) max-content minmax(34px,max-content) minmax(38px,max-content) minmax(58px,1fr) minmax(30px,max-content);column-gap:8px}.quota-compact:has(>.quota-row--codex-credits)>*{grid-column:1/-1}.quota-compact:has(>.quota-row--codex-credits)>.quota-row:not(.quota-row--credits){grid-template-columns:subgrid}.codex-auth-credits-toggle{align-items:center;gap:var(--space-2);white-space:nowrap;display:inline-flex}.codex-auth-credits-toggle__label{font-size:var(--text-label);color:var(--muted)}.codex-credit-spend{align-items:center;gap:var(--space-2);white-space:nowrap;display:inline-flex}.codex-credit-spend .toggle[aria-pressed=mixed] .toggle-knob{transform:translate(8px,-50%)}.codex-account-credits{align-items:center;gap:7px;display:inline-flex}.codex-account-credits__label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);white-space:nowrap}.codex-account-credits__toggle{transform-origin:50%;margin-inline:-3px;transform:scale(.8)}.kiro-device-dialog{max-width:var(--prose-measure);border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--surface);width:100%;color:var(--text);padding:var(--space-6)}.kiro-device-dialog::backdrop{background:var(--glass-rail)}.kiro-login-choices{gap:var(--space-2);margin-block:var(--space-4);display:grid}.kiro-login-choices .btn{min-height:var(--control-touch);justify-content:flex-start}.kiro-device-code{align-items:center;gap:var(--space-3);margin-block:var(--space-4);flex-wrap:wrap;display:flex}.kiro-device-code-value{font-family:var(--font-code);font-size:var(--text-title);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-wide)}.kiro-device-destination{overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.kiro-device-actions{justify-content:flex-end;gap:var(--space-2);margin-top:var(--space-4);display:flex}.main-inner:has(.claude-page .claudecode-workspace-shell){max-width:980px}.claude-page .page-tabs{margin-bottom:var(--space-5)}.claude-panel-lead{color:var(--muted);font-size:var(--text-label);line-height:var(--leading-body);max-width:var(--prose-measure);margin:0}.claude-page .pwi-auth-body:has(>.pwi-auth-status-row .pwi-auth-dot--off)>.anthropic-pool-card{order:1}.claude-page .pwi-auth-status-row>.pwi-auth-actions{margin-top:0}.claude-account-empty{padding:var(--space-12) var(--space-5)}.claude-account-empty p{max-width:48ch;margin:0 auto var(--space-4);text-wrap:balance}.claude-account-empty-actions{justify-content:center;gap:var(--space-2);display:flex}.claude-account-empty .btn svg{color:currentColor;width:14px;height:14px;margin:0}.claude-account-empty-hint{max-width:560px;margin:var(--space-4) auto 0;text-align:left}.claude-account-empty-hint svg{width:14px;height:14px;margin:0}.claudecode-connection-card{margin-bottom:var(--space-4)}.claudecode-workspace-shell .setting-controls>.custom-select{text-align:right}.claude-page .claude-status-bar{z-index:8;box-shadow:var(--shadow-sm);flex-wrap:wrap;padding:6px 8px 6px 14px;position:sticky;top:12px}.claude-page .claude-status-bar>.claude-status-health{margin-left:0}.claude-status-actions{align-items:center;gap:var(--space-3);margin-left:auto;display:flex}.claude-settings{gap:var(--space-3);flex-direction:column;display:flex}.claude-settings>.notice{margin-bottom:0}.claude-settings-port{font-family:var(--font-code);font-size:var(--text-control)}.claude-intercept-start>[role=status]{justify-content:space-between;align-items:center;gap:var(--space-4);color:var(--muted);font-size:var(--text-label);line-height:var(--leading-body);flex:1;display:flex}.claude-intercept-start .btn{flex-shrink:0}.claude-status-pending.data-surface-skeleton__block{border-radius:var(--radius-pill);width:64px;height:20px;min-height:0;display:inline-block}.remote-link-page{gap:var(--space-4);display:grid}.remote-link-page .page-head{align-items:flex-start}.remote-link-page .page-sub{max-width:var(--prose-measure);margin:0}.remote-link-panel{gap:var(--space-4);display:grid}.remote-link-off-preview{min-height:260px;position:relative;overflow:hidden}.remote-link-off-preview:after{content:"";pointer-events:none;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);background:color-mix(in srgb, var(--bg) 24%, transparent);position:absolute;inset:0}.remote-link-preview-content{gap:var(--space-3);filter:grayscale();opacity:.64;-webkit-user-select:none;user-select:none;display:grid}.remote-link-preview-row{justify-content:space-between;align-items:center;gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);display:flex}.remote-link-preview-lines{gap:var(--space-2);width:min(55%,300px);display:grid}.remote-link-preview-lines span{border-radius:var(--radius-pill);background:var(--border);height:8px;display:block}.remote-link-switch-row{z-index:1;justify-content:space-between;align-items:center;gap:var(--space-4);display:flex;position:relative}.remote-link-switch{width:var(--control-touch);height:var(--control-md);border:1px solid var(--border);border-radius:var(--radius-pill);background:var(--toggle-off-bg);cursor:pointer;padding:3px}.remote-link-switch:after{content:"";background:var(--toggle-dot-color);width:24px;height:24px;transition:transform var(--motion-fast) ease;border-radius:50%;display:block}.remote-link-switch[aria-checked=true]{background:var(--toggle-on-bg)}.remote-link-switch[aria-checked=true]:after{transform:translate(16px)}.remote-link-switch:focus-visible,.remote-link-role-card:focus-visible,.remote-link-sheet button:focus-visible,.remote-link-sheet a:focus-visible,.remote-link-row button:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px}.remote-link-role-grid{gap:var(--space-3);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.remote-link-role-card{min-height:132px;padding:var(--space-4);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);color:var(--text);text-align:left;cursor:pointer}.remote-link-role-card:hover{background:var(--raised-hover)}.remote-link-role-card[aria-disabled=true]{color:var(--muted);cursor:not-allowed;opacity:.72}.remote-link-role-card[aria-disabled=true]:hover{background:var(--raised)}.remote-link-role-card[aria-checked=true]{border-color:var(--text);box-shadow:0 0 0 1px var(--text)}.remote-link-role-card strong,.remote-link-role-card span{display:block}.remote-link-role-card span{margin-top:var(--space-2);color:var(--muted);font-size:var(--text-label)}.remote-link-toolbar{justify-content:space-between;align-items:center;gap:var(--space-3);display:flex}.remote-link-status{align-items:center;gap:var(--space-2);color:var(--muted);font-size:var(--text-label);display:inline-flex}.remote-link-status:before{content:"";background:var(--faint);border-radius:50%;flex:none;width:8px;height:8px}.remote-link-status[data-state=connected]:before{background:var(--green)}.remote-link-status[data-state=reconnecting]:before{background:var(--amber)}.remote-link-status[data-state=failed]:before{background:var(--red)}.remote-link-status[data-state=connecting]:before{background:var(--amber)}.remote-link-children{gap:var(--space-2);display:grid}.remote-link-row{gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);grid-template-columns:minmax(0,1fr) auto;align-items:center;display:grid}.remote-link-row-main{gap:var(--space-2);min-width:0;display:grid}.remote-link-row-meta{gap:var(--space-3);color:var(--muted);font-size:var(--text-caption);flex-wrap:wrap;display:flex}.remote-link-row .btn{min-height:var(--control-touch)}.remote-link-error{color:var(--red)}.remote-link-hint{margin-top:var(--space-1);color:var(--muted);font-size:var(--text-label);overflow-wrap:anywhere;display:block}.remote-link-info{color:var(--muted);font-size:var(--text-label)}.remote-link-restart{gap:var(--space-2);padding:var(--space-4);border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);display:grid}.remote-link-restart p{color:var(--muted);margin:0}.remote-link-fingerprint{padding:var(--space-3);overflow-wrap:anywhere;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);font-family:var(--font-code);font-size:var(--text-label);margin:0}.remote-link-workspace-card{justify-content:space-between;align-items:center;gap:var(--space-4);display:flex}.remote-link-workspace-card p{margin:var(--space-1) 0 0;color:var(--muted);font-size:var(--text-label)}.remote-link-sheet{width:min(620px, calc(100vw - var(--space-4)));max-height:min(760px, calc(100dvh - var(--space-4)));padding:var(--space-6);border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--bg);color:var(--text);box-shadow:var(--shadow);margin:auto;overflow:auto}.remote-link-sheet::backdrop{background:color-mix(in srgb, var(--text) 24%, transparent)}.remote-link-sheet-head{justify-content:space-between;align-items:flex-start;gap:var(--space-3);display:flex}.remote-link-sheet-head h3{font-size:var(--text-title);margin:0}.remote-link-sheet-body{gap:var(--space-4);margin-top:var(--space-5);display:grid}.remote-link-sheet pre{white-space:pre-wrap;overflow-wrap:anywhere;font-family:var(--font-code);font-size:var(--text-label)}.remote-link-candidates{gap:var(--space-2);display:grid}.remote-link-candidate{justify-content:space-between;align-items:center;gap:var(--space-3);min-height:var(--control-touch);padding:var(--space-2) var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);color:var(--text);cursor:pointer;text-align:left;display:flex}.remote-link-candidate:hover{background:var(--raised-hover)}.remote-link-form{gap:var(--space-2);display:grid}.remote-link-form .field-label{margin-bottom:0}.remote-link-sheet-actions{justify-content:flex-end;gap:var(--space-2);flex-wrap:wrap;display:flex}.remote-link-confirm-dialog{width:min(460px, calc(100vw - var(--space-4)));padding:var(--space-5);border:1px solid var(--border);border-radius:var(--radius);background:var(--bg);color:var(--text);box-shadow:var(--shadow);margin:auto}.remote-link-confirm-dialog::backdrop{background:color-mix(in srgb, var(--text) 24%, transparent)}.remote-link-confirm-dialog h3{font-size:var(--text-subtitle);margin:0}.remote-link-confirm-dialog p{color:var(--muted)}@media (width<=620px){.remote-link-role-grid{grid-template-columns:1fr}.remote-link-workspace-card,.remote-link-switch-row{flex-direction:column;align-items:stretch}.remote-link-switch{align-self:flex-start}.remote-link-sheet{width:calc(100vw - var(--space-2));border-radius:var(--radius-lg) var(--radius-lg) 0 0;max-height:88dvh;margin:auto auto 0}}@media (prefers-reduced-motion:reduce){.remote-link-page *,.remote-link-page :before,.remote-link-page :after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}.quota-summary-bar{z-index:var(--z-sticky);border-bottom:1px solid var(--border);background:var(--bg);min-height:34px;font-size:var(--text-label);align-items:center;gap:12px;padding:4px 16px;display:flex;position:sticky;top:0}.quota-summary-scroller{flex:1;align-items:center;gap:2px;min-width:0;display:flex}.quota-summary-list{overscroll-behavior-x:contain;scrollbar-width:none;flex-wrap:nowrap;flex:auto;align-items:center;gap:4px;min-width:0;margin:0;padding:3px;list-style:none;display:flex;overflow:auto hidden}.quota-summary-list::-webkit-scrollbar{display:none}.quota-summary-item{flex:none}.quota-summary-scroll{border:1px solid var(--border);background:var(--surface);width:22px;height:22px;color:var(--text);font:inherit;cursor:pointer;border-radius:999px;flex:none;place-items:center;padding:0;font-weight:600;line-height:1;display:inline-grid}.quota-summary-scroll:hover:not([aria-disabled=true]){background:var(--bg)}.quota-summary-scroll[aria-disabled=true]{color:var(--muted);opacity:.45;cursor:default}.quota-summary-scroll:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-chip{color:var(--text);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:999px;align-items:center;gap:6px;padding:3px 8px;text-decoration:none;display:inline-flex}.quota-summary-chip:hover,.quota-summary-chip--open{border-color:var(--border)}.quota-summary-chip:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-name{color:var(--muted)}.quota-summary-pct{font-variant-numeric:tabular-nums;font-weight:600}.quota-summary-flag{width:14px;height:14px;color:var(--bg);font-size:var(--text-micro);border-radius:50%;place-items:center;font-weight:700;display:inline-grid}.quota-summary-item--warn .quota-summary-chip{background:var(--amber-soft)}.quota-summary-item--warn .quota-summary-pct{color:var(--amber)}.quota-summary-item--warn .quota-summary-flag{background:var(--amber)}.quota-summary-item--critical .quota-summary-chip{border-color:var(--red);background:var(--red-soft)}.quota-summary-item--critical .quota-summary-pct{color:var(--red)}.quota-summary-item--critical .quota-summary-flag{background:var(--red)}.quota-summary-popover{top:calc(var(--qs-pop-top,0) * 1px);left:calc(var(--qs-pop-left,0) * 1px);z-index:var(--z-popover);border:1px solid var(--border);background:var(--surface);border-radius:8px;min-width:260px;max-width:calc(100% - 16px);padding:10px 12px;position:fixed;box-shadow:0 8px 24px #00000024}.quota-summary-popover:before{content:"";left:calc(var(--qs-bridge-left,0) * 1px - 1px);right:calc(var(--qs-bridge-right,0) * 1px - 1px);height:calc((var(--qs-pop-gap,4) + 1) * 1px);position:absolute;bottom:100%}.quota-summary-popover-head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:6px;display:flex}.quota-summary-badge{font-size:var(--text-caption);border-radius:999px;padding:1px 6px}.quota-summary-badge--warn{color:var(--amber);background:var(--amber-soft)}.quota-summary-badge--critical{color:var(--red);background:var(--red-soft)}.quota-summary-table{border-collapse:collapse;width:100%}.quota-summary-table th,.quota-summary-table td{text-align:left;white-space:nowrap;padding:3px 0;font-weight:400}.quota-summary-table td.quota-summary-row-pct{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;padding:3px 12px;font-weight:600}.quota-summary-row-reset{color:var(--muted);white-space:nowrap}.quota-summary-table th[scope=row]{white-space:normal;overflow-wrap:anywhere}.quota-summary-row--warn .quota-summary-row-pct{color:var(--amber)}.quota-summary-row--critical .quota-summary-row-pct{color:var(--red)}.quota-summary-popover-foot{color:var(--muted);font-size:var(--text-caption);flex-wrap:wrap;justify-content:space-between;gap:4px 12px;margin-top:6px;display:flex}.quota-summary-updated{color:var(--muted);font-size:var(--text-caption);white-space:nowrap;flex-shrink:0}.quota-summary-popover-link{color:var(--text);text-underline-offset:2px;text-decoration:underline}.quota-summary-popover-link:focus-visible{outline:2px solid var(--text);outline-offset:1px}.quota-summary-updated--stale{color:var(--amber)}.main:has(>.quota-summary-bar):has(>.main-inner--combos .combos-workspace-shell){flex-direction:column;height:100dvh;display:flex}.main:has(>.quota-summary-bar)>.main-inner.main-inner--combos:has(.combos-workspace-shell){flex:auto;height:auto;min-height:0}@media (width<=760px){.quota-summary-bar{padding:4px 10px;position:static}.quota-summary-popover{top:calc(var(--qs-pop-top,0) * 1px);min-width:0;left:8px;right:8px}.main:has(>.quota-summary-bar):has(>.main-inner--combos .combos-workspace-shell){height:100%;min-height:0}}.app{--titlebar-h:40px;--tl-inset:80px;--chrome-clear:52px}.app--macos{--chrome-clear:124px;--sidebar-column:max(232px, calc(var(--tl-inset) + 52px))}.sidebar-top{z-index:calc(var(--z-overlay,30) + 1);width:232px;height:var(--titlebar-h,40px);border-bottom:1px solid var(--border);background:var(--glass-rail);-webkit-backdrop-filter:var(--glass-blur);-webkit-user-select:none;user-select:none;align-items:center;padding:0 10px 0 14px;display:flex;position:fixed;top:0;left:0}.app--macos .sidebar-top{width:var(--sidebar-column);padding-left:var(--tl-inset,80px)}.sidebar{padding-top:calc(var(--titlebar-h,40px) + 18px)}.sidebar-collapse{border-radius:var(--radius-sm);width:28px;height:28px;color:var(--muted);cursor:pointer;transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.sidebar-collapse:hover{background:var(--accent-soft);color:var(--text)}.sidebar-collapse:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px}.sidebar-collapse svg{width:18px;height:18px}.main-top{z-index:var(--z-sticky);height:var(--titlebar-h,40px);background:var(--bg);border-bottom:1px solid var(--border);-webkit-user-select:none;user-select:none;align-items:stretch;display:flex;position:sticky;top:0}.main-top>.quota-summary-bar{border-bottom:none;flex:auto;min-width:0;min-height:0;padding:0 16px;position:static}.main:has(>.main-top):has(>.main-inner--combos .combos-workspace-shell){flex-direction:column;height:100dvh;display:flex}.main:has(>.main-top)>.main-inner.main-inner--combos:has(.combos-workspace-shell){flex:auto;height:auto;min-height:0}@media (width>=761px){.app{transition:grid-template-columns .16s}.app--macos.app--reduced-zoom{transition:none}.app--macos:not(.app--nav-collapsed){grid-template-columns:var(--sidebar-column) minmax(0, 1fr)}.app.app--nav-collapsed{grid-template-columns:0 1fr}.app--nav-collapsed .sidebar{display:none}.app--nav-collapsed .main{grid-column:2}.app--nav-collapsed .sidebar-top{-webkit-backdrop-filter:none;background:0 0;border-bottom:none;width:auto;margin:0;padding:0 12px}.app--macos.app--nav-collapsed .sidebar-top{padding-left:var(--tl-inset,80px)}.app--nav-collapsed .main-top,.app--nav-collapsed .main>.quota-summary-bar{padding-left:var(--chrome-clear,52px)}}@media (width<=760px){.sidebar-top{display:none}.main-top{z-index:auto;position:static}.main:has(>.main-top):has(>.main-inner--combos .combos-workspace-shell){height:100%;min-height:0}.app--macos .mobile-topbar{padding-left:var(--tl-inset,80px)}.app--macos .sidebar.open{padding-top:calc(var(--titlebar-h,40px) + 18px)}}@media (width<=320px){.app--macos .mobile-topbar{flex-wrap:wrap}.app--macos .mobile-topbar-actions{width:calc(100% + var(--tl-inset,80px));margin-left:calc(-1 * var(--tl-inset,80px));justify-content:flex-end}}
|