Skip to content

Commit 1cff6da

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feat/user-choose-workspace
# Conflicts: # apps/desktop/src/main/index.ts # apps/desktop/src/renderer/src/store.test.ts
2 parents 0f0f153 + b2e4bfe commit 1cff6da

93 files changed

Lines changed: 7075 additions & 2349 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@open-codesign/desktop': minor
3+
'@open-codesign/shared': patch
4+
'@open-codesign/i18n': patch
5+
---
6+
7+
fix: tighten Always Reportable architecture after 3-reviewer audit
8+
9+
Follow-up to the Always Reportable refactor, consolidating 3 parallel reviews (architecture / privacy / UX).
10+
11+
**Privacy hardening:**
12+
- IPC validators (`parseReportableError`, `parseRecordRendererErrorInput`) cap `message` at 8 KB, `stack` at 16 KB, `context` at 4 KB serialized. Previously a compromised renderer could DoS via 10 MB stack.
13+
- `reportEvent` handler recomputes the dedup fingerprint main-side instead of trusting the renderer-supplied value.
14+
- `recordRendererError` IPC echoes the main-computed `fingerprint` back so the in-memory record matches the persisted row.
15+
16+
**Correctness:**
17+
- All four main-side `computeFingerprint` call sites now pass `message` alongside `errorCode`+`stack`, matching the renderer signature. Previously stack-less errors produced different fingerprints on the two sides, which broke the "you already reported this" dedup.
18+
- `applyGenerateError` reads `err.code` from the rejected IPC error so `ATTACHMENT_TOO_LARGE` / `PROVIDER_HTTP_4XX` / `CONFIG_MISSING` survive into the Report (previously flattened to a generic `GENERATION_FAILED`). `NormalizedProviderError` fields are forwarded into `ReportableError.context`, so the preview's upstream block fires for real provider failures.
19+
20+
**UX:**
21+
- `reportableErrorToast` helper + migrated 13 existing `pushToast({variant:'error'})` sites (onboarding imports, provider test/save/delete/activate, model save, reasoning save, open-log-folder fail, onboarding-blocked inline comments). Each now ships with a meaningful `code` and `scope` for triage rather than the generic `RENDERER_ERROR`/`renderer` fallback.
22+
- Diagnostics panel falls back to rendering the in-memory `reportableErrors[]` when SQLite is unavailable, with a "showing in-memory — will not persist" banner. Previously a DB-down user had no way to find their dismissed toast errors.
23+
- Bundle-saved toast now always fires after the bundle is written, regardless of whether `openExternal` or `clipboard.writeText` succeeds afterward. On failure, a follow-up recovery toast includes a copy-URL / paste-manually hint.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
"@open-codesign/providers": minor
3+
"@open-codesign/desktop": minor
4+
"@open-codesign/shared": minor
5+
"@open-codesign/core": minor
6+
"@open-codesign/i18n": patch
7+
---
8+
9+
feat(codex): unify ChatGPT subscription path onto pi-ai's built-in openai-codex-responses wire
10+
11+
Phase 2 of the Codex subscription login work. The self-rolled Codex client
12+
path from Phase 1 is replaced by pi-ai's first-class `openai-codex-responses`
13+
adapter (shipped in pi-ai 0.67.68) so every provider — Anthropic, OpenAI,
14+
Gemini, ChatGPT Codex — now runs through the same core/pi-agent-core route
15+
with no provider-specific branching.
16+
17+
### Schema + routing
18+
- `packages/shared`: extend `WireApiSchema` and `CanonicalWire` with
19+
`openai-codex-responses`; promote `CHATGPT_CODEX_PROVIDER_ID` to shared so
20+
`provider-settings` references the same literal the OAuth module writes
21+
without creating a module cycle.
22+
- `canonicalBaseUrl` passes codex URLs through untouched (pi-ai's wire
23+
appends `/codex/responses` itself); `modelsEndpointUrl` throws for codex
24+
(no discoverable /models endpoint — providers use `modelsHint`).
25+
- `packages/core`, `packages/providers`: `apiForWire` + `synthesizeWireModel`
26+
recognize the new wire; all 4 duplicated `'openai-chat' | …` unions
27+
consolidated onto the shared `WireApi` type.
28+
29+
### Desktop wiring
30+
- New `apps/desktop/src/main/resolve-api-key.ts`: dependency-injected helper
31+
that routes ChatGPT provider id to the token store's auto-refreshing
32+
access token, and every other provider to the keychain-backed API key.
33+
Codex auth failures surface as `CodesignError(PROVIDER_AUTH_MISSING)` so
34+
the renderer's error-code routing stays consistent with the API-key-missing
35+
path. Covered by 7 unit tests via DI.
36+
- `main/index.ts`: `resolveActiveApiKeyFromState` replaces the inline
37+
`isChatgptCodex` validate / dispatch branches in all 4 IPC handlers
38+
(`codesign:v1:generate`, legacy `codesign:generate`, apply-comment,
39+
generate-title). Legacy `codesign:generate` no longer rejects codex.
40+
- Long-running agent runs: `GenerateInput.getApiKey` is a new optional async
41+
getter; the desktop passes it only for codex so pi-agent-core calls back
42+
into the token store on each LLM round-trip (auto-refreshes within the
43+
5-min buffer). Mid-run sign-out errors are captured in a closure variable
44+
and rethrown verbatim from the post-agent branch so the structured
45+
`PROVIDER_AUTH_MISSING` code isn't lost to pi-agent-core's plain-string
46+
failure-message flattening.
47+
48+
### Registration + migration
49+
- `codex-oauth-ipc.ts`: provider entry registers `wire=openai-codex-responses`,
50+
bare `baseUrl=https://chatgpt.com/backend-api`, and the full 9-model catalog
51+
(gpt-5.1 → gpt-5.4-mini), ordered flagship-first.
52+
- `migrateStaleCodexEntryIfNeeded()` runs once at boot and rewrites any
53+
Phase-1-shaped `chatgpt-codex` provider (`wire=openai-responses`,
54+
`baseUrl=/codex`) to the Phase 2 canonical values, so feat-branch testers
55+
don't need to sign out and back in after upgrade. No-op when the entry is
56+
absent or already canonical.
57+
58+
### UI
59+
- `ChatgptLoginCard.tsx`: flipped out of "coming soon" mode back to the full
60+
three-state login/status/logout flow, with i18n keys in both locales.
61+
62+
### Deletions (-963 LOC of Phase 1 code now provided by pi-ai)
63+
- `apps/desktop/src/main/codex-generate.ts` + test
64+
- `apps/desktop/src/main/codex-title.ts`
65+
- `packages/providers/src/codex/client.ts` + test
66+
67+
OAuth-side code (`oauth.ts`, `oauth-server.ts`, `token-store.ts`) is unchanged
68+
— still the only codex-specific code, and it sits outside the generation link.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@open-codesign/desktop': patch
3+
'@open-codesign/core': patch
4+
---
5+
6+
fix: send attached screenshots to ChatGPT Codex as image inputs
7+
8+
Image attachments in the desktop app were previously reduced to filename-only hints on the `chatgpt-codex` route, so models like `gpt-5.4` could ignore uploaded screenshots entirely.
9+
10+
This change keeps the existing text-attachment behavior, but reads supported image files into data URLs and forwards them as Responses `input_image` parts for ChatGPT Codex generations.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@open-codesign/desktop': patch
3+
'@open-codesign/i18n': patch
4+
---
5+
6+
feat(settings): auto-discover models in custom provider modal
7+
8+
When adding a custom provider (e.g. a CPA at http://127.0.0.1:8317), the modal now probes the endpoint automatically after the user types a valid http(s) baseUrl, debouncing 500ms. A spinner appears inline next to the "Default model" label while discovery runs, then either a green "Found N models" badge or a muted "Could not connect" hint.
9+
10+
On success the "Default model" input becomes a `<select>` pre-populated with discovered model IDs, with smart auto-selection prioritising claude-sonnet-4-5 → claude-opus → claude-sonnet → gemini-2.5-pro → gpt-5 → first in list. A "Enter manually" escape hatch lets users type any ID instead, and a "Pick from list" link restores the dropdown. The probe re-fires when the API key or wire protocol changes. Empty or non-http(s) baseUrls are skipped so the existing manual flow is completely unaffected.

.changeset/cpa-preset.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@open-codesign/desktop': minor
3+
'@open-codesign/shared': patch
4+
'@open-codesign/i18n': patch
5+
---
6+
7+
feat(settings): add CLIProxyAPI preset quick-pick
8+
9+
Adds CLIProxyAPI (`router-for-me/CLIProxyAPI`) as a first-class preset in the Add Provider menu. CLIProxyAPI is a Go local proxy on port 8317 that wraps Claude/Codex/Gemini OAuth subscriptions into a unified Anthropic Messages API — heavily requested by the Chinese user base.
10+
11+
- `packages/shared`: new `cli-proxy-api` entry in `PROXY_PRESETS` (anthropic wire, `http://127.0.0.1:8317`)
12+
- `packages/i18n`: `settings.providers.cliProxyApi.*` keys in both `en.json` and `zh-CN.json` (preset name, description, api-key-optional hint, thinking-budget hint, model discovery strings)
13+
- `apps/desktop`: `AddProviderMenu` gains a CLIProxyAPI item that opens `AddCustomProviderModal` pre-filled with the CPA endpoint and anthropic wire; claude-cli identity headers are injected automatically by the existing `shouldForceClaudeCodeIdentity` path (no extra code needed)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@open-codesign/desktop": patch
3+
---
4+
5+
Fix: allow larger binary attachments (images/png) up to 10MB. Binary attachments only contribute filename to context so size limit can be larger.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@open-codesign/desktop": patch
3+
"@open-codesign/i18n": patch
4+
---
5+
6+
Fix Settings so Ollama is hidden until users add the local provider manually.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
'@open-codesign/desktop': patch
3+
'@open-codesign/shared': patch
4+
'@open-codesign/i18n': patch
5+
'@open-codesign/providers': patch
6+
---
7+
8+
fix: 3-reviewer adversarial round — privacy, UX, correctness
9+
10+
Third consolidated round of fixes from three parallel adversarial reviewers.
11+
12+
**Privacy (from R1):**
13+
- Issue URL `logs=` and `actual=` fields now go through the same redact pipeline as `summary.md`. Previously the URL (which ends up in browser history + referrer + shell history) silently ignored the user's redact toggles.
14+
- `bundlePath` in the issue URL now renders as `~/Downloads/...` rather than `/Users/<realUsername>/...`, so OS username isn't leaked through the link.
15+
- `config-redacted.toml` now applies path + URL redaction per toggle, so raw IPs in `baseUrl` and filesystem paths in `[designSystem]` get masked when the user unchecks Paths/URLs. The filename is no longer a lie.
16+
- `API_KEY_RE` broadened to catch Google Gemini `AIzaSy…`, AWS `AKIA…`, and 43-char Azure base64 keys.
17+
- `setWindowOpenHandler` is now gated through `isAllowedExternalUrl`, matching the existing allowlist for the IPC channel.
18+
- `showItemInFolder` rejects paths outside config/logs/Downloads to prevent a compromised renderer from revealing arbitrary files in Finder.
19+
20+
**UX (from R2):**
21+
- Redaction placeholders changed from `<prompt omitted>` / `<path omitted>` / `<url omitted>` to `[prompt omitted]` / `[path omitted]` / `[url omitted]`. GitHub's markdown renderer was stripping the angle-bracket form as HTML tags, leaving users and triagers looking at empty redacted fields.
22+
- `summary.md` Message field now uses a backtick-safe inline code span (`mdInlineCode`), so error messages containing backticks don't eat the lines that follow.
23+
- Report dialog panel has `max-h-[90vh] overflow-y-auto` so buttons stay on-screen at 1280×720 viewports.
24+
- Dedup warning now shows the prior issue number (`#123`) when extractable from the stored URL.
25+
- Confirm step ("Yes, open anyway") has a 60-second countdown visible on the button.
26+
- Notes-too-long error is now localized.
27+
- Toast Report button shows a Loader2 spinner while the auto-record IPC is resolving.
28+
- Report bundle-saved toast only appears AFTER `openExternal` / `clipboard.writeText` succeeds, so a silent failure doesn't flash a green success toast alongside an error banner.
29+
- User notes are now injected into the bug_report.yml `actual` field, not just the zipped bundle.
30+
- Windows `platform_version` maps NT build (`10.0.22631`) to marketing name (`Windows 11 (10.0.22631)`).
31+
32+
**Correctness (from R3):**
33+
- Fingerprint basis includes a hash of `message` when the stack is empty. Previously all renderer errors without stacks collapsed to the same fingerprint and triggered false "already reported" warnings.
34+
- `ReportEventDialog` is now mounted once at the App root via a single store slice (`activeReportEventId`). Previously each error toast mounted its own dialog, so opening Report on two toasts stacked two overlays.
35+
36+
**i18n:**
37+
- Filled in three missing English keys (`loading.tokens`, `settings.providers.missingKey`, `settings.providers.addKey`).
38+
- `{relative}` single-brace interpolation finally fixed (it was rendering literally because i18next expects `{{relative}}`).
39+
40+
**Test coverage:**
41+
- Added regression tests for each privacy leak, the fingerprint collision, the store's auto-record chain, and the dedup countdown.
42+
- 779 desktop + 153 shared tests pass.

apps/desktop/electron-builder.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ mac:
2828
arch: [arm64, x64]
2929
dmg:
3030
# Custom window layout guides users to drag the app into /Applications.
31-
# Running from the DMG mount leaves safeStorage unavailable (the volume
32-
# is read-only so macOS can't establish a keychain trust entry), which
33-
# breaks API key save / import. The background, arrow, and in-app boot
34-
# check (install-check.ts) work together to steer users to the right
35-
# flow.
31+
# Running Open CoDesign from a mounted DMG instead of /Applications
32+
# breaks (1) the auto-update code path (read-only volume can't receive
33+
# electron-updater's staged binary), and (2) XDG-style user-data-dir
34+
# resolution (Electron falls back to a path inside the mounted image
35+
# which disappears when the volume ejects). The background, arrow, and
36+
# in-app boot check (install-check.ts) steer users to the right flow.
3637
background: build/dmg-background.png
3738
iconSize: 92
3839
window:

0 commit comments

Comments
 (0)