diff --git a/.gitignore b/.gitignore index ce10233dcc..f32218aafd 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ tests/**/.tmp-* # `git add` three separate times and reached `dev` once — see # tests/ci-workflows/repo-hygiene.test.ts, which fails if any path here becomes tracked again. go/ + +# Rust native helpers keep their reproducible sources and lockfile in git, never local artifacts. +native/**/target/ diff --git a/.npmignore b/.npmignore index acf3a0c4d0..cfbe1d3750 100644 --- a/.npmignore +++ b/.npmignore @@ -19,6 +19,7 @@ gui/eslint.config.* gui/bun.lock # misc +native/remote-workspace-helper/target/ *.test.ts *.map .DS_Store diff --git a/devlog/_plan/260912_operations/020_listeners.md b/devlog/_plan/260912_operations/020_listeners.md index 393ba74e8a..8ac8fbe3bf 100644 --- a/devlog/_plan/260912_operations/020_listeners.md +++ b/devlog/_plan/260912_operations/020_listeners.md @@ -11,3 +11,5 @@ MODIFY existing tests/server/ports.test.ts and tests/server/loopback-listener-in MODIFY directly relevant structure/runtime.md, structure/config.md, structure/ops/service-and-sidecars.md and public hub/loopback guidance; link the canonical contract from other mapped ownership docs only where applicable. Review all conditional activation rows on hosted CI. Source inspection is not runtime proof. Design OPS-LIST-01..04 accepted with amendments. NEW tests/cli/cli-start-auxiliary-bind.test.ts, registered in both test-layout files, uses isolated CLI subprocess to cover soft and hard-pinned startup: failure names auxiliary key/address, exit nonzero, no public repick/wait branch. Existing management rollback fixture occupies management first then selects distinct public/loopback ports. Warning helper runs on all three load return paths plus read-only diagnostics; controls cover absent and valid-disabled entries and malformed secret-shaped input without echoing raw values. + +Follow-up090 validates raw managementIngress against the existing shared strict managementIngressSchema; disappearance of the entire hub block is not evidence that the ingress itself was malformed. diff --git a/devlog/_plan/260912_operations/040_client_usage.md b/devlog/_plan/260912_operations/040_client_usage.md index 389c303f8b..e582767c44 100644 --- a/devlog/_plan/260912_operations/040_client_usage.md +++ b/devlog/_plan/260912_operations/040_client_usage.md @@ -8,6 +8,22 @@ MODIFY existing client/hub API owner only where the read contract requires it; e MODIFY public connected-client/CLI usage guide and structure/runtime.md / gui-and-management-api.md canonical scope. Any pre-disclosure details stay in scratch. Hosted regressions only; local execution NOT RUN. -Accepted design OPS-USAGE-02/03/04. NEW tests/server/hub-usage.test.ts and tests/clients/hub-usage.test.ts with entries in scripts/test-layout/layout.json explicit and tests/fixtures/test-layout-expected.json; NEW tests/cli/cli-usage-hub.test.ts. Tests use two client keys, loopback and remote admissions, invalid state, custom window, unsupported endpoint, bad response, expired/revoked credentials. Full implementation follows source confirmation before B. +Accepted design OPS-USAGE-02/03/04. NEW tests/server/hub-usage.test.ts and tests/clients/client-hub-usage.test.ts with entries in scripts/test-layout/layout.json explicit and tests/fixtures/test-layout-expected.json; NEW tests/cli/cli-usage-hub.test.ts. Tests use two client keys, loopback and remote admissions, invalid state, custom window, unsupported endpoint, bad response, expired/revoked credentials. Full implementation follows source confirmation before B. Reflection amendments: getFilteredUsageAggregate in src/server/management/usage-aggregate-cache.ts is the aggregation owner. Client DTO preserves #4111 incomplete flags; CLI suppresses advice to remove filters for account totals because that scope never exports accounts. Public files: docs-site/src/content/docs/guides/remote-hub.md and reference/cli/agents.md. All three new tests register in scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json. + +P revalidation after totals28c13d0c09: this slice depends on its usageIncomplete aggregate contract, so publish an ordinary child PR based on operations-totals. Retire4343 review follow-up was prioritized by explicit user steering; it is now source-reviewed and resolved. + +Concrete DTO: version1/source hub/scope client; range/surface/since/until/customWindow/generatedAt, numeric summary fields consumed by CLI, provider/model/day cost rows, and provider/model/matched/comboOverlap filter echo. No accounts, raw entries, apiKeyId or arbitrary spread fields cross the wire. NEW remote/hub-usage.ts owns a stripping Zod schema, capped arrays/string sizes and1MiB response bound; server projects through it and client parses through it. Incomplete flags retain positive-only semantics. No persistence or cache on client. Existing getFilteredUsageAggregate owns server cache keyed by authenticated key; no route-global cache. + +Handler accepts GET/v1/usage only, requires dedicated data key and configured admission even for loopback; no management/API env key. Reject unknown or duplicate query keys, caller apiKeyId, invalid range/surface/window, and noncanonical (blank/padded) authenticated key IDs before aggregation because the existing filtered cache trims IDs. Check origin and hub role. Recheck matched current credential/key identity after awaited scan before returning; revocation/rotation changes cannot publish a stale authority response. Serialize bounded allowlist DTO or explicit error, never a partial silent result. + +CLI reads connection state and matching service token fingerprint, sends only data credential to configured serverUrl via existing fetchBounded/boundedText helpers, retains redirect refusal and deadlines. Invalid/mismatched connection/token fails with no local fallback. Confirm owner remains the same after the read before printing. Human header names hub source/client scope and suppresses account-total advice; standalone runtimeRequest remains unchanged. + +Hosted tests: actual server two keysA/B and loopback auth; caller keyID rejected; absent/environment/admin/bad keys rejected; unknown/duplicate params and invalid window; provider filters/custom window; malformed response/too-large/redirect/oldHub/offline; CLI connected versus standalone and token mismatch. Test paths in this doc register in both layout files. No local tests. Unpublished security analysis remains .tmp/operations/040_client_usage_private.md. + +Reflection closure: post-read CLI validates both owner triple AND current connection/file token fingerprints; sameClientConnectionOwner alone omits fingerprint. Every nested DTO object strips unknown fields; the1MiB check uses serialized UTF-8 bytes in addition to array/string caps. + +B scope refinement: reuse resolveDataPlaneAdmissionSecret directly; no resolver logic change necessary; auth-cors.ts AUTH_MATRIX gets the new endpoint row and tests/server/api-key-attribution.test.ts drives its real GET cells. Client test basename is client-hub-usage.test.ts to avoid the registry basename collision with server/hub-usage.test.ts. + +Follow-up100: new fetchHubUsage requires HTTPS or supported loopback HTTP before credential headers, uses request cache:no-store, and retains server cache-control:no-store. diff --git a/devlog/_plan/260912_operations/050_pairing.md b/devlog/_plan/260912_operations/050_pairing.md index 2b05bff2ba..dacb098a50 100644 --- a/devlog/_plan/260912_operations/050_pairing.md +++ b/devlog/_plan/260912_operations/050_pairing.md @@ -4,10 +4,28 @@ Class C3; dependency roadmap. Reuse existing connected-client state and browser- MODIFY owning dashboard pending-auth component and bootstrap state: distinguish a reachable connected machine awaiting hub browser authentication from a stopped standalone proxy. Show configured hub identity/origin, explain that machine enrollment and browser session are separate, offer the current origin-specific existing pairing/authentication action. Preserve revoked/expired/unreachable states and their existing retry actions; do not suggest ocx start while the local runtime is reachable. Derive the next action from current origin + configured hub instead of a hardcoded localhost URL. No credentials appear in visible copy/URLs. -MODIFY all gui/src/i18n locale dictionaries with meaningful labels. Extend existing pending-auth/dashboard tests for local origin, remote hub origin, pending, authenticated, expired/revoked and unavailable standalone; positive browser auth transitions into connected dashboard. Exact files: gui/src/App.tsx, api.ts, pages/dashboard-core-poll.ts, pages/use-dashboard-data.ts and pages/Dashboard.tsx consume a classified authentication/error state instead of a boolean. Existing connect-pairing.ts and connect-pairing-transport.ts own hub identity and origin-specific action. Define the error classification in api.ts at response ingress; consume in polling and Dashboard; reset on authenticated success and pairing completion. No persistence/serialization for this UI state. Keep cached data with stale labeling when auth fails; do not erase a known hub into standalone offline. Public hub/browser-pairing guidance is updated with the same distinction. No service restart or live auth reconfiguration. +MODIFY all gui/src/i18n locale dictionaries with meaningful labels. Extend existing pending-auth/dashboard tests for local origin, remote hub origin, pending, authenticated, expired/revoked and unavailable standalone; positive browser auth transitions into connected dashboard. Exact files: gui/src/App.tsx, api.ts, pages/dashboard-core-poll.ts, pages/use-dashboard-data.ts and pages/Dashboard.tsx consume a classified authentication/error state instead of a boolean. Existing connect-pairing.tsx and connect-pairing-transport.ts own hub identity and origin-specific action. Define the error classification in api.ts at response ingress; consume in polling and Dashboard; reset on authenticated success and pairing completion. No persistence/serialization for this UI state. Keep cached data with stale labeling on non-auth read failures; hide it when authentication or permission is denied; do not erase a known hub into standalone offline. Public hub/browser-pairing guidance is updated with the same distinction. No service restart or live auth reconfiguration. Hosted component suite and screenshot artifact of the rendered pending state required for final delivery; local GUI tests/build NOT RUN. Static source or mockup is not rendered application evidence. Accepted OPS-PAIR-01/02. Cases include browser session expiry and post-pairing refresh, local and hub origin guidance, code versus API/admin-key explanation, and operator handoff text. Prefer existing component tests; new test files only where needed. Reflection amendments: reuse existing api.ts SESSION_UNAVAILABLE_EVENT and App sharedSessionReady; subscribe in App, emit on terminal 401 expiry (not aborted requests), reset/read refresh on successful pairing. Do not create duplicate auth state. Poll classification and pairing errors distinguish HTTP auth refusal, transport/network, and invalid responses; aborted work does not show a failure. + +P revalidation at81f0c78d7a: same App, Dashboard, pairing and API owners remain. This independent branch starts from refresheddev; previous usage-transportD directs pairing after the user-requested source repairs. + +Concrete delta: App subscribes to SESSION_UNAVAILABLE_EVENT for the shared plane and derives readiness from hasApiSession; ignore a late notice while a newer session is present. Pairing success increments a dashboard refresh epoch and marks ready. Pass connected/authenticationPending into Dashboard. Hide protected dashboard content while authentication is pending; keep known data with a stale notice only on non-auth read failures. In fetchDashboardOverview distinguish 401(auth), 403(denied), other non-OK(request), invalid JSON/shape(invalid), and transport failure(unavailable); aborted polls propagate without publishing an error. Hook exposes failure and overview refresh without a second authentication store. Only standalone transport unavailability may show ocx start; connected/auth/invalid/request failures use relevant copy and retry. + +API wrapper emits its existing unavailable event on terminal401 only when the caller is not aborted and no newer session exists. Retain credential refresh/singleflight behavior; no new auth bypass or token persistence. Dashboard receives success epoch as a prop; useDashboardData adds it to existing useKeyedClientResource revalidation dependencies without changing resource keys or remounting. Every dashboard resource refreshes even when a settled failed/cached store survived. + +Pairing form shows target.serverOrigin, a copyable ocx gui pair --origin command for window.location.origin, instructions to run it on the hub or ask its operator, and the distinction between one-time code and API/admin keys. Reuse useCopyFeedback and existing copy labels; copy failure remains visible. Keep relay technical copy subordinate. Pairing transport gets a typed error kind (invalid-code/refused/unreachable/invalid-response), mapped to localized actionable copy while preserving pasted code; abort does not publish an error. This is process-local UI state, not a wire schema. + +Exact regressions: extend gui/tests/connect-pairing.test.ts for real App dashboard pending/authsuccess/expiry/recovery and hub/command identity; extend api-auth-deadline.test.ts for terminal notice behavior if needed; NEW gui/tests/dashboard-connection-state.test.ts for poll failure classes, cached data and no erroneous start advice. All9 locale modules get new copy. Existing Notice/buttons/tokens, variance2/motion1, dense utility layout; no decorative assets or new dependencies. Hosted built preview, inspected screenshot and browser interaction supply rendered proof later; local suites/build NOT RUN. + +Pairing lifetime precision: form keyed by target server/bootstrap identity, one AbortController per submit cancelled on unmount; transport accepts optional caller signal in addition to its existing fetch seam and checks abort before session installation. This prevents an obsolete target response from installing a session or publishing errors after its form unmounts. Keep existing request method/credential mechanics unchanged. + +A amendment: post-pairing refresh explicitly reaches each dashboard keyed resource through [apiBase, refreshEpoch] dependencies; a component remount is not treated as a cache invalidation mechanism. Regression first seeds a failed overview store, completes pairing, and requires a new authenticated health/provider read plus rendered data. + +Reflection03/05 closure:403 keeps distinct permission-denied guidance and never starts or re-pairs a running proxy merely for denied permissions. Validate HealthData status/version strings and finite nonnegative uptime; providers must be an array of objects with the required name/adapter/baseUrl strings and hasApiKey boolean, optional defaultModel string. Invalid shapes are classified invalid even with HTTP200. Unauthorized/denied content stays hidden; only nonauth read failure may show cached data with stale notice. + +Resume C repairs: hosted34682559994 found erasableSyntaxOnly constructor parameter-property and React ref analysis at createElement form. Explicit class field and JSX component preserve behavior without disabling rules. Source compound-failure repair was already published externally at4124a644; local byte-identical patch preserved before fast-forward. Hidden-document App fixture disables periodic polls, and a controlled real resource deadline verifies retained data becomes stale. All local suites/build/typecheck/install NOT RUN. diff --git a/devlog/_plan/260912_operations/060_transport.md b/devlog/_plan/260912_operations/060_transport.md index a884509d22..0b8d180f4a 100644 --- a/devlog/_plan/260912_operations/060_transport.md +++ b/devlog/_plan/260912_operations/060_transport.md @@ -5,3 +5,5 @@ Class C4; dependency roadmap. Scope #4315 and the current CHANGES_REQUESTED revi The executable security design and negative-case audit live only in ignored .tmp/operations/060_transport_private.md. That file must be completed and independently reviewed before B; no pre-disclosure reasoning is copied into public planning history. Public deliverable is the implementation, regression tests and shipped contract text only. Required review dimensions: local destination selection, redirect and proxy-environment behavior, credential separation and all current callers. Original contributor credit: Cortes Ventures . No fallback that substitutes a data credential for admin authentication. Hosted regression execution plus independent security source audit bind the final patch SHA. Review state is refreshed before handoff; this work cannot approve or merge the original PR. Local suites/build/typecheck/install NOT RUN. + +P resume revalidation at c311f9bf7f5003af29fa8e7ebc2f2b5db20267f6: original4317 still CHANGES_REQUESTED, helper and sole productioncaller unchanged. Prior pairingD directs this independent slice. Reuse direct-local-http transport and local-destinations resolver; private060 contains exact diff contract and controls. No new dependencies, service changes or fallback settings. Existing8s deadline retained. New tests/providers/opencode-management-transport.test.ts isolates real socket/proxy/redirect controls and registers in both test-layout maps. Existing opencode-cli caller test changes transport spy and checks distinct management/inference credentials and generated blocks. diff --git a/devlog/_plan/260912_operations/070_verification.md b/devlog/_plan/260912_operations/070_verification.md index e5af9101e3..03319049a6 100644 --- a/devlog/_plan/260912_operations/070_verification.md +++ b/devlog/_plan/260912_operations/070_verification.md @@ -7,3 +7,9 @@ For each independently mergeable branch: record git rev-parse HEAD, original sou A local receipt may run git diff --check and read-only hosted-result assertions; it is not a local test result. Local suites, typecheck/build/install are NOT RUN. Final behavior acceptance comes from GitHub-hosted test runs at the final SHA and independent review; author reports/old green CI are not substituted. Update ignored .tmp/operations/handoff.md as soon as each artifact exists. Include outstanding issue acceptance, original author trailers, unresolved maintainer objections, exact run links/conclusions and cycle ledger pointers. Publish template-complete PR bodies with truthful verification, screenshots for changed dashboard UI and no private investigation notes. Parent owns all integration decisions. + +P resume amendment: reconcile at pinned origin/dev db7062c37a84b12c4f59abc567d07241bf2a6042, which includes separately owned Cline/native-restore fixture repairs. No repeated rewrites. Fast-forward local lane refs to parent-published remote heads before edits; merge the pinned baseline into owned feature branches only where needed to incorporate failed-check repairs/conflicts. Never move dev/main/preview or merge PRs. Preserve shared changes and resolve only operations-owned conflicts; record any cross-lane source collision for parent. + +Listener4353 also has a documentation-only review requiring the plan to describe reuse of the already-existing managementIngressSchema. Correct020/090 wording, do not duplicate a schema. Totals4357 consumes baseline then child4373 receives that exact lower head; verify ancestry and original source patch parity. Pairing4378 incorporates baseline only once and retains all source repairs. Transport4402 is already based on repaireddev; do not rewrite its unchanged candidate for unrelated later commits. + +Final requested gate is hosted laneall on listener, cumulative usage child, pairing, and transport. Inspect live job outcomes and exacthead. New failures inside this lane become separately audited repaircycles; external owner failures are recorded without duplicate edits or baselinegreen claims. Read build artifacts from hosted GUI jobs, serve only those static files with fixture responses in isolated scratch for screenshot/interaction review, no product build/test/server locally. This is render observation, not a local suite. No liveuser service/config changes. diff --git a/devlog/_plan/260912_operations/090_listener_diagnostic.md b/devlog/_plan/260912_operations/090_listener_diagnostic.md new file mode 100644 index 0000000000..c230df5219 --- /dev/null +++ b/devlog/_plan/260912_operations/090_listener_diagnostic.md @@ -0,0 +1,7 @@ +# Precise ingress degradation diagnosis + +User intake4353 discussion3995160105. P amendment reprioritizes a source review repair before pairing; pairing source was not changed. Class C2, satisfy-spec, same tool/write bounds and no resource cap; no local suite/build/typecheck/install, no merges/services. Final behavior proof is hosted CI. + +Valid managementIngress is currently blamed when an invalid sibling makes the whole hub parse disappear. MODIFY src/config.ts: reuse the existing private managementIngressSchema in hubConfigSchema and raw-field validation; test the raw ingress with that same strict schema before issuing its field-specific warning. Do not change normalization, acceptance, port relationship validation, or whole-hub warnings. Rawvalues never printed. + +MODIFY tests/config/config-load-degrade.test.ts: valid ingress plus invalid dataPublicOrigin must warn about the actual hub sibling and not claim managementIngress invalid; preserve file bytes. Existing malformed-ingress cases still warn. Update020 and structure/config.md canonical wording. Independent source re-audit then authorized comment reply/resolution; hosted criterion remainsOPEN. diff --git a/devlog/_plan/260912_operations/100_usage_transport.md b/devlog/_plan/260912_operations/100_usage_transport.md new file mode 100644 index 0000000000..ac09181261 --- /dev/null +++ b/devlog/_plan/260912_operations/100_usage_transport.md @@ -0,0 +1,7 @@ +# Client usage credential transport + +User intake4353 plan comments3995195164 and3995195169. The new usage source is in4373, not in4353. Previous listener-diagnosticD directs this separate repair before pairing. Class C4; same scoped HOTL/tool/write bounds, no resource cap, no local suites/build/typecheck/install. Do not change unrelated hub-client operations or publish speculative analysis. + +MODIFY src/client/hub-client.ts fetchHubUsage only: after normalizeHubOrigin, use existing isPairingTransportPermitted before constructing credential headers or invoking fetchBounded. Accept HTTPS and supported numeric/localhost loopback HTTP; reject plain HTTP remote origins with an actionable static error. Add cache:no-store on the authenticated request. The server already sends cache-control:no-store; preserve it. + +MODIFY tests/clients/client-hub-usage.test.ts: remote HTTP and credentials-bearing malformed origins fail before injected transport invocation; HTTPS and each supported loopback form remain accepted; request cache mode is no-store. Existing real route test proves response header. Modify040 and publichub usage guide to state transport constraint. Independent source re-audit, reply/resolve the two authorized plan threads with4373 exacthead. Hosted cumulativetip acceptance remainsOPEN. diff --git a/devlog/_plan/260912_operations/110_resume_status.md b/devlog/_plan/260912_operations/110_resume_status.md new file mode 100644 index 0000000000..2ae5182e88 --- /dev/null +++ b/devlog/_plan/260912_operations/110_resume_status.md @@ -0,0 +1,9 @@ +# Operations resume checkpoint + +Update carry #4343 merged with exact candidate f37894711158fa8215d26bed642389148ac395f6 and successful Cross-platform CI34674523305. The already-carried stop fix is not replayed. Original issue/PR closure stays with integration coordination. + +Listener #4353, usage #4357 → #4373 and pairing #4378 remain open. Published usage source/security audits passed; hosted execution must be checked on the final cumulative tip. Prior Cline registration/native-restore fixture failures are retained as failures; current dev has a separate repair, and this unit does not duplicate its ownership. + +Pairing resumed at persisted C. The previous local compound-failure patch matched the newer remote commit byte-for-byte and was preserved before fast-forward. The subsequent fix uses an erasable explicit error field and JSX event handlers for the hosted compiler/lint failures; no checks were disabled. A hidden-document pairing fixture excludes periodic polling, and a controlled resource deadline verifies stale-data marking. Hosted execution and rendered preview remain pending. + +The OpenCode management-token and local transport change remains outstanding against original #4317 CHANGES_REQUESTED. No whole-lane completion is claimed. All local suites, focused tests, GUI tests, build, typecheck and installs are NOT RUN. No service changes or release actions were performed. diff --git a/devlog/_plan/260912_operations/120_coordinator_probe.md b/devlog/_plan/260912_operations/120_coordinator_probe.md new file mode 100644 index 0000000000..db3354b6f9 --- /dev/null +++ b/devlog/_plan/260912_operations/120_coordinator_probe.md @@ -0,0 +1,15 @@ +# Coordinator-refusal fixture diagnostics + +The Windows5 failure in run34693005384 ended the transaction child at its existing15-second deadline before result assertions. The failed head and current dev have identical scoped test/connect/lock/ACL source. The log does not identify the stalled phase, so this work adds evidence and strengthens the coordinator-specific oracle; it does not claim to repair a proven production stall. + +Class C2, satisfy-spec, triggered by parent triage assignment. Scope: tests/clients/client-connect.test.ts and this plan only. No runtime, ACL policy, unrelated fixture, or timeout-budget changes. Local suites/build/typecheck/install NOT RUN; manual hosted dispatch/rerun HOLD. Existing publication and independent model-inheriting source review remain authorized. Stop this diagnostic slice when source reviewed and published; actual Windows outcome remains open until authorized hosted execution. Original operations verification criteria remain unchanged/open in verification-resume after the cancelled-CI checkpoint. + +MODIFY the existing transaction child script: synchronously emit fixed JSON phase markers on stderr around module load, connect invocation/completion, state observation and result publication. Markers contain only an allowlisted phase and bounded nonnegative integer elapsed milliseconds. They contain no home paths, URL, credentials, error text or raw output. + +MODIFY the parent fixture: parse only those marker objects on failure before throwing ClientStateProbeError, and include only validated phase/elapsed evidence. Preserve15-second kill, successful exit requirement, output parse and all cleanup. A valid result followed by a retained child still fails. Unknown/malformed marker fields are ignored; never expose raw stderr/stdout. Existing other fixtures keep the same constructor behavior. + +MODIFY the coordinator oracle: inspect the caught cause chain for the exact CONFIG_MUTATION_LOCK_UNAVAILABLE code and expose only a boolean in fixture JSON. Assert this in addition to connected=null, calls=[], absent token/catalog and zeroed authority. An earlier lifecycle refusal must not pass as coordinator coverage. No matching on arbitrary raw error prose. + +Extend existing fixture self-checks with valid phase evidence on a retained child and malformed/unknown/secret-shaped marker controls. All original expectations remain. Independent A/C review checks marker privacy, actual reachability, timeout/cleanup retention and unchanged production source. git diff --check is whitespace evidence only. Hosted execution after HOLD must distinguish module loading, connect-internal delay and completed-result exit retention; until then no root-cause or baseline-green claim. + +Design reflection accepted: cause traversal uses a seen-object set and finite depth; connect markers distinguish entered, resolved and rejected outcomes; result_published follows serialization/output. Parent scans a bounded stderr tail and accepts only fixed phase names plus finite nonnegative integer elapsed milliseconds within a fixed cap. A valid marker followed by malformed input retains the valid evidence. These markers do not identify a particular inner ACL/lock call. diff --git a/devlog/_plan/260912_remote_workspace_carry/020_executor_runtime.md b/devlog/_plan/260912_remote_workspace_carry/020_executor_runtime.md index 550b2a5bb5..e20200c7c3 100644 --- a/devlog/_plan/260912_remote_workspace_carry/020_executor_runtime.md +++ b/devlog/_plan/260912_remote_workspace_carry/020_executor_runtime.md @@ -82,3 +82,25 @@ REMOTE-ARCH-003: Separate persisted enrollment capabilities from current connect REMOTE-ARCH-006: Use existing required private-file/Windows ACL primitives for new identity and bearer stores. Check permission setup failures and refuse loading/saving secrets when enforcement fails. Do not change global config-store behavior. Record exact selected existing helper in phase-2 P after reading the owner; no best-effort function is accepted as proof. REMOTE-ARCH-007: Codex real App Server tests depend on OCX_CODEX_BIN; Claude real integration on OCX_CLAUDE_BIN; Pi on OCX_PI_BIN. The Linux confinement case can return without execution unless OCX_REQUIRE_LINUX_REMOTE_WORKSPACE_CONFINEMENT=1 or bwrap is available. Current generic CI alone does not prove those paths. Mock tests prove lifecycle and tool-routing contracts only; native Hub isolation and executor confinement stay explicit final acceptance gaps when not activated. For each adapter separately record denied local tools, inherited plugins/hooks/config, offline refusal and teardown; inspect source plus hosted mocks, no claims of live CLI confinement from flags alone. + +## Phase-2 revalidation and exact owner choices + +Previous D: wp1 inactive foundation source cycle complete at 726ddc7fc0; final hosted proof remains wp4. Continue in child branch codex/260912-60plus-remote-runtime. Existing public exports and added host-negative coverage are retained. + +REMOTE-ARCH-004: storage modules import atomicWriteFile directly from src/config/atomic-write.ts and getConfigDir from src/config/paths.ts, avoiding the broad config.ts barrel. Device CLI orchestration retains explicit runner construction because it computes actual availability after root approval; no import-time probe exists. This is intentional sequential coupling. Server seams in phase 3 use narrow structural connection/session interfaces rather than pulling concrete remote classes into shared request types. No remote module imports server surfaces. + +REMOTE-ARCH-006 exact helpers: NEW src/remote-control/workspace-secret-store.ts owns prepareWorkspaceSecretDirectory(directory) and hardenWorkspaceSecretFile(path). On POSIX use chmodSync with propagated failure and lstat directory/file identity/type checks. On Windows call existing src/lib/windows-secret-acl.ts hardenSecretDir/hardenSecretPath with required:true. Reject symlink state targets. All three stores use this before reads and before atomicWriteFile. Existing atomic-write.ts already creates an empty private descriptor, hardens before writing bytes, and scrubs failures; retain it. Tests: NEW tests/clients/remote-workspace-secret-store.test.ts covers owner-only POSIX file mode, unexpected path types/symlinks and failed reads; hosted Windows ACL owner tests remain applicable. No global config behavior changes. + +src/lib/windows-atomic-replace.ts change is the new ReplacePublisher literal remote-workspace (the function is already exported). Use existing counter serialization/consumers unchanged: creation at executor write, diagnostic key serialization, dynamic record readers; no closed switch to extend. + +NEW tests/clients/remote-workspace-session-binding.test.ts covers session/device/root/capability mismatches with zero execution and a valid positive control, using encrypted messages and independent fixtures. MODIFY agent-wire, hub, sessions and device tests to assert subset negotiation and presence intersection. Platform runner source retains existing fail-closed native paths; remove stale comment claiming supported macOS commands. + +### Audit amendment: store-level failure propagation + +Hub/Device/Session file-store constructors accept an optional narrow permissions dependency containing prepareDirectory and hardenFile, defaulting to the required production helper. Load returns null for absent files; existing files require directory and file checks before secret reads. Save prepares directory, hardens an existing target, then invokes the existing private atomic writer. For each store, injected directory/file hardening throws must propagate, preserve existing bytes and prevent secret IO. New-state first-run controls return null then save/load valid fixtures. Add all three store cases to remote-workspace-secret-store.test.ts; this injection observes caller ordering rather than relying on ACL-owner tests alone. + +### Native containment amendment + +Independent source review requires a protected Linux bubblewrap executable outside writable roots, with identity revalidation before use. Custom executable files and their parent chain must not be writable by group/other; canonical system symlinks are resolved before checking. Workspace roots cannot contain the executable; every invocation rechecks. Add source/runner regression fixtures without claiming a local run. + +Windows command availability remains disabled in this carry: nativeRemoteWorkspaceCommandRunnerAvailable returns false before invoking the helper, and the official Windows helper rejects public probe/run without allocating OS resources. The candidate Windows implementation remains in original PR history; do not retain callable unverified entrypoints. This matches the fail-closed macOS policy and preserves independently authorized file tools. Update native denial tests and docs; Windows working-command acceptance stays OPEN. A future lifecycle owner and hosted cancellation/cleanup evidence are required before re-enablement. This is a safety limitation, not completion of Windows commands. diff --git a/devlog/_plan/260912_remote_workspace_carry/030_integration.md b/devlog/_plan/260912_remote_workspace_carry/030_integration.md index 5c126f5987..4cf079534d 100644 --- a/devlog/_plan/260912_remote_workspace_carry/030_integration.md +++ b/devlog/_plan/260912_remote_workspace_carry/030_integration.md @@ -67,3 +67,23 @@ Local tests/build/typecheck/install NOT RUN by user instruction. Text comparison NEW src/remote-control/workspace-activation.ts exports a side-effect-free guard requiring runtimeRole=hub AND process.env.OCX_REMOTE_WORKSPACE_ENABLED === "1". This guard imports only the config type. Pair and agent branches call it before dynamic import; disabled requests return 404. Management namespace returns a disabled status before importing runtime. Shutdown uses already retained workspace references or initialized-only lazy import only when explicitly enabled; a disabled Hub never creates identity or probes model CLIs. CLI pairing remains explicit Executor-local authorization and never modifies server environment. Document the opt-in variable and require an explicit environment choice to enable the feature. Test disabled Hub, non-Hub with flag, and enabled Hub, with no ambient inheritance in fixtures. Existing-file conflicts observed by git apply --check: management-api.ts, management/context.ts and ws-bridge.ts. Port the namespace-dispatch addition into current management handler, append only type/dependency seam fields after current imports, and extend current WebSocket discriminator/handlers without replacing newer fields. The check was text applicability only, not a product test. + +## Phase-3 revalidation + +Previous D: runtime source cycle closed at a3182185f0 after corrected whitespace receipt. Final executable/native proof remains open; Windows commands unsupported. Continue integration from that exact parent. Carry current React resource/Select/Notice/icon conventions with no dependency additions. All locales inherit original translations with the unavailable-state opt-in message added consistently. + +Server adaptation: preserve current quota-reset and Grok coupon lazy dispatch. Add remote namespace handler before normal configuration routes. It answers disabled GET status with available:false and empty collections before loading workspace runtime; mutations when disabled refuse. Pair/agent paths require explicit guard before lazy imports and existing Origin/device-token validation. WebSocket data stores only structural receive/open/close callbacks; no concrete Hub class imports in ws-bridge. Upgrade closure owns hub/device association and close cleanup. Management dependency seams use structural Pick projections of only public Hub/session operations; all are import type and erased at runtime. Runtime modules use narrow config imports from phase 2, eliminating the prior broad runtime cycle. + +Shutdown: a promise-local initialized workspace module reference is set only on actual workspace route activation; shutdown calls initialized service getters only when that reference exists. It never dynamically imports remote runtime merely because runtimeRole is hub. Management-only activation also needs lifecycle-owned shutdown registration or a retained optional shutdown callback; resolve before B and test both paths. + +NEW tests/clients/remote-workspace-activation.test.ts covers hub+flag guard, disabled management status without store writes and unauthorized principal refusal before dependency construction. Existing server tests get explicit isolated flag setup/restore; no real devices. CLI capabilities list pair/agent/status, no Hub-status automation introduced. Regenerate skills/ocx reference surface through its existing generator (documentation only). Docs state OCX_REMOTE_WORKSPACE_ENABLED=1 opt-in, default read-only sessions, Linux conditional exec and both desktop native helpers refusing commands. + +Rendering: this worktree has no node_modules or gui/node_modules. Do not install or run a local build. Prefer final hosted package artifacts for a local static render with synthetic API responses; if no artifact exists, retain rendering as unmet acceptance and attach no historical screenshot as current evidence. + +### Awaited per-server cleanup decision + +The existing optional-shutdown registry is synchronous best-effort and cannot prove awaited Remote Workspace shutdown. Reuse server.stop's existing runListenerShutdown array instead. Add a per-server retained shutdown callback and a ManagementApiDeps onRemoteWorkspaceShutdown callback setter. Workspace management resolves its already-loaded services then registers an initialized-only cleanup closure through that setter; pair/agent loader registers the same kind of closure. server.stop calls the retained callback if present. No callback means no remote import/work. Keep registration idempotent and closure references scoped to the current config/server; tests cover management-only initialization and explicit stop. Do not change the global optional-shutdown API. + +In-flight initialization refinement: management checks per-server stopping before and after module import, creates Hub/session services synchronously in one turn, then registers initialized-only teardown. Pair/upgrade paths check stopping after lazy load. SessionService rejects create/resume after shutdown even when an availability promise completes later; a regression holds availability across shutdown. This prevents request initialization from creating resources after stop. + +Source-audit follow-up: pending creation promises and late handle cleanup are owned by shutdown, which settles all session cleanups before propagating failure. Pair-body completion rechecks stop admission. UI derives enrollment commands from the actual shared Hub origin, keeps drafts per session, preserves newer input on failure, shares submission eligibility between keyboard/button, warns on stale snapshots, and permits Stop during pairing. Controlled runtime/body/draft/Stop regressions accompany these adaptations; execution remains hosted-only. diff --git a/devlog/_plan/260912_remote_workspace_carry/041_resume_ci_repair.md b/devlog/_plan/260912_remote_workspace_carry/041_resume_ci_repair.md new file mode 100644 index 0000000000..0b8bcdec90 --- /dev/null +++ b/devlog/_plan/260912_remote_workspace_carry/041_resume_ci_repair.md @@ -0,0 +1,23 @@ +# Resumed final-tip verification + +The integration branch was fast-forwarded from 5c462fec1a to existing remote head 4ad1d1ce54 without rewriting the six intervening commits. PRs #4344, #4362 and #4372 remain open. CI run 34683454076 at 4ad1d1ce54359ee25fbb078344a22bdb16f7e304 failed; cancelled and skipped jobs are not passing evidence. + +## Scoped repair + +MODIFY tests/clients/remote-workspace-activation.test.ts: provide the HTTP Host precondition that managementRequestOrigin requires. Preserve 200/404 expectations and assert the admin-token denial message so a generic origin failure cannot satisfy the consent regression. + +MODIFY tests/clients/remote-workspace-sessions.test.ts: observe pending rejection using native Promise settlement, release the held start/availability gate, then assert rejection. Keep late runtime cleanup, one-stop/one-close checks, terminal failure state, and assert zero model prompts. Production cleanup code is unchanged. The source dependency order is verified; Bun matcher scheduling remains a hypothesis until repaired-head hosted execution confirms it. + +The host goal is observed blocked and the native cycle remains C; no direct goal/FSM edits or reset were performed. This repair continues the incomplete integration Check under explicit resume authorization. It is not claimed as an additional completed cycle. Local suites/build/typecheck/install are NOT RUN. Independent inherited-model review and final cumulative-tip hosted CI remain required. + +## Render provenance + +Dashboard artifact 10294424393 from run 34683454076 records merge-ref commit 5270d422166eb56692d1fde1513d5ff4f40533d4 and GUI tree 69b1bce039ee18cecea2586bc484c2afe0523a13, equal to candidate 4ad1d1ce54:gui. It is rendered with synthetic example state on a loopback static server; mutations are disabled. This proves the captured layout only, not real pairing or runtime execution. + +Observed screenshots: assets/041_desktop_read_only.png and assets/042_desktop_files_only.png at 1440x913 CSS pixels. The actual access picker changes from Read only to Edit files only and displays the command-unavailable notice. No live enrollment or model operation was invoked. A requested390px native-window resize stopped at500px; that is not390px proof, and no narrower layout claim is made. The installed browser CLI does not expose the documented script command; no driver was installed to work around it. + +## Windows subprocess fixtures + +Run34693137770 at d1a922ae reports three remote-owned fixture failures on Windows: two native response cases cannot execute a POSIX shebang file, and the cwd case times out while starting PowerShell. The intended contracts are bounded stdin/response decoding and real child cwd; neither requires a shell. Replace only test subprocess fixtures with the exact current Bun executable, preserve helper-path checks, timeout/output bounds and success/error assertions. Native Windows command support remains disabled. Local suites remain NOT RUN; independent source review and repaired-head hosted proof are required. + +The Windows native fixture keeps descriptor keys separate from its injected spawn function, verifies all pipe options before forwarding them unchanged, and never executes authority from the input JSON. Cwd checks compare decoded stdout with the canonical executor directory and exclude the canonical coordinator directory. An exact exit-code/empty-stderr assertion accompanies the unchanged deadline. At predecessor d1a922ae, hosted Windows2 job103552067478 passed the corrected disabled management status case; that narrow result is not an all-suite pass. diff --git a/devlog/_plan/260912_remote_workspace_carry/assets/041_desktop_read_only.png b/devlog/_plan/260912_remote_workspace_carry/assets/041_desktop_read_only.png new file mode 100644 index 0000000000..9075e975be Binary files /dev/null and b/devlog/_plan/260912_remote_workspace_carry/assets/041_desktop_read_only.png differ diff --git a/devlog/_plan/260912_remote_workspace_carry/assets/042_desktop_files_only.png b/devlog/_plan/260912_remote_workspace_carry/assets/042_desktop_files_only.png new file mode 100644 index 0000000000..c99e88e29f Binary files /dev/null and b/devlog/_plan/260912_remote_workspace_carry/assets/042_desktop_files_only.png differ diff --git a/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-hub-dashboard.png b/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-hub-dashboard.png new file mode 100644 index 0000000000..98972b8e75 Binary files /dev/null and b/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-hub-dashboard.png differ diff --git a/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-pairing-code.png b/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-pairing-code.png new file mode 100644 index 0000000000..3fc3c97e08 Binary files /dev/null and b/devlog/_plan/260912_remote_workspace_carry/screenshots/remote-workspace-pairing-code.png differ diff --git a/devlog/_plan/260912_unimplemented_trio_stack/000_plan.md b/devlog/_plan/260912_unimplemented_trio_stack/000_plan.md new file mode 100644 index 0000000000..611dbac17c --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/000_plan.md @@ -0,0 +1,108 @@ +# Trio stack: WS stage instrumentation, native-main device reauth, paginated history recovery + +Unit 260912_unimplemented_trio_stack. HOTL loop goalplan slug +`implement-three-unimplemented-opencodex-backlog` (session +01a09616-38e6-72e0-b5bf-99eb10ce58a6). Bottom-up manual stacked-PR chain +against `dev` (lidge-jun/opencodex). No merges, no GitHub native-stack +registration. Every push uses `git push --no-verify`; local product +suite/build/typecheck/install NOT RUN; each PR relies on hosted exact-head +CI and says so in its Verification section. + +## Objective + +Close the three implementable unimplemented backlog items identified in the +2026-09-12 inventory: + +1. Issue #4191 — WS 1006 / response-prelude-timeout diagnosis has no durable + content-free evidence. Ship stage instrumentation only; no fix, no + auto-retransmit fallback. +2. Issue #3898 — headless hub cannot reauth native `__main__` because + deviceauth is pool-only. Ship the native-main device reauth API/CLI, then + the main-card Re-login GUI on top of it. +3. Issue #4311 residual — paginated history still has no writer support and + no recovery for ordinal-corrupted rollouts. Ship the offline recovery + tool with preservation proofs; live writes stay refused. + +## Sources + +- #4191 body: content-free stage diagnostics list; A/B evidence that the + failure is proxy-path-specific; related #2471, #4083, #3976. +- #3898 body: suggested contract (reuse OpenAI deviceauth, persist to native + main slot, keep `__main__` out of `/api/codex-auth/login`, no codex + binary/keyring requirement, secret-free DTOs). +- #4311 body: ordinal-0 clone defect (now guarded), incident recovery by + ordinal-digit rewrite while Codex was closed, prohibition of N+1 guessing + and live rewrites. +- devlog/_plan/260912_accounts/080_reauth_api.md and 090_reauth_ui.md — + accepted Accounts-lane design drafts this unit adopts for L2/L3. +- devlog/_plan/260912_history_containment/ — refusal contract this unit + must preserve. + +## Constraints (hard) + +- L1 logs stay content-free: create-frame byte count, send completion, + close code (numeric), elapsed/first-frame timings, frame counters, OCX and + Bun versions. No conversation text, no headers, no close-reason text, no + account identifiers in the new records. +- L1 adds no `responseCommitted === false` auto-retransmit: turn + duplication risk is documented in #4191 discussion. +- L2 keeps `/api/codex-auth/login` rejecting `__main__` (400), keeps pool + Add/Re-login semantics unchanged, and must not route the native flow + through `startLoginFlow("chatgpt")` (scratch-slot overwrite + pool + singleflight collision, src/oauth/index.ts:1899-1973). +- L2 commit to `$CODEX_HOME/auth.json` only under an exclusive claim with + path/hash/inode assertion and same-identity verification; never retains + old identity token beside new credentials; fails safe + (`native_main_unavailable`) when no fence can be established. +- L3 must not reuse `AddCodexAccountModal` or `openReauth("__main__")`; + dedicated hook and dedicated backend namespace only (the pool login route + rejects `__main__` at src/codex/account-id.ts:15-20). +- L4 must not invent last-ordinal+1, must not write to a live rollout, must + not weaken `history_paginated_requires_native_writer` refusal in + preflight/apply/restore paths, and must preserve every non-ordinal byte. +- All layers: focused tests land with the layer; every new test file gets + layout.json `explicit` + tests/fixtures/test-layout-expected.json + entries in the same PR. +- structure/ ownership: any owned source area changed by a layer updates + its structure doc in the same PR (structure/AGENTS.md). + +## Work-phase map (dependency order = stack order, bottom first) + +| WP | Layer | Branch | PR base | Decade doc | +|----|-------|--------|---------|------------| +| wp2 | L1 #4191 WS stage instrumentation | codex/260912-ws-stage-instrumentation | dev | 010 | +| wp3 | L2 #3898 native-main reauth API/CLI | codex/260912-native-main-reauth-api | wp2 branch | 020 | +| wp4 | L3 #3898 main-card Re-login GUI | codex/260912-native-main-reauth-ui | wp3 branch | 030 | +| wp5 | L4 #4311 paginated history recovery | codex/260912-native-paginated-writer | wp4 branch | 040 | + +Dependency logic: L2 and L3 are one feature split at the API/UI seam +(030 depends on 020's route). L1 is independent but touches the shared +request-log schema, so it sits at the bottom where later layers rebase onto +a stable log contract. L4 is the riskiest (user data) and rides on top so +lower layers can land without waiting for it. There is no functional +dependency between L1/L2 and L4; the chain exists to serialize review. + +## Verification policy per layer + +- Red-first focused tests, then implementation, then green. +- `bun test tests//` (or `cd gui && bun test tests/` + for L3) fresh at C, captured via `cxc receipt test`. +- Full local suite/build/typecheck/install: NOT RUN (standing rule); each + PR Verification section labels this and names the hosted exact-head CI + run as the integration evidence. Cancelled/skipped CI never counts as + passing. +- L4 additionally: privacy-relevant paths (rollout bytes) stay in tests + with synthetic fixtures only. + +## Open decisions carried to audit + +1. L2 hub fence: on a headless hub the native owner never activates + (src/server/index.ts:1026-1046 + src/codex/desired-state.ts:79-81). + 020 resolves how commit fencing works there without weakening the + exclusive-claim contract; audit must confirm the chosen fence. +2. L4 scope: true live-write support needs a Codex-owned writer API that + does not exist in this tree. This unit ships the offline recovery tool + and keeps live refusal; the PR description must say so explicitly. +3. L3 screenshot evidence: obtained from hosted CI artifacts or recorded + exemption, per repo PR gate (title/body mentions of gui need a + screenshot). diff --git a/devlog/_plan/260912_unimplemented_trio_stack/001_baseline_revalidation.md b/devlog/_plan/260912_unimplemented_trio_stack/001_baseline_revalidation.md new file mode 100644 index 0000000000..327dc4285c --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/001_baseline_revalidation.md @@ -0,0 +1,22 @@ +# Baseline revalidation (wp1 B-phase) + +Independent main-session spot check of the citations folded in by the wp1 +audit (0268727f82), re-run against the working tree at B. Every folded +reference was opened and read; results below. All verified TRUE. + +| Claim | Where verified | Result | +|-------|----------------|--------| +| `assertNativeMainOwner` throws without a held owner entry | src/codex/native-main-owner.ts:302-314 — throws NATIVE_MAIN_OWNER_UNAVAILABLE/BUSY (503) unless snapshot held | TRUE | +| Exclusive claim is owner-independent (FS/SQLite lock) | src/codex/native-main-claim.ts:167 — `withNativeMainExclusiveClaim(context, operation, options)`, claim/release around operation, no owner lookup | TRUE | +| `shouldSyncCodexOnStart` is composed at desired-state.ts:130 | src/codex/desired-state.ts:130 — exported function; comment names the hub rule | TRUE | +| Pool login writes `isMain: false` | src/codex/auth-api.ts:2934,2939 — both update and add paths set `isMain: false` | TRUE | +| Paginated guard throws the structured reason | src/codex/history-provider.ts:1172 — `CodexHistoryIntegrityError("history_paginated_requires_native_writer")` on `ordinal` key or `history_mode === "paginated"` | TRUE | +| State DB resolution | src/codex/paths.ts:106-109 — `resolveCodexStateDbPath` joins sqlite root + state_5.sqlite | TRUE | +| `startLoginFlow` location | src/oauth/index.ts:1899 — export begins | TRUE | +| GUI modal state | gui/src/components/CodexAccountPool.tsx:75 (`showAdd`), :94 (`reauthId`), :651-654 (modal mount) | TRUE | + +Consequence for implementation cycles: 020's hub-fence resolution stands +as amended — the native-main reauth fence MUST NOT call +`assertNativeMainOwner`; the owner-independent exclusive claim plus +path/hash/inode and recovery/admission rechecks is the whole fence, and +claim/admission failure alone maps to `native_main_unavailable`. diff --git a/devlog/_plan/260912_unimplemented_trio_stack/010_l1_ws_stage_instrumentation.md b/devlog/_plan/260912_unimplemented_trio_stack/010_l1_ws_stage_instrumentation.md new file mode 100644 index 0000000000..72cfd8c3c2 --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/010_l1_ws_stage_instrumentation.md @@ -0,0 +1,142 @@ +# L1: content-free Codex WS upstream stage instrumentation (#4191) + +Class C2. Stack bottom, base `dev`. Branch +`codex/260912-ws-stage-instrumentation`. Diagnosis instrumentation only: +no behavior change to success paths, no retry/fallback change. +Second revision: folds the wp2 A-audit FAIL (2 blockers, 2 majors, 1 +minor) into the design. First revision's `recordCodexWsStage`-on-context +design is retracted — the exchange has no `RequestLogContext` +(codex-ws-exchange.ts:11-18,85) and cannot get one without inverting +layers. + +## Problem + +#4191 fails as WS 1006 or "response prelude timed out" only through the +proxy. The content-free stage record already exists as +`CodexWsFailureStage` (src/server/responses/codex-ws-wire.ts:100-144) and +`failureStage()` (src/server/responses/codex-ws-exchange.ts:148-159), but +it is only interpolated into failure message strings. Durable logs keep +neither the message nor a typed code: the eager relay collapses stream +errors to `upstream_reset` + `streamAborted` (wire.ts:218-229 comment; +relay.ts:1417-1430), and the 504 pre-response JSON path never reaches the +relay at all. `/api/logs` and usage.jsonl are explicit per-field copies, +so a field added only to `RequestLogContext` is dropped on write and on +restart hydrate. + +## Contract (from #4191 + maintainer bounds) + +Record, per upstream exchange: create-frame bytes, send completion, +close code (numeric only), elapsed ms and first-frame ms, frame counters +(upstream/control/relayed, pings/pongs), pool reuse boolean, OCX version, +Bun runtime version. Never record conversation text, headers, close-reason +text, or account identifiers. No `responseCommitted === false` +auto-retransmit fallback. Client CLI version is not on the handshake +(`user-agent` is not in FORWARD_HEADERS, +src/adapters/openai-responses.ts:43-61) — the limitation is documented in +the PR, not worked around by parsing `frameText`. + +## Changes + +MODIFY `src/server/responses/codex-ws-wire.ts` +- New exported type `CodexWsStageRecord = + Omit & { + requestBytes: number | null; closeCode: number | null; reused: boolean; + ocxVersion: string; bunVersion: string }` (Omit, not an intersection — + an intersection cannot widen `requestBytes`). Extend the privacy + comment: numeric/boolean/semver fields only; close-reason text stays out + of every durable record. +- New `markCodexWsStage(response, record)` / `readCodexWsStage(response)` + over a `WeakMap` — the same + Response-marker seam `markCodexWsResponse` already uses. +- `ocxVersion` comes from a module-local package.json IIFE, the exact + pattern already duplicated in management-api.ts:87-93, gui-static.ts:6-9, + client/machine-listener.ts:21, update/index.ts:147. Do NOT import + management-api (layer inversion + cycle). + +MODIFY `src/server/responses/codex-ws-exchange.ts` +- `ExchangeOptions` gains optional `bunVersion?: string` and nothing + else; no context, no callback registry. +- Snapshot once in `failStream` (the funnel every failure site already + calls: armSilence :206, connect-deadline :256, onClose :426, onError + :437, and the onMessage sites :330-402) and once in `commitResponse` + (:160). After the existing settle decision, call + `markCodexWsStage(response, record)` on the Response being resolved — + both the SSE 200 and the `codexWsPreResponseFailure` JSON paths resolve + a Response, so one marker covers success and failure. +- `requestBytes`: computed at failure time only (current deferred + behavior). On the committed-success record it is `null` — the happy + path must not byte-count megabyte replay frames (the deferral comment at + :143-147 is the contract). +- `closeCode` is captured in `onClose` from the event (numeric only) and + carried into the `failStream` call it makes; other sites pass `null`. +- `reused` is `session.reused`; `bunVersion` from the new option. +- No control-flow change at any site: emissions happen after the settle + decision, never instead of it. + +MODIFY `src/server/responses/ws-upstream.ts` +- Pass `bunVersion: typeof runtime === "string" ? runtime : runtime.version` + (the gate input at :62-64 may be a plain string) through + `codexWsUpstreamFetch` into `codexWsExchange`. Signature gain is one + optional field. + +MODIFY `src/server/responses/core.ts` +- Adopt the stage onto the attempt at the handleResponses send path, not + only at `retryCodexPoolOnAlternateAccount` (:1532-1556 is the pool + retry, not the primary send): `readCodexWsStage(upstreamResponse)`; + when present assign `logCtx.activeAttempt.codexWsStage`. Apply at every + adopted `upstreamResponse`: the primary send (:5304-5320), the + post-retry assignment (:5824) — or once on the final response after the + ladder (~5758); B picks the single funnel that covers every adopted + response and tests it. This covers the 504/502 pre-response JSON path + that never reaches relay.ts, and needs no relay.ts change: the relay + collapse only sets `streamAborted` alongside the stage. (First + revision's relay.ts MODIFY is retracted.) + +MODIFY `src/usage/log.ts` +- `PersistedUsageAttempt` gains `codexWsStage?: CodexWsStageRecord` + with a comment naming #4191 and the content-free invariant. +- Attempt serializer allowlist (:445-480 region): carry `codexWsStage` + through a `normalizeCodexWsStageRecord` guard (numeric fields via + isNonNegativeFiniteNumber-style checks, booleans strictly, versions as + capped semver strings, `requestBytes: number | null`) so a hand-edited + row cannot inject strings into the DTO. +- `normalizeUsageEntry` (:527-612) carries it via the attempts + normalization above; no entry-level copy (stage is per-attempt). + +MODIFY `src/server/request-log.ts` +- `RequestLogEntry` needs no new field: `attempts` already projects. + `requestLogEntryFromPersistedUsage` (:280-330) keeps copying + `attempts` wholesale. Verify `addFinalRequestLog` (:1037-1086) passes + the attempt objects (with the stage) into `addLog` — if it re-derives + attempt rows field-by-field, add `codexWsStage` there instead. B + confirms which of the two attempt paths is authoritative and tests it. + +## Tests (red-first) + +MODIFY `tests/responses/ws-upstream.test.ts` +- Through `handleResponses` (the :399-408 pattern — the only path that + owns a logCtx): upstream 1006 persists `codexWsStage` on the logged + attempt with `closeCode: 1006` and `sent: true`; prelude-timeout + persists `firstFrameMs: null`, `upstreamFrames: 0`; a committed + success records exactly one stage with `requestBytes: null`. +MODIFY `tests/responses/ws-failure-stage.test.ts` +- Record carries closeCode/reused/versions; the serialized record never + contains reason text, header names, or body substrings. +NEW `tests/usage/usage-log-ws-stage.test.ts` +- Round trip: `normalizeUsageEntry` + attempt serializer keep a valid + stage; corrupt stage shapes (string frames, object closeCode) are + dropped, not passed through. layout.json explicit + + tests/fixtures/test-layout-expected.json entries (domain `usage`). + +## Docs / ownership + +L1 touches owned `src/server/responses/*`, `src/usage/log.ts`, and +`src/server/request-log.ts`: sync structure/transports/responses.md and +structure/runtime.md in this PR (structure:check must stay green). + +## Out of scope + +Any WS behavior fix, SSE-fallback policy change, prelude-timeout tuning +(#3976/#4083), pool policy, inbound client-socket metrics +(codexWebSocketAdmissionMetrics is the client side — do not touch), +auto-retransmit on `responseCommitted === false`. diff --git a/devlog/_plan/260912_unimplemented_trio_stack/020_l2_native_main_reauth_api.md b/devlog/_plan/260912_unimplemented_trio_stack/020_l2_native_main_reauth_api.md new file mode 100644 index 0000000000..bde091a235 --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/020_l2_native_main_reauth_api.md @@ -0,0 +1,138 @@ +# L2: native-main device reauth API/CLI (#3898) + +Class C4 (auth boundary). Stack layer 2, base the L1 branch. Branch +`codex/260912-native-main-reauth-api`. Adopts the accepted Accounts-lane +design devlog/_plan/260912_accounts/080_reauth_api.md; this doc is the +diff-level revalidation of that draft against current `dev` plus the +deltas the code map surfaced. 080 remains the contract source; anything +here overrides stale details of 080, not its invariants. + +## Problem + +Headless hub (`runtimeRole=hub`, `oauthOpenBrowser: false`, no codex +binary, no keyring) cannot reauth native `__main__`: +`/api/codex-auth/login` is pool-only and rejects `__main__` +(src/codex/account-id.ts:15-20; src/codex/auth-api.ts:2733-2748); +`ocx account main add` requires official `codex login` + OS keyring +(src/cli/account-main.ts:73-90,214-260). WHAM `token_revoked` on the main +grant is then unrecoverable from the hub. + +## Changes (080 contract, revalidated) + +MODIFY `src/oauth/chatgpt-device.ts` +- Factor the private grant exchange so a native-only result retains the + raw validated token payload: new `loginChatGPTNativeDevice` returns + `{ credential, idToken }` in-process only; reject missing + access/refresh/id token or mismatched account identity. Existing + `loginChatGPTDevice` behavior unchanged (still projects + OAuthCredentials, no id_token). +- Delta from 080 (explorer-confirmed gap): the usercode/poll/token fetches + (84-90, 121-127, 152-163) have no per-request timeout — only the 15-min + poll deadline and abort. Add a service-owned per-fetch deadline (fetch + + body) so a stuck TCP cannot hold the flow until TTL. This is the Kuhn + blocker "poll timer does not bound fetch/body deadlines". + Audit-folded: one FRESH 30s timeout per fetch attempt inside the poll + loop (AbortSignal.any([ctrl.signal, AbortSignal.timeout(30_000)]), the + main-account.ts:239-241 pattern) — a single 30s signal across the whole + poll would kill the 15-minute grant. Abort-timeout maps to + device_authorization_failed. The shared helper also bounds hung POOL + device logins at 30s per fetch — an intended improvement, called out in + the PR. + +MODIFY `src/codex/main-account.ts` +- New `beginNativeMainReauth`: captures the existing + `MainAuthJsonCredential` snapshot (103-136) into a private closure; + returned commit accepts complete native device tokens and, only after + human authorization, acquires `withNativeMainExclusiveClaim` + (src/codex/native-main-claim.ts:167), rechecks recovery/admission fence, + asserts original path/hash/inode before atomic rename, requires same + chatgpt account identity, writes access+refresh+id token + account_id + together, advances the mutation epoch, and reconciles runtime/quota + state. Old identity token is never retained beside new credentials. No + claim held during human polling. + Audit-folded: do NOT reuse persistRefreshedMainAuthJson (:190-195) — it + spreads expected.tokens and never writes id_token, so the old identity + token would survive beside the new grant. The commit uses a SIBLING + persist that sets access_token/refresh_token/id_token/account_id + together and overwrites any prior id_token (adding the key is safe: + readMainAuthJsonCredential :122 tolerates it and + native-profile-store.ts:476-481 expects it). + +NEW `src/codex/main-device-reauth.ts` +- One process-owned active flow (opaque UUID, AbortController, bounded + terminal retention 5 min, grant deadline 15 min). Start/status/cancel + return only flowId, status, verificationUrl, deviceCode, and closed safe + failure codes per the 080 `MainDeviceReauthStatus` union. Injectable + login/commit dependencies for tests. Superseded/cancelled completions + never publish. No tokens/emails/raw account ids in DTO/log/error. +- Dedicated abort controller and direct `loginChatGPTNativeDevice` call: + MUST NOT use `startLoginFlow("chatgpt")` (would overwrite the chatgpt + scratch slot and 409 against pool logins, src/oauth/index.ts:1899-1973). + +NEW `src/codex/main-device-reauth-api.ts` +- `POST/GET/DELETE /api/codex-auth/main/reauth-device` with exact opaque + flow query, strict request keys, safe 400/404/409. Registered at the + management dispatch boundary (src/server/management-api.ts:385-407 + region); existing management auth/origin/session controls stay + authoritative. No CLI direct account-file write. + +MODIFY `src/cli/account-main.ts` +- `ocx account main reauth --device [--no-wait]`, + `reauth status --flow `, `reauth cancel --flow ` via the + management API; reject extra args before start. Register capability/help; + regenerate skill surface with `bun run skill:surface` if the capability + registry changes (tests/ci-workflows/skill-ocx.test.ts gates this). + Audit-folded: the native-main CLI branch point is account-main.ts (:181 + region, beside add/switch) with USAGE in src/cli/account.ts:64; the + management route-registry (src/server/management/route-registry.ts + MANAGEMENT_ROUTES) must gain the POST/GET/DELETE rows or + management-route-registry.test.ts and the capabilities ratchet go red — + do NOT grow UNDECLARED_ROUTES_2026_08_28. + +## Hub fence resolution (open decision 1, resolved here for audit) + +On a headless hub the native owner lifecycle is a no-op +(src/server/index.ts:1026-1046 binds the no-op when +`shouldSyncCodexOnStart` is false; the gate is composed at +src/codex/desired-state.ts:130 — :79-81 is `localClientSyncAllowed`). +The reauth commit therefore MUST NOT depend on owner activation and MUST +NOT widen `shouldSyncCodexOnStart` (that gate covers client-config sync, +not credential rewrite). + +Audit-folded correction to 080: 080's `assertNativeMainOwner` at +preparation/commit is RETRACTED for this layer. That assert throws without +a held owner entry (src/codex/native-main-owner.ts:302-314), which would +make hub reauth always fail. The exclusive claim is owner-independent +(src/codex/native-main-claim.ts:167, FS/SQLite lock only). The fence is +pinned to: `withNativeMainExclusiveClaim` + in-process admission fence + +path/hash/inode assertion + recovery/admission snapshot recheck, exactly +as on workstations. Only claim/admission failure maps to +`native_main_unavailable`; no write occurs without the full fence — an +unfenced write is a C4 violation, not a fallback. + +## Tests (red-first; domain tests/codex-integration, tests/oauth, tests/cli) + +NEW `tests/codex-integration/main-device-reauth.test.ts` — same-account +success without codex/keyring; wrong identity refused; missing token +fields; cancelled/superseded late result cannot publish; concurrent file +replace/refresh/profile switch; atomic write failure; claim unavailable → +native_main_unavailable with zero writes; no pool-row mutation; DTO/log +secret scan. +NEW `tests/codex-integration/main-device-reauth-api.test.ts` — route +contract: strict keys, 400/404/409 shapes, unauthorized rejected, +`__main__` still refused by `/api/codex-auth/login`. +MODIFY `tests/oauth/chatgpt-device-auth.test.ts` — native result retains +idToken in-process; per-fetch deadline fires on a hung stub fetch. +Audit-folded: native-main CLI tests land in +tests/cli/cli-native-profile.test.ts (native-main CLI); the pool +cli-account.test.ts keeps only the __main__ login rejection cases. +MODIFY `tests/cli/cli-native-profile.test.ts` — reauth --device surface, +status, cancel, arg rejection. +All NEW files: layout.json explicit + expected-fixture entries. + +## Docs / ownership + +structure/ ownership docs for src/codex, src/oauth, src/cli, src/server +synced in this PR (structure:check must stay green). Headless recovery +instructions updated (docs-site) in the same PR. Security draft stays in +scratch; only the implementation + regression diff is published. diff --git a/devlog/_plan/260912_unimplemented_trio_stack/030_l3_main_card_relogin_ui.md b/devlog/_plan/260912_unimplemented_trio_stack/030_l3_main_card_relogin_ui.md new file mode 100644 index 0000000000..41c1196409 --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/030_l3_main_card_relogin_ui.md @@ -0,0 +1,104 @@ +# L3: main-card Re-login with device code (#3898 GUI) + +Class C3 (auth-adjacent GUI). Stack layer 3, base the L2 branch. Branch +`codex/260912-native-main-reauth-ui`. Adopts +devlog/_plan/260912_accounts/090_reauth_ui.md, revalidated against current +`dev` by the GUI code map. Depends on L2's +`/api/codex-auth/main/reauth-device` contract. + +## Problem + +The main card is a locked App-login identity: expired state shows only +`codexAuth.mainTokenExpired` ("sign in again via Codex App login", +gui/src/components/codex-account-pool-main-card.tsx:183-185) and no +Re-login control (props at 21-56 have no `onReauth`). Pool rows have the +full device-code modal; the main card has nothing. + +## Constraints (090 + code map) + +- MUST NOT reuse `AddCodexAccountModal` / `openReauth("__main__")` / + `reauthAccountId=__main__`: the pool login route rejects `__main__` + (src/codex/account-id.ts:15-20; src/codex/auth-api.ts:221-224,2736-2748) + and a successful pool login writes `isMain: false` rows + (src/codex/auth-api.ts:2934-2939) — wrong credential store. +- DTO field chain: backend DTO → hook-validated state → main card only; + no device code in browser storage; verification URL accepted only from + the backend contract, never from arbitrary payloads. +- New copy lands in ALL locale files (en, de, fr, ja, ko, ru, tr, zh, + zh-TW) per gui/AGENTS.md "Text and i18n". +- `tests/gui/provider-workspace-auth.test.ts:248` currently requires + `codexAuth.mainTokenExpired` on the main card; updating that copy is + part of this layer. + +## Changes + +NEW `gui/src/components/use-main-device-reauth.ts` +- Dedicated hook mirroring the pool OAuth hook's start/poll/cancel shape + (gui/src/components/use-add-codex-account-oauth.ts:27) against + `/api/codex-auth/main/reauth-device`: `start()` POST, `poll(flowId)` + with visibility polling (2s tick, 10s per-tick timeout, stop on terminal + status), `cancel(flowId)` DELETE, unmount/abort cleanup. +- Normalizes closed status/error payloads; ignores late responses from a + replaced flow (flowId ownership); never accepts token/account-id fields; + renders only verificationUrl + deviceCode + status. + +MODIFY `gui/src/components/codex-account-pool-main-card.tsx` +- New optional `onReauthDevice` prop. When `showReauth` (83) is true, + render a "Re-login with device code" CTA beside the existing copy; after + start, show verification URL + human code + pending status + cancel; + success triggers the existing parent refresh. +- Layout stays consistent with the current card; pool Add/Re-login and the + native profile picker are untouched. + +MODIFY `gui/src/components/CodexAccountPool.tsx` +- Own main-reauth modal state separate from `showAdd`/`reauthId` + (75,94; openReauth at 189-192); wire `onReauthDevice` at the main-card render (515-533); + pause pool refresh while the main flow is active, same as the existing + modal pause (174-178). + +MODIFY `gui/src/i18n/{en,de,fr,ja,ko,ru,tr,zh,zh-TW}.ts` +- New `codexAuth.*` keys: CTA label, pending status, cancel, terminal + failure copy (actionable, safe; no auto-retry wording). Revise + `mainTokenExpired` so it no longer claims App login is the only path. + +## Audit folds (wp4 A) + +- Start POSTs an EMPTY body (the route rejects any body with 400); poll + immediately until verificationUrl/deviceCode arrive (they are empty in the + start response), and keep the last url/code through the committing state. +- Map the full MainDeviceReauthStatus union + HTTP error shapes: committing + (no url/code), failed.code (identity_mismatch, credential_changed, + native_main_unavailable, device_authorization_failed, + publication_failed, reconciliation_failed), 409 flow_in_progress, 503 + native_main_unavailable; when credentialUpdated is true the copy never + claims the file was unchanged; the verification URL is allowlisted to + https://auth.openai.com/codex/device. +- structure claim lands in structure/gui-and-management-api.md (the + Codex-accounts row :312), not overview.md. + +## Tests (red-first) + +NEW `gui/tests/main-device-reauth.test.tsx` — happy-dom mount per +gui/tests convention: CTA starts the dedicated route (never +`/api/codex-auth/login`), code/URL display, cancel ownership, stale-poll +ignore, success refresh, keyboard and error states. +MODIFY `tests/gui/provider-workspace-auth.test.ts` — main-card contract +updated for the new CTA + copy. +MODIFY `tests/gui/codex-auth-modal-status.test.ts` if locale-key +assertions enumerate codexAuth keys. +The happy-dom file lives under `gui/tests/`, outside the `tests/` layout +map — layout.json explicit + expected-fixture entries are needed only for +any NEW `tests/gui/*` source-contract file, not for `gui/tests/*`. + +## Docs / ownership + +L3 touches owned `gui/`: sync structure/overview.md and +structure/gui-and-management-api.md in this PR (structure:check must stay +green). + +## Verification + +`cd gui && bun test tests/main-device-reauth.test.tsx` plus the touched +suites; `bun run lint:i18n` for copy. Local GUI build NOT RUN; PR +screenshot evidence comes from hosted CI built artifacts, or an explicit +recorded exemption (repo gate: gui-mentioning PRs need a screenshot). diff --git a/devlog/_plan/260912_unimplemented_trio_stack/040_l4_native_paginated_writer.md b/devlog/_plan/260912_unimplemented_trio_stack/040_l4_native_paginated_writer.md new file mode 100644 index 0000000000..0b6e879460 --- /dev/null +++ b/devlog/_plan/260912_unimplemented_trio_stack/040_l4_native_paginated_writer.md @@ -0,0 +1,91 @@ +# L4: paginated history — offline ordinal recovery, live refusal preserved (#4311) + +Class C4 (user data). Stack top, base the L3 branch. Branch +`codex/260912-native-paginated-writer`. + +## Problem and scope decision (open decision 2, resolved here for audit) + +#4311's live defect (ordinal-0 `session_meta` clone) is already guarded: +`updateSessionMeta` throws for paginated records before writing +(throw at src/codex/history-provider.ts:1172), and preflight refuses +`history_paginated_requires_native_writer` +(structured field src/codex/inject.ts:899; preflight closure +src/codex/inject.ts:1182-1194). The residual acceptance is +(a) native paginated writer support and (b) corrupted-rollout recovery. + +(a) needs a Codex-owned writer API/IPC. None exists in this tree: Codex +owns ordinals and the live projection cursor +(structure/codex-home.md:232-234), `appendRolloutLine` deliberately does +not allocate ordinals (src/codex/history-provider.ts:77,248), and H +serializes only OpenCodex writes (src/codex/history-lock.ts; +src/codex/internal/history-writer.ts:86,107). Inventing N+1 is explicitly +forbidden by the issue (concurrent native writer / stale cursor). This +layer therefore ships (b) the offline recovery tool, keeps (a) refused +with the same structured reason, and says so in the PR. A follow-up +native-writer integration needs a Codex-side write API first — reported, +not faked. + +## Changes + +NEW `src/codex/history-ordinal-recovery.ts` +- Offline repairer for the #4311 corruption shape: an unprojected suffix + whose ordinals regress (projector error `expected N, got 0`). +- Preconditions, all enforced before any write: + - Codex fully closed (no running Codex process holds the home; detect + via the same process/home inspection the service uses, fail safe when + undecidable). + - Target resolution follows `resolveCodexStateDbPath` and + `threads.rollout_path` (src/codex/paths.ts:107-108; the column is + read through history-provider, not paths.ts) — never assume + `~/.codex/sessions`. + - Suffix shape verified: ordinals strictly increase before the boundary, + regress at the boundary, and the suffix parses cleanly. Anything else + refuses. + - Byte-identical backup written before mutation (manifest beside the + existing backup convention, src/codex/history-provider.ts:30). +- Rewrite: only ordinal digits in the unprojected suffix, renumbered to + continue the pre-boundary sequence; message text, ids, timestamps, and + all earlier bytes preserved. Exact readback verification before + reporting success. Dry-run (verify-only) is the default; `--write` + applies. + +MODIFY `src/cli/` (doctor/dispatch surface per existing conventions) +- `ocx doctor history repair-paginated-ordinals [--thread ]` + [--write]: runs the recovery, prints boundary, counts, backup path, and + readback result. Register capability/help; regenerate skill surface if + the registry changes. + +MODIFY `structure/codex-home.md` +- Record the recovery tool's ownership of offline ordinal repair and + restate that live paginated writes stay refused (structure:check gate). + +Explicitly unchanged (regression-tested, not edited): +`preflightCodexHistoryInjection` (history-provider.ts:307), +`appendRolloutLine` (77), `updateSessionMeta` paginated guard (1172), +inject pre/postflight (inject.ts:1182,1295,1332), catalog-only sync +(src/codex/sync.ts:216). + +## Tests (red-first; tests/codex-integration) + +NEW `tests/codex-integration/history-ordinal-recovery.test.ts` +- Synthetic fixture: session_meta ordinal 0 followed by event ordinal 1 + (the issue's minimal shape) behind a healthy increasing prefix. +- Dry-run reports and writes nothing (byte-identical file). +- Applied repair renumbers only the suffix; every non-ordinal byte + identical; readback passes; backup exists and matches the original. +- Refusals: Codex process detected / undecidable; suffix shape mismatch + (no regression, gap, unparsable line); missing backup space; absolute + rollout_path outside CODEX_HOME via sqlite_home. +- Preservation invariants red-first: run the preservation assertions + against the unimplemented command first (red), then implement (green). +MODIFY `tests/codex-integration/codex-history-provider.test.ts` +- Assert preflight refusal reason unchanged for paginated rows (the + recovery tool must not become a live writer). +NEW files: layout.json explicit + expected-fixture entries. + +## Out of scope + +Live paginated writes, ordinal allocation, native-writer IPC, any change +to the authless/compaction relabel fork (inject.ts:1098), provider-table +lifetime policy (separate #4311 sub-thread, tracked by containment unit), +in-app repair while Codex runs. diff --git a/devlog/_plan/260913_60plus_skipci_stack/screenshots/pairing-hub-1440.png b/devlog/_plan/260913_60plus_skipci_stack/screenshots/pairing-hub-1440.png new file mode 100644 index 0000000000..66ed8a04a3 Binary files /dev/null and b/devlog/_plan/260913_60plus_skipci_stack/screenshots/pairing-hub-1440.png differ diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs index b25586f7a6..b76a01cdd5 100644 --- a/docs-site/astro.config.mjs +++ b/docs-site/astro.config.mjs @@ -86,6 +86,7 @@ export default defineConfig({ translations: { fr: "Guides", ko: "가이드", "zh-CN": "指南", "zh-TW": "指南", ru: "Руководства", ja: "ガイド", tr: "Kılavuzlar" }, items: [ { label: "Remote Hub Deployment", translations: { fr: "Déploiement Remote Hub", ko: "Remote Hub 배포", "zh-CN": "Remote Hub 部署", "zh-TW": "Remote Hub 部署", ru: "Развёртывание Remote Hub", ja: "Remote Hub のデプロイ", tr: "Remote Hub Dağıtımı" }, slug: "guides/remote-hub" }, + { label: "Remote Workspace", translations: { fr: "Espace de travail distant", ko: "원격 워크스페이스", "zh-CN": "远程工作区", "zh-TW": "遠端工作區", ru: "Удалённая рабочая область", ja: "リモートワークスペース", tr: "Uzak Çalışma Alanı" }, slug: "guides/remote-workspace" }, { label: "Providers", translations: { fr: "Fournisseurs", ko: "프로바이더", "zh-CN": "提供商", "zh-TW": "供應商", ru: "Провайдеры", ja: "プロバイダー", tr: "Sağlayıcılar" }, slug: "guides/providers" }, { label: "Factory Droid Bridge", translations: { fr: "Pont Factory Droid", ko: "Factory Droid 브리지" }, slug: "guides/factory-droid" }, { label: "Cursor Private Inference", translations: { ko: "Cursor Private Inference" }, slug: "guides/cursor-private-inference" }, diff --git a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md index b28642e0ca..b531e1b307 100644 --- a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md @@ -315,6 +315,9 @@ ocx account main doctor [--json] ocx account main list [--json] ocx account main register