Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
31cee9b
docs(updater): map safe restart admission ownership
devswha Sep 7, 2026
9691569
feat(updater): add authenticated preparation controls
devswha Sep 7, 2026
6f99642
fix(updater): keep snapshot validation compatible with ES2020
devswha Sep 7, 2026
49c1010
fix(updater): validate preparation in the isolated desktop app
devswha Sep 7, 2026
da8a0c5
feat(updater): connect admission and preserve unsent drafts
devswha Sep 8, 2026
7ef7cda
fix(ci): include authored engine tests in the SSOT inventory
devswha Sep 8, 2026
e143546
feat(updater): implement verified installation transaction primitives
devswha Sep 8, 2026
c64d8aa
feat(updater): connect guarded startup and successor recovery
devswha Sep 8, 2026
402dd25
feat(updater): retain runtime and draft ownership through restart pre…
devswha Sep 8, 2026
06bbc51
fix(server): persist job interruption before watcher shutdown
devswha Sep 8, 2026
721806d
feat(updater): integrate SDK lifecycle patch and draft owner bridge
devswha Sep 8, 2026
4fb43c2
feat(updater): integrate native restart and durable attachment handoff
devswha Sep 8, 2026
4e0bf66
feat(updater): track SDK producers and preserve restart activations
devswha Sep 8, 2026
f69ec4f
feat(updater): apply durable consent in admitted release builds
devswha Sep 8, 2026
6280f49
docs(updater): record notarized same-source qualification checkpoint
devswha Sep 8, 2026
5aecb49
fix(deps): verify ZIP security backport and update vulnerable parsers
devswha Sep 9, 2026
c89a9de
docs(updater): record signed automatic update and data preservation
devswha Sep 9, 2026
cc812b4
docs(release): record verified local updater key custody
devswha Sep 9, 2026
e28fa6d
chore(release): prepare beta.11 desktop test build
devswha Sep 9, 2026
a649273
test(website): distinguish published releases from local candidates
devswha Sep 9, 2026
1c58693
docs(release): record accepted beta.11 test installer
devswha Sep 9, 2026
c400d48
feat(updater): install only after a sidebar update click
devswha Sep 9, 2026
48fffce
chore(release): prepare beta.12 click-update distribution
devswha Sep 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ job projection protocol). `scripts/` holds build/release/verify tooling.
- Bun **exactly 1.4.0** for `*.bun.test.ts` and `*.dom.bun.test.tsx` files (pinned in
`scripts/fetch-bun.mjs`): `dist-native/bun` or PATH; fetch with
`node scripts/fetch-bun.mjs`.
- `npm ci` applies the app-owned SDK lifecycle patch from
`patches/gjc-sdk-lifecycle/manifest.json` through postinstall. Exact SDK/core/AI
versions and complete before/after hashes are mandatory. Use
`npm run apply:sdk-patch` / `npm run check:sdk-patch`; never hand-edit installed
dependency files. Unknown local modifications must fail rather than be replaced.
- Server binds loopback by default (fail-closed; it can run shell commands).
`SERVER_PORT` defaults to 3001, Vite dev on 5173. Do not export `SERVER_PORT=0`.
- Tauri builds choke on `CI=1`: use `env -u CI npm run tauri -- build`.
Expand Down Expand Up @@ -151,11 +156,32 @@ is `.ts`/`.tsx`. Routing is react-router-dom 7.
unknown dependencies. Do not add cross-module imports that violate them.
- **Product identity is checked**: `npm run check:identity` verifies names/URLs/scheme
against `shared/productIdentity.js`. Change identity constants there, nowhere else.
- **Desktop updates are click-driven**: `automatic` means discovery checks only.
Download/restart require the native `targetId`; cached bytes alone cannot
authorize startup installation. Preserve one-shot manual intent consumption
and the draft/backend/process gates. Current contract: `docs/DESKTOP-CLICK-UPDATE.md`.
- **Design system**: all product colors route through semantic CSS variables in
`src/index.css` + the `@theme` color aliases in the same file. See `DESIGN.md` before
touching UI styling; do not hardcode palette values.
- **Bundled runtime manifest**: `server/gjc-runtime-manifest.json` is filled by
`npm run fill:runtime-manifest` (runs automatically before dev/build:server).
Schema 2 includes the native closure and the canonical SDK patch's post-hashes.
Worker startup checks both and refuses mismatched/nested dependency instances.
A verified SDK patch is source-integrity evidence, not proof of complete SDK
quiescence; unrepresented streaming/extension work must still block restart.
`shared/sdkLifecyclePolicy.json` owns the file-count bound used by the applier,
worker and native payload/archive guard. After changing the canonical patch,
reapply it through a clean install and explicitly regenerate tracked runtime
hashes with `npm run fill:runtime-manifest -- --update` before verification;
normal dev/build gates only check the manifest and do not bless changed hashes.
- **Browser archive security backport**: `patches/extract-zip-symlink-leaf/manifest.json`
owns the exact extract-zip 2.0.1 upstream PR160 transform. Postinstall applies
it; `npm run check:extract-zip-patch` verifies canonical source/package hashes
and rejects nested, aliased or modified installations. Server/desktop staging
must carry and verify this independent patch. Do not put it in the SDK32
lifecycle manifest or hand-edit node_modules. Audit recognition is conditional
on the actual patch and a current review, not an unconditional advisory skip.
Its archive-only protection is not a sandbox against concurrent local writers.
- **Chat tool cards follow the runtime, not Claude**: `src/components/chat/tools/configs/toolConfigs.ts`
is keyed by the tool's own lowercase name (`bash`, `read`, `edit`, `todo_write`), and
its accessors read the runtime's parameter schema. `server/gjc-tool-configs.bun.test.ts`
Expand Down
8 changes: 8 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ The system uses Tailwind's 4px spacing scale. Existing values like `p-2`, `gap-2
- **Accessibility**: disclosure buttons expose `aria-expanded` and `aria-controls`; all icon-only actions have names and titles, and every control preserves a visible focus ring.
- **Responsive behavior**: desktop and mobile preserve the same information order and one scroll owner, with touch-sized primary rows on mobile.

### Desktop Update Notice

- **Placement**: a compact `bg-card`, `border-border`, `rounded-lg` card sits immediately above Settings in the fixed sidebar footer. The collapsed rail keeps an accessible update-details icon immediately above its bottom Settings control; opening details only expands the sidebar, without a modal or automatic focus change.
- **Visibility**: only confirmed native snapshots with a target introduce a notice. Web, disabled, idle, and no-target states stay hidden. Dismissal is page-memory-only and scoped to the native target, so a different target can appear. About remains available for a dismissed target.
- **Actions**: Update is an explicit click, for available or prepared targets with native installation support. The shared hook owns download and one safe, target-bound restart. Automatic means discovery checks only; rendering, checking, or opening the sidebar never installs anything. Busy, changed-target, and failed operations explain the next user action and never auto-retry.
- **Status**: translated polite live text accompanies download/verification progress; unknown totals remain indeterminate. Pending or unresolved operations lock mutations. Disconnected snapshots are labelled as last-confirmed and cannot enable mutations. Read-only status refresh remains available when no request is pending, including connection failures and recovery; recovery never offers installation controls.
- **Accessibility**: owned Button controls retain visible focus rings and translated names; release metadata remains plain text. The About panel keeps installed/target versions, bounded keyboard-readable notes, manual-update guidance, and the OS-approval caveat.

### Chat Pane

- **Structure**: `ChatMessagesPane` owns scroll; `ChatComposer` is fixed at the bottom of the chat column.
Expand Down
4 changes: 2 additions & 2 deletions THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9522,7 +9522,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```

### js-yaml 3.15.1
### js-yaml 3.15.2

License: MIT
Copyright holder: Vladimir Zapparov <dervus.grim@gmail.com>
Expand Down Expand Up @@ -17235,7 +17235,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

### multer 2.2.0
### multer 2.3.0

License: MIT
Copyright holder: Hage Yaapa <captain@hacksparrow.com> (http://www.hacksparrow.com)
Expand Down
96 changes: 96 additions & 0 deletions docs/DESKTOP-CLICK-UPDATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Desktop updates: check automatically, install only after a click

The user's September 9, 2026 request supersedes the previous automatic-download
and automatic-next-launch-install policy. The new interaction is a compact
notice immediately above Settings in the bottom-left sidebar.

![Update notice above Settings — UI fixture, not a live installation](images/updater/click-update-notice.png)

## Behavior

1. The existing schedule discovers release metadata only. An eligible release
becomes `available`; merely checking or opening the app does not download it.
2. The user presses **Update**. Native download admission binds the exact
offered target; it does not rediscover and silently substitute a newer one.
3. After signature/archive verification, the same document requests one
target-bound safe restart. Draft sealing, backend admission, owned-process
shutdown, installation journal and successor health gates remain mandatory.
4. Busy work, target changes, connection loss, errors and unknown state stop
that UI attempt. There is no automatic restart retry when work later ends.
Rate-limited clicks are rejected without queueing a hidden download; retry
requires another user click after the limit expires.

`automatic` retains its wire/preference field name but means **automatic checks**
only. Neither `automatic: true` nor an existing verified cache permits next-launch
installation. Only a matching explicit manual restart intent can proceed into
the existing native install gate. Legacy schema-1 unbound intents are not accepted;
new schema-2 intents bind both the target ID and the actual archive SHA-256.
The first admitted startup durably consumes that selection before location,
network or installation preflight. If preflight fails, a later ordinary launch
does not replay the click; a fresh explicit request is needed. An existing
installation journal retains its separate verified-successor recovery path.

## State and authority

- `shared/desktopUpdateProtocol.ts` owns the UI contract. Snapshot `targetId` is
required (nullable without a target); `download` and `restart` require it.
The native ID hashes a fixed domain, release/asset IDs and raw manifest bytes.
Restart rechecks both the snapshot and prepared record, including same-version
substitutions. The browser supplies no URL, path, signing key or installer.
- This native updater interface has not been publicly enabled. Its strict
protocol-1 schema evolves as one bundled native/server/client unit: old partial
snapshots and unbound commands fail closed, with no compatibility fallback.
Private backend framing and draft challenge protocols are unchanged.
- One document-scoped client shares polling, pending mutations and the user's
click between Sidebar and About. Sidebar mode swaps preserve its stable owner;
full unmount or bridge replacement retires the click. A UI timeout does not
cancel or duplicate native execution.
- Ordinary web and updater-disabled builds show no native sidebar update action.
A retained disconnected snapshot is read-only; Refresh performs only a status
read. Dismissal is in-memory and target-specific, surviving sidebar mode swaps
while allowing a different target to surface.
- Unknown download progress is indeterminate, never a fabricated percentage.
The collapsed rail exposes a labelled details icon directly above bottom
Settings. English, Korean and all other existing settings locales retain key
parity. About uses the same state and explains checks-only behavior.

## Verification scope

Focused checks cover the shared client/real injected bridge, HTTP/protocol
validation, native discovery/explicit download, cached startup consent,
same-target restart, cancellation, duplicate clicks, stale responses, rate limits,
Sidebar/Settings behavior and locale parity. Full source and native gate results
are recorded in the current handoff.

- Full `npm run verify` passed (`/private/tmp/gajae-click-update-full-verify-final.log`).
- Native clippy with `-D warnings` and all native tests passed: 340 unit + 10
binding tests; 6 dedicated/optional helpers ignored
(`gajae-click-update-consume-clippy.log`, `gajae-click-update-native-accepted.log`).
- Shared client, actual injected bridge, Sidebar and About DOM union: 59 passed;
HTTP/relay/protocol union: 76 passed. Native tests include one-shot intent
consumption across reopen and concurrent consumers, and rate-limited clicks
without hidden delayed retries.

Browser visual QA renders the actual SidebarFooter/SidebarCollapsed/update
components with the app CSS and React Compiler in a clearly labelled local
state fixture. At the native minimum 960×640, the expanded card fits above
Settings (card bottom 556px; Settings top 562px). Light/dark, indeterminate
download, collapse/expand, dismissal and new-target redisplay were checked.
The fixture recorded one download and one restart request after the explicit
click. This is **UI/protocol evidence, not actual app replacement**.

This change has not yet been rebuilt into a new signed two-version QA pair or
publicly enabled installer. Earlier signed automatic-update QA proves the old
policy only; do not reuse it as acceptance of this click-based flow.

## Current installed beta.11 and bootstrap

The previously delivered beta.11 / desktop 0.2.5 DMG is updater-disabled and
unchanged. To update it now, the user installs a newer DMG manually after quitting
the app. It cannot receive this implementation through an update button it lacks.

A first click-update-enabled installer therefore still requires one manual
installation. Subsequent releases can use the sidebar button after production
binding, signed artifact acceptance and the remaining release gates are complete.
The UI fixture does not enable production updates, create a release or modify
the user's installed application.
7 changes: 7 additions & 0 deletions docs/DESKTOP-QA-PROFILE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ the filesystem profile; keep its UUID with the QA evidence. Deleting the QA
directory alone does not erase that WebKit store. QA profiles are not portable.
No production browser profile is inspected or copied by this mechanism.

QA pins the automation bridge to the short `a.sock` path directly under its
private profile root. This avoids silently truncated Unix socket names when
the child inherits a long profile-specific `TMPDIR`. Roots that cannot fit the
platform socket address capacity are rejected before the profile is initialized.
Updater preparation's real-app QA is recorded separately in
[DESKTOP-UPDATER-QA-PREPARATION.md](DESKTOP-UPDATER-QA-PREPARATION.md).

The bundled runtime requires macOS 13 or later. On macOS 13, QA mode refuses
startup rather than silently falling back to WebKit's default store. Other
platforms reject this option. A disposable OS account remains useful for
Expand Down
Loading