mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-21 05:06:37 +00:00
55 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6a6367b560
|
chore(opencode): retire adaptations for runtimes and events OpenCode V2 no longer produces (#1034)
## Summary This PR removes OpenCode compatibility code that nothing can reach any more: - Code that was already dead at the former 2.0.27 minimum, and is still dead at the current 2.1.0 minimum (#1029). - Handlers for events and data shapes that OpenCode V2 never produces. Each item was checked against the upstream 2.0.27 and 2.1.0 sources before removal. Kept on purpose: - Workarounds for upstream bugs or limits that are still present in 2.1.0. - Code that reads conversations written by older runtimes: V1-migrated tool names and metadata, `workspaceID` data, task summary titles, `session-legacy` replay. - Code that recognises and upgrades old CLIs and live older daemons: 1.x replacement, beta recognition, 2.0.11 service discovery, 2.0.15 native upgrade, `/api/status` and `/api/health` identification. ## Removed or changed **Server** - Negotiation: one "not modern → `canonical_api`" rule replaces the pre-2.0.4 legacy schema recognition, and runs before #1029's `native_contract` check. - The transport no longer rewrites `/api/status`. - Desktop skills no longer send the pre-2.0.4 `location` and `slash` fields. - The legacy `auth.json` usage fallback for daemons without `credential.list` (pre-2.0.20) is removed, along with its UI reason and the i18n key in 10 locales. A missing endpoint still fails safely. - Workspace selectors are rejected up front, without a native resolution request. - CLI service probes try `/api/info` first. An admitted daemon no longer costs two authenticated 404s on every check. **UI** - Remaining V1 `session.idle`/`session.status` branches: Missions store, pending discovery (UI and server), `eventAffectsMessages`. - `server.instance.disposed` and the now-unused `rehydrateInstance`. - The V1 `worktree.ready` envelope (the handler now reads the V2 shape). - V1 tool-state titles and the `success` status alias. - Part `time.start` and `time.end`. - Text stored as objects or segment arrays. - `deriveMessageStatus`. - The V1 `error.data.message` shape. - `projectID` and `location` fallbacks on `session.created`. - The replay-only `session.message.content.updated`. - The unreachable `output.answers` fallback. **Fixtures, Missions and docs** - Legacy branches removed from the location, fork, families, pruning and automation native fixtures. The WSL setup fixture now compares against the reported version instead of 2.0.11. - Unused 2.0.21 launch helpers removed. - The Missions native and trajectory fixtures also run on the minimum lane. - The capability proof checks the reported version. - Stale 2.0.2x labels now say "as of the 2.1.0 minimum". **Follow-ups from the #1029 post-merge review** - Test fixtures no longer send the ignored `recent: ""` compaction field (18 sites). - The manual compaction-isolation fixture accepts any published version at or above the minimum. - `CONTRIBUTING.md` wording updated. 114 files, +319 / −1117: source +90 / −487, tests/fixtures/CI +214 / −604, i18n −10, docs +15 / −16. ## Validation (rebased on dev with #1029) **Typechecks:** server and UI pass. **Server tests** - Touched areas: 480/480. - Full server CI step: 2430 pass, 0 fail, 7 skipped, 1 cancelled. The cancelled test is the `index.test.ts` real-process shutdown test; it hit its 5 s timeout under load. It passes alone (4/4), and that file is unchanged versus dev. **UI unit tests** - Touched files: 230/230. - CI steps: 574/574, 200/200 and 519/519. **Browser suites**, one at a time: - Provider and service usage: provider-usage 13/13, service-usage 3/3. - Missions: mission-visibility 3/3, mission-control-feedback 5/5, mission-lifecycle-revision 10/10, mission-lifecycle-navigation 10/10, mission-current-passage 1/1, mission-native-family 11/11. - Transcript and rendering: compaction-responsiveness 5/5, session-rendering 47/47, reasoning-collapse 3/3, render-cost 17/17, tool-images 4/4, system-messages 10/10. - Other: search-highlight 11 pass (1 skipped by its env gate), panel-extensions 13/13. **Native fixtures on an isolated 2.1.0 CLI:** location, session-fork, automation, session-pruning, missions native, missions trajectory, provider-usage, Missions capability proof and compaction-isolation all pass. The WSL setup fixture was not run (it needs a WSL distro with a Linux CLI). ## Left for later - `RuntimeIdentity.discovery` is now write-only. - `ownsLocation` has an unused `_client` parameter (about 30 callers). - A test-only V1 translation in `auto-accept-manager.test.ts`. - Out of scope: HTML-entity decoding (a product decision), the `MutableHashMap` loop, the pruning-UI import-order workaround, unused log-based Missions readers, and the unshipped managed-owner module with its 2.0.24-pinned test. Oversized source files touched: `stores/instances.ts` ~2,209, `message-block.tsx` ~1,601, `workspaces/manager.ts` ~1,104, `tool-call.css` ~1,047, `tool-call.tsx` ~865, `opencode-data.ts` ~865, `api-types.ts` ~784, `session-events.ts` ~606, `recurring-day-fixture.ts` ~535. |
||
|
|
d6a890fba7
|
chore(opencode): qualify 2.1.0 and adopt its native contracts (#1029)
Adopt the OpenCode 2.1 native replay and compaction contracts, align client/plugin pins and set minimum and recommended runtime to 2.1.0. Preserve authenticated contract recognition for future/custom runtimes and explicit installation/restart boundaries. Preserve historical conversations through official projection-based pruning revisions and independently checked migrations from 2.0.3, beta-19271 and 2.0.32. Retain ownership, execution claims, stale-selection checks and transaction fences. Update setup, help and qualification evidence. Isolated Windows native qualification and integration checks cover pruning UI, historical reimport, Compare/Wayfinder, recurring Missions, builds and typechecks. Document broad-suite limitations and outstanding platform/package/mobile acceptance; this merge does not publish CodeNomad 1.0.0. |
||
|
|
debbdce33f
|
feat(missions): add a "Compare two models" Mission template (#1026)
## Summary Adds a fifth Mission template, **Compare two models** (`compare`). It runs the same bounded task on two different models and ends with a blind verdict. - **Creation:** the user picks **model A** and **model B** in the main creation form. Both are required and must name different models (provider + model id; a reasoning variant alone is not a different model). This is enforced on every creation path: HTTP, prepare, recurrence create and agent-started missions. - **Roles:** `model-a`, `model-b` and `comparator`. - A and B share one instruction text and report contract. - The coordinator writes the task, inputs and criteria once, and gives both byte-identical briefs. - The server refuses a run task whose brief differs from its sibling's, or whose per-task execution would change its role's model. - **Blind judge, always on:** the comparator works on neutral X/Y labels. - It reports one versioned `comparison` artifact: the A/B task references, per-criterion scores for both runs, sourced observations, and a verdict `a | b | equivalent | inconclusive`. - Completion requires both runs and that comparison. - **Judge model:** frozen once at creation, like every other role. - An explicit judge is kept; otherwise the judge copies the coordinator's effective model. When that model is unknown, both stay on the native default. - Replays and retries therefore reuse the stored profile. - The editor warns when the judge's model equals A or B. - **Readers:** the verdict, both model names, a score table and evidence by path. Hashes stay under Technical details, for current and archived recurring passages. The template came out of evaluating Harness2's comparison loop. It deliberately has **no** lesson, human approval, budget or duration handling, and leaves the Wayfinder human gate unchanged. Up to five models, per-run worktrees and launching from the composer's model picker (OpenChamber-style multi-run) are left for later. `AGENTS.md` records the single editor exception: the A/B selectors sit outside the collapsed Options disclosure. All ten locales are updated. ## Size and upkeep 62 files, +837/-96: | Part | Lines | |---|---| | Product code (about 16 files are one-line template-list hooks) | +280/-57 | | Locales (13 keys × 10) | +131 | | Tests | +409 | | Docs | +17 | `missions/control.ts` stays oversized (~1,500 lines). ## Validation - Full server suite: 2,426 tests pass, 7 existing skips. Root and server typechecks, the server build and the plugin build pass. - UI: 45 unit tests and 36 browser tests pass. - The native trajectory fixture, extended with a compare case, passes on OpenCode 2.0.31. It checks two distinct models, a one-newline brief difference refused with the journal unchanged, a real blind judgment and a completed mission. The native contract and recurring Q fixtures also pass. - Regressions cover: - distinct-model refusals on every creation path; - brief and override refusals; - artifact validation and the completion policy; - judge freezing at creation, revision replay, and retry after a coordinator model change; - editor inheritance and readable evidence. - Independent review rounds ended with no P0-P3 findings. - The editor and reader were checked from screenshots of the real Solid components in the browser harness, not in a packaged app. |
||
|
|
b2d5b722ec
|
feat(automation): complete safe native window interactions (#1018)
Complete application-window interaction on the shared page engine introduced by #1015, while preserving native window/run and document-scoped ref authority. Add real pointer clicks, hover, stepped pointer dragging, wheel scrolling, keyboard chords and bounded text waits. Flat tool commands are validated at both bridge boundaries. Clicks refuse covered targets; press(ref) refuses a target that cannot acquire focus, so Enter never reaches an unrelated draft. Drag requires both ends visible instead of scrolling under a measured source. Preferences remains outside automation; focusing Preferences or a remote window falls back to the most recently used local application window. Trusted native input carries monotonic provenance intervals. Human Form decisions check the originating event timestamp, not the time a stalled renderer handles it; delayed keys and their implicit submit clicks remain automated after lease expiry. Fixed page functions keep their depth marker. Native events use the page's epoch clock, and cleanup preserves the original press timestamp, independently of configured command timeouts. Failed sequences best-effort release held buttons and keys, including when the cleanup mark write itself times out. An admitted input timeout is reported as an unknown outcome with inspection-before-retry guidance: the renderer may deliver the input or finish the click later. Never replay these inputs. Validation covers the actual Mission editor and InterruptionDock in isolated Chromium, including a 16-second renderer freeze and a control human click. Targeted server tests cover key mapping, both bridge parsers, focus/target fences, failure cleanup and late input outcomes. Full server validation, isolated OpenCode 2.0.31 automation, bundle regression and Tauri compilation also pass; typecheck diagnostics remain at baseline. No installed application or shared daemon was changed or restarted. Four independent gatekeeper passes; the final review reports zero actionable P0-P3 findings at 0ffb5a53b425500336854902c7068cd2233695f4. Refs #1008. |
||
|
|
1932da9307
|
feat(automation): shared page engine with budgeted outlines, select and replacing type (#1015)
codenomad.inspect/act could not fill real forms (#1008): type appended to a prefilled field, native <select> could not be changed, and inspections were a flat JSON list silently cut after 750 nodes. Page automation now lives in a transport-agnostic engine under packages/server/src/automation/page/, used by DeveloperCdp for the CodeNomad window and designed to carry the browser preview next: - snapshot.ts renders the accessibility tree as an indented plain-text outline with refs. Wrappers, unnamed images and text repeating a name computed from contents are dropped; fields show their value (numeric ones included) instead of inner nodes; native selects list options with selected/disabled. A 32 000-character budget is shared among siblings: small parts stay whole, large ones collapse in place with "(+N hidden)" or keep their first and last items around "(+N more)". inspect accepts ref (one subtree) and query (exact role, or text in name/value/description, with contents and ancestors). - refs.ts names a DOM node per target, run and navigation epoch; a ref keeps its name and stays usable for the whole page generation. - actions.ts acts through fixed page functions whose inputs travel as protocol arguments. type refuses disabled fields and fields that cannot take focus (closed disclosure, modal dialog), so text never lands in another field; it replaces the field's text by default, clear: false appends (email/number through their value). Date/time/number/range/color values are validated before anything changes and keep the browser's normalization. select picks options by label, else value, dispatching input/change only on a change; clicking an option ref picks that exact option. Results return the field value or chosen labels; page exceptions are reported. The trust model is unchanged and documented: in the CodeNomad window page functions run under __codenomadAutomationDepth, clicks stay programmatic and native text insertion yields only input events, so automation can never produce the trusted dock interaction a human Form answer requires. Validation: snapshot unit tests (exact outlines, query, scope, fair collapse, budget property), updated controller/plugin/route tests, and a real-Chromium regression driving DeveloperCdp over the DevTools endpoint, including the real Mission editor (title replaced, chosen playbook reaches the created mission) and every reviewed edge case. Full server suite green apart from a load-only 5 s timeout in index.test.ts that passes alone; isolated native automation fixture passes on OpenCode 2.0.31. Three gatekeeper rounds; the last found no P0-P3 issue. Closes #1008. |
||
|
|
b4f1dde4f8
|
feat(missions): coordinator hand-offs, task interrupts and native decision evidence (#1013)
Completes the coordinator frictions of #1009 left after #1011 (points 4 to 9) and repairs the recurring Wayfinder human-mark journey checks. mission.interrupt({ taskKey }) stops a retired native task's conversations through the authenticated bridge: the coordinator's direct children whose first user message carries that task's canonical assignment header. Each family is interrupted deepest first, then the conversation, with lifecycle Stop's post-interrupt recheck, settle and quiet verification; queued inputs are cancelled under the worktree-deletion fence. It refuses while any open task lives in that conversation's family (reuse or nesting chains, or its actor), and never touches the coordinator, other tasks or the plan. mission.prepare creates a paused one-time hand-off through the editor's prepareMissionCreation pipeline, holds and fences, and never starts it. A trusted preparedBy gives the preparing coordinator read-only visibility (inspect({ missionID }), inspect({ list: true })), never control. Retries read the journal's creation event first and are reported uncertain, never as nothing created. mission.inspect({ taskKey }) adds the task's observed native conversations as advisory evidence; the task-key parser is shared with the UI. A native Wayfinder decision readout may omit its artifact: the gate's discover() derives candidates from exact native structure only and verifies each; only a complete discovery with exactly one candidate fills it. requestID "auto" briefings may let the server pick the revision. One replacement may merge several retired tasks, and the task reader lists every predecessor. Scheduled passages, which have no backend route, are not offered the new tools. The Q and N journeys queried a retired human-marks key pattern; they now read HUMAN_MARK_STORAGE_PREFIX, and the Q UI run exercises discovery natively. Validation: the full server suite passes (2,383 tests, 7 existing skips). Isolated native fixtures pass against a private OpenCode 2.0.31: test-missions-native, trajectory, contract, family-control, and recurring journeys ABCD and QN. The task-reader browser suite and bundle regression pass; typechecks show only existing diagnostics. Three gatekeeper rounds; the last found no P0-P3 issue. Closes #1009. |
||
|
|
1173beb37c
|
fix(missions): compact coordinator tool results and state the decision rule (#1011)
Coordinators driving a real Wayfinder mission hit three costly frictions (#1009): every mission tool mutation echoed the whole map (about 50 KB after ten tasks), the canonical assignment prompt only existed inside that response, and the decision role read as a self-contained analysis although completing it requires the human's own answer to a native question. mission.delegate, revise, report and briefing now return a compact readout (missions/tool-result.ts): disposition, current revision, status, run state, frontier and the affected tasks, plus the contract and exact assignment prompt for a declared native task. Briefs, reports and the objective stay out; mission.inspect keeps the full map, and mission.inspect({ taskKey }) rereads one task with its contract and current prompt. The returned revision feeds expectedRevision and basedOnRevision directly. Reports name the task the control actually resolved, including an independent actor's omitted taskKey. The native Wayfinder decision role, the coordinator contract and native decision declarations state the rule verifyHumanDecision enforces: the task's own conversation asks through the native question tool and the user answers in CodeNomad; self-contained analysis belongs to research. Independent-mode coordinators, which that gate does not check, do not get it. The refusal shows the exact provenance shape the gate validates, kept aligned with nativeDecisionProvenance by a test. Refusals for a withdrawn readout and unsettled withdrawn work explain what to do, a briefing citing missing or retired tasks names them, and the Missions skill matches. No journal, gate, ownership, RPC or UI contract changes. Interrupting a retired task's native child, multi-task replacement, a paused-mission creation tool, native execution visibility and Form IDs remain open. Validation: 1,104 Missions server tests pass (one existing skip), with new compact-result, task reread, retired readout, briefing source, implicit report key, refusal shape and decision-rule tests. The isolated native Missions, trajectory and contract fixtures pass against OpenCode 2.0.31. Server typechecks show only the existing diagnostics. Two gatekeeper rounds; the second found no P0-P3 issue. Refs #1009. |
||
|
|
ba0b8e5683
|
docs(sidecars): drop the rejected-isolation trace from agent guidance (#1004)
Documentation only. Removes the remaining "SideCar isolation was evaluated and rejected" trace from `AGENTS.md` and the architecture-guide `desktop-conventions.md`. Both keep the current behavior: SideCars are trusted same-origin extensions, and cookie filtering is not DOM/API isolation. |
||
|
|
008e53aa27
|
docs(sidecars): keep rejected-isolation history out of the architecture notes (#1003)
Documentation only. Removes the 'isolation was evaluated and rejected' sentence from \dev-docs/architecture.md\: the architecture notes describe how SideCars work (trusted same-origin extensions), not the alternatives tried. \AGENTS.md\ and the architecture-guide reference kept a pointer to that sentence; they now state the reason directly, so agents are still told not to reintroduce isolation. |
||
|
|
1ce629b9a6
|
docs(sidecars): document SideCars as trusted same-origin extensions (#1001)
## Summary Documentation only. SideCars are now documented as **trusted same-origin extensions** of CodeNomad, replacing the "temporary exception / isolation follow-up" wording introduced with #994. ## Why The isolation follow-up was prototyped, measured and reviewed, then rejected: - **Opaque sandbox:** the frame loses cookies and storage, so the service's own login and state break. - **Separate origin:** keeping service cookies requires a same-site origin (another port or subdomain). Chromium still sends the application's `Lax` cookie across ports of the same host, and CORS alone did not block authenticated writes, so every API would need an origin barrier. - **Per-view ports:** these are unreachable through a single exposed port, reverse proxy or tunnel, and reset service storage on every opening. - **IP and single port:** with a literal IP and one exposed port, no frame topology gives both isolation and working `Lax` cookies. ## Changes - **`dev-docs/architecture.md`:** records the decision and these constraints. - **`AGENTS.md` and the architecture-guide `desktop-conventions.md`:** refer to the decision instead of a pending prototype. - **`CONTRIBUTING.md`:** no longer claims SideCar frames are sandboxed. - **`README.md`:** tells users to add only services whose content they trust. The #995 cookie filtering stays as is; no behavior change. |
||
|
|
be66133469
|
fix(sidecars): isolate application cookies from upstream services (#995)
Authenticate SideCar HTTP/WS requests before removing the configured CodeNomad session cookie, desktop session-cookie namespace and Remote Control device credential from upstream requests. Filter reserved response cookie names as well while retaining service cookies. Use the bounded Node HTTP parser for WebSocket handshakes so successful and rejected upgrades receive the same cookie treatment; preserve buffered bytes, binary forwarding and non-101 response framing. Document that this is credential filtering, not same-origin DOM/API isolation. Validation: 143 HTTP/proxy tests, 11 focused cookie/transport/preview tests, server typecheck, and isolated Chromium/Electron prototype exercises. General CI was still running at the explicitly authorized admin merge. |
||
|
|
d19d1c39fa
|
fix(sidecars): keep SideCar frames same-origin so proxied requests authenticate (#994)
## Summary
Since 0.20.0, opening a SideCar panel (e.g. ttyd) shows the page but
every in-page request fails: the terminal immediately falls back to
"Press ⏎ to Reconnect". All HTTP subresource fetches
(`/sidecars/<id>/token`, …) and the WebSocket upgrade
(`/sidecars/<id>/ws`) are rejected with 401/403. Connecting to the same
service directly (no iframe sandbox) works fine.
## Root cause
The browser-frame sandbox added in 0.20.0 (`allow-scripts allow-forms
allow-modals allow-popups allow-downloads`, no `allow-same-origin`) also
applies to SideCar frames. That makes the frame an **opaque origin**, so
the browser sends its in-page requests with `Origin: null`, cross-site,
and **without the `SameSite=Lax` session cookie**:
1. `sandbox` lacks `allow-same-origin` → iframe document is an opaque
origin
2. In-page fetch/WS requests become cross-site (`Origin: null`, no
cookies)
3. `codenomad_session` is `SameSite=Lax` → never attached
4. Server enforces session auth on `/sidecars/*` → **401**; the
opaque-origin gate additionally answers **403** (`http-server.ts`,
"Opaque origins may access preview capabilities only")
Only the frame's *subsequent* requests fail — the initial navigation is
issued by the top-level page (same-origin, with cookies), which is why
the panel visibly loads before disconnecting. Browser previews already
solve this with their token-scoped capability path; SideCars have no
such path and depend on the session cookie, so their frames must stay
same-origin.
## Change
Opt-in relaxation, scoped to user-configured app-proxied content only:
- `getBrowserFramePolicy(environment, { trustedSameOrigin })` appends
`allow-same-origin` to the sandbox only when explicitly requested
(`browser-frame-security.ts`)
- `BrowserFrame` gains a documented `trustedSameOrigin` prop; arbitrary
web previews must never set it
- `SideCarView` passes `trustedSameOrigin` — restoring pre-0.20 behavior
for content the user explicitly configured (a local service on
`127.0.0.1` reached through the app's own authenticated proxy)
Security posture is otherwise unchanged: the server-side gates stay
exactly as strict (the new server tests pin this), and browser preview
frames keep the full sandbox.
`allow-scripts` + `allow-same-origin` together do let SideCar content
script its same-origin parent — the same trust level SideCars had before
0.20.0 for services the user deliberately added. A follow-up can remove
even that by issuing short-lived tokens in the iframe URL (see below).
## Tests
- **Unit** (`browser-frame-security.test.ts`): trusted SideCar policy
includes `allow-same-origin`; existing tests still assert the default
policy excludes it
- **Browser** (`tests/browser/sidecar-sandbox.test.ts`, new): asserts in
a real Chromium DOM that the `SideCarView` iframe carries
`allow-same-origin` while a plain preview `BrowserFrame` does not
- **Server** (`server/__tests__/sidecar-proxy.test.ts`, new): WebSocket
upgrade **without cookie → 401**, **with valid session cookie → 101**
(also verifies `strip` prefixMode drops `/sidecars/:id` before
proxying); HTTP with `Origin: null` → 403, same-origin + cookie → 200 —
locking the exact contract that forces same-origin frames, so the server
gates cannot be quietly loosened instead
## Validation
- CI's runnable-UI unit list: 56/56 pass
- Targeted browser suite (`sidecar-sandbox` + full
`browser-frame-native` Electron suite) under xvfb: 20/20 pass
- Full server suite: 2286/2329 pass; all 27 failures are pre-existing
Git/gpg-signing environment failures (reproduced on an unmodified tree
via stash), none touch sidecars/auth/http-server
- `tsc --noEmit` clean for `@codenomad/ui` and the server package
- Manual: `ttyd -i 127.0.0.1 -p 7682 bash` as a port SideCar (insecure,
strip) — terminal stays connected; before the fix the token fetch was
403 and the WS handshake 401
## Follow-ups (not in this PR)
- Short-lived token in the SideCar iframe URL accepted by `/sidecars/*`
HTTP + WS auth, so even trusted sidecars could drop `allow-same-origin`
(mirrors the preview capability mechanism)
- Optional `SameSite=None; Secure` configuration for authenticated
sandboxed iframes behind HTTPS reverse proxies
---------
Co-authored-by: Pascal André <pascalandr@gmail.com>
|
||
|
|
db6685cb55
|
fix(workspaces): closing a project tab closes the project in CodeNomad (#970)
## Problem
Closing a project tab only hid it in that window. The backend workspace
record kept routing the folder's events, notifications, auto-accept and
pending-request recovery, invisibly, until the palette-only **Stop
Workspace** command was run on the active tab. That command still showed
the V1 message "Stop OpenCode instance? This will stop the server."
although V2 has one shared OpenCode service, and it called
`debug.location.evict`, which (per OpenCode source) rejects pending
permissions, cancels pending Forms, fails plugin RPC and kills terminals
of that directory, even for sessions started elsewhere. OpenCode loads
locations on demand and unloads idle ones itself.
## Change
- **Closing a project tab** (×, Ctrl/Cmd+W) removes that tab's backend
workspace record. CodeNomad stops following it; sessions keep running in
OpenCode and reappear when the project is reopened.
- **Another tab of the same folder** has its own record and is
unaffected.
- **The same record shown in another window**: that window's tab closes
through the existing `workspace.stopped` broadcast, with an info
notification ("closed from another window"); the initiating window shows
nothing.
- **CodeNomad never evicts OpenCode locations**: eviction, its
serialization helpers and `locationOwned` bookkeeping are removed. A
failed launch now always removes its logical record (the retention only
existed to retry a failed eviction).
- **Stop Workspace removed** (command, confirm dialog, i18n keys in all
locales).
- Unchanged: opening an open project still offers a new tab (recent row)
or switching (switch button); temporary projects keep Keep / Discard /
Cancel; window close, app quit, reload, restore and backend shutdown
delete nothing; disconnected-instance dismissal stays local.
- Delete failure: error toast, record kept and reachable from the home
page, no automatic retry.
## Docs
Help in all 10 locales (`projects`, `index`, `desktop`, `server`,
`opencode`, `missions`), `AGENTS.md`, `CONTRIBUTING.md`,
`dev-docs/architecture.md`, `packages/server/README.md` and the
architecture-guide skill now describe the new contract.
## Validation
- UI store tests (`--conditions=browser`): app-tabs,
temporary-instances, workspace-list-reconciliation-fence,
instances-restore-ownership — 30/30.
- Server: manager + shared service 54/54; event ownership and workspace
identity suites pass.
- New real-component browser regression (click ×, Ctrl+W, Cmd+W): 3/3;
project restoration (Electron/Tauri) and new-instance launcher browser
suites pass.
- `npm run test:help` 9/9 (250 pages); UI, server and Electron
typechecks.
|
||
|
|
8e8ca15934
|
chore(opencode): qualify runtime 2.0.29 and align client/plugin pins (#948)
## Summary - Recommend and pin OpenCode **2.0.29** (`@opencode/client`, `@opencode/plugin`); the technical minimum stays **2.0.27** since 2.0.28/2.0.29 keep Effect 4.0.1. - Add 2.0.29 as a reviewed contract profile beside 2.0.27; 2.0.28 and future/custom labels keep authenticated negotiation. - Test fixture only: the recurring Missions host declares the `credential` domain that the 2.0.29 Promise adapter reads eagerly (the managed owner spreads `ctx`, dropping the Proxy fallback). No product code change. - Two new isolated fixtures for upstream behavior changes: bounded output-length continuation, and rejected Promise tools / native denial. - Compatibility docs, CONTRIBUTING, AGENTS and architecture guide updated. ## Upstream review - OpenAPI: same 118 paths; additive schema changes (config `policies`, provider/model `compatibility`, `encoding`). - Private LocationServiceMap/Form/Permission/queue contracts used by the pending snapshot: unchanged. - Effect stays 4.0.1. ## Validation (Windows, isolated CLIs/databases, never the shared daemon) - 2.0.29: plugin runtime, automation, pruning/history/proxy, Missions contract/family control/full journey, session environment, fork, aside, prompt skills, Git degraded/init, provider usage/accounts, temporary workspaces, blank-session cleanup, output-limit continuation, Promise tool failure, system settings discovery, native upgrade 2.0.15→2.0.29. - 2.0.27 (minimum): plugin runtime, automation, pruning, Missions contract/family, session environment, fork, aside, prompt skills, blank cleanup. - Server: 2235 passed / 7 skipped / 0 failed. UI: 1524 passed. Tauri crate 268/268, updater handoff 1/1, UI updater flow 13/13 (dev base includes #786). ## Known, not caused by this change `scripts/test-permission-receipts-native.mjs` times out identically on 2.0.27 with the previous pins; tracked separately. |
||
|
|
af075a6fa5
|
feat(missions): add a Product delivery playbook based on NomadWorks (#946)
## Summary Missions gains a fourth playbook, **Product delivery** (`delivery`; FR "Livraison produit"), next to Flexible, Debugging and Exploration. Like them, it is named after what it does. It adapts the NomadWorks Collective method from the original [NeuralNomadsAI/NomadWorks](https://github.com/NeuralNomadsAI/NomadWorks) (`main` at `55eec7e`, v0.1.1). It works without installing that plugin. - **Coordinator as Product Manager.** - **Classification:** it classifies each request by complexity (tiny, standard, complex) and track (implementation, investigation, spec). - **Specification:** for behavioral work, it has the business analyst and tech lead draft a Spec Change Request, then asks the human to approve it through a native Form. - **Delivery:** with the technical architect, it splits complex work into slices (foundation, core, logic, ui, polish, qa, docs). Only one task at a time edits the shared checkout. - **Closure:** it closes only with QA and tech-lead evidence, and once the documentation impact is resolved. - **Six roles:** business analyst, technical architect, tech lead, developer, QA engineer and UI/UX designer. Each returns the NomadWorks specialist output sections: summary, work performed, acceptance-criteria coverage, documentation impact, open risks and next step. Each role can have its own agent and model in the profile selectors and in Missions defaults. - **Deliberate differences from NomadWorks:** - Request approval is coordinator guidance, not a gate enforced by the server. - The Missions safety boundary replaces NomadWorks' agent commit authority: the human owns commits. - One playbook covers both NomadWorks team presets (mini and full), because the coordinator declares only the roles each complexity needs. - **Fix found along the way:** task-role validation checked every non-Debugging playbook against the **Exploration** roles. A new playbook's tasks would have been rejected. Each playbook now admits exactly its own declared roles. ## Changes - **Server:** - the recipe in `missions/recipes.ts` and the roles in `playbook-profiles.ts`; - the `delivery` template id in every server, plugin, RPC and route enum, and in the journal decoder; - the role check in `contracts.ts`. - **UI:** the Playbook selector, the defaults-scope selector and saved-brief validation. - **i18n:** the playbook name and six role labels in all ten locales. - **Docs:** `dev-docs/MISSIONS.md` (Included playbooks) and the `codenomad-missions` skill. ## Validation - Server and UI typecheck. - All Missions server tests, including a new regression showing that Product delivery admits exactly its own roles and that other playbooks reject them. - CI "Missions UI units" (36 files), plus every Mission and i18n UI unit test (40 files). The locale-ownership test now covers 25 profile labels. - `build:missions` plugin bundle. - Browser tests `mission-defaults-models` and `mission-editor-profiles` pass 24/24. The Flexible-exception loop now also covers the new playbook. Not yet validated: a live model run of a NomadWorks mission. |
||
|
|
dd5a1f387d
|
fix(opencode): share host plugin runtime and require 2.0.27 (#920)
## Résultat Corrige le chargement des plugins CodeNomad avec OpenCode 2.0.27 et établit cette version comme minimum pour les prochaines releases et les prereleases dev. Aucun déploiement de l’application active ni redémarrage du daemon partagé. ## Cause démontrée - Le runtime natif passe d’Effect 4.0.0-rc.112 à 4.0.1. Le bundle précédent reproduit `cache.stackFrame` sur une CLI 2.0.27 isolée. - Embarquer Effect 4.0.1 ne préserve pas la 2.0.26 : échec inverse `cache.scheduler`. - Les schémas 2.0.27 consomment `Schema.isStartingWith`, absent du moteur 2.0.26. Le plancher est fondé sur cette rupture mesurée, pas sur une liste de versions testées. ## Implémentation - Pins client/plugin synchronisés à 2.0.27 ; Effect et le SDK public des plugins sont fournis par OpenCode, hors bundles natifs pruning/Missions/automation. - Réglages de build partagés et régression qui interdit une seconde copie du runtime ; smoke natif ajouté à la matrice minimum/latest. - Diagnostic `plugin_runtime` traduit dans les dix locales ; versions futures et personnalisées conservent la reconnaissance authentifiée du contrat. - Adaptations du SDK : annulation des lectures projet, références de credentials externes et connexion fournisseur externe avec formulaire natif, sans fallback OAuth/API key ni rejeu. - Le runtime OpenTunnel du backend reste isolé et inchangé. Aucun tunnel, route ou identité distant n’est modifié. ## Validation locale - Échec reproduit sur 2.0.26 et réussite sur 2.0.27 pour les variantes de bundle comparées. - Suites natives isolées automation, pruning/historique/proxy/concurrence/redémarrage et Missions réussies sur 2.0.27. - Régressions ciblées de build, store/serveur et navigateur (diagnostic du minimum, connexion externe et brouillon conservé) réussies ; typechecks UI/serveur/Electron/OpenTunnel réussis. - Suite serveur complète et CI multiplateforme encore en validation à l’ouverture ; aucun résultat entièrement vert anticipé. La revue gatekeeper indépendante sera publiée ici avant fusion. Les anciennes preuves de qualification restent historiques, pas une promesse de support des moteurs antérieurs au nouveau plancher. |
||
|
|
81fb513558
|
feat(missions): native project coordination, briefings and tracking (#866)
# Missions: product specification ## Product goal Missions coordinates complex work through native OpenCode conversations. CodeNomad provides creation, controls, human attention and result reading; OpenCode owns execution. One-time objectives and finite daily recurring passages share the same planning and reading experience. No OpenCode modification is required. ## Create and configure - **Flexible mission**: free-form objectives and bounded delegation. - **Debugging**: diagnosis, implementation, independent standards/specification reviews and fresh validation. - **Exploration**: bounded decisions and parallel investigation, with explicit native human questions where required. Creation presents an objective, a short optional title, verbatim working notes, coordinator/task profiles and native or independent task-session policy. Optional choices stay collapsed. A single **Create** button saves a prepared one-time mission or paused recurring schedule without starting anything. **Play** is a separate explicit action for both. Settings → Missions contains defaults for **all new missions**, with optional exceptions for each of the three types, including Flexible. A type exception overrides the global value; an unset field shows the inherited value. Defaults never reconfigure existing missions or busy actors. Reusable briefs contain creation inputs only; loading copies them into a normal draft and deletion preserves executions. **Save as brief** is also available from a selected one-time mission, including a completed mission: it copies objective, verbatim notes, template, stored profile choices and task-session policy; the mission title prefills the brief name, never copying execution identities or results. Profiles choose an agent, model and optional reasoning variant. Coordinators use primary/all profiles; native task actors use subagent/all and independent actors use primary/all. Business roles remain separate from native session identities. Actor continuation preserves the accepted profile. The native subagent-depth editor is separately Location-scoped and applies to all OpenCode conversations there, not just missions. It shows the configuration file, effective value and override. Conditional Save preserves the original file expectation and never automatically reloads or restarts OpenCode. ## Missions panel The first toolbar holds only general actions: **Create**, **Settings** and **Refresh**, aligned right. Settings opens the Missions settings section directly, using the existing native Preferences window on desktop. A native refusal shows an error rather than opening a second embedded window; browser and remote windows retain their embedded settings. The current-mission line contains a leading chevron, the selected title and a small status mark: - Clicking the **chevron** expands a persistent inline list; selection leaves it open. - Clicking the **title** opens a transient popup; selection, outside interaction or Escape closes it. - Both lists show titles and status marks, with full labels in tooltips and accessible text. Titles truncate only at the available row edge. - Search appears only when the measured list exceeds its maximum height, and remains available while a query is present. - The closed chevron indicates activity/attention in other missions using the same visual vocabulary as the session list. - Only the picker changes the selection, remembered per project; opening a mission's conversation never reselects a mission. Selected-mission controls are separate: **Play/Pause**, **Stop**, optional recurring **Run now**, then **Summary**, **Open coordinator conversation**, **Edit** and **Delete**. Destructive actions require confirmation. **Request an update** is a text button below the icons, available only while meaningful; its pending/uncertain state is retained without automatic replay. The **Tasks** disclosure contains only the declared dependency tree, not a duplicate task list. It is initially open, remembers its state and uses the remaining panel height down to the window bottom rather than a fixed task-height cap. Rows retain full-width selected/hover backgrounds across connectors and controls. A task's exact conversation shortcut appears on desktop hover/keyboard focus, and remains visible on touch. Mission selection is remembered per project and changes only through explicit mission selection/creation. Opening a coordinator or task conversation in the session list never changes the selected mission. Conversation shortcuts remain available from the mission panel to the coordinator and exact task conversations. The session-list files are unchanged relative to `dev`; restoring the full cached session hierarchy is supplied by the separately merged #841. ## Plan and native execution The coordinator declares tasks, dependencies, roles and expected outcomes. Ready work can run in parallel through ordinary native subagents. Recursive decomposition follows OpenCode permissions and configured depth; the product imposes no delegation target or root fallback. Independent sessions remain available for an explicit Location, lifetime or existing-root requirement. The task-session policy is frozen per mission. Tasks have stable keys/generations; conversations have exact native identities. Business dependency edges never stand in for native ancestry. Native task returns and business settlement are separate: a coordinator records the actual returned result/evidence, then finalizes the mission. A notification/admission acknowledgement is not proof of consumption or completion. ## Results and human interaction Long objectives, briefings, task results, evidence and plan history open in the central reader above the transcript. Reader eyes toggle the exact target and highlight it. Task results come before the original brief and technical details. A missing/unavailable reader target must not leave the transcript hidden. The coordinator publishes dated, bounded briefings explaining delivered results, remaining work, obstacles and the next step in plain language. Briefings remain separate from task settlement and observed activity; exact request identity is required to acknowledge an explicitly requested update. Attention contains real native Forms and permissions. Obstacles reported in prose are not automatically human requests. Native interruptions retain conversation provenance and drafts in the shared interruption dock. A template's required human decision counts only when answered through the CodeNomad UI, locally or from a live paired Remote Control device; a simple UI-answer mark records that provenance. Users give direction or ask questions by writing in the coordinator conversation (**Open coordinator conversation**). From the panel itself, the only coordinator message is **Request an update**; its pending/uncertain state is retained by identity and never replayed automatically. Reports, plan history and cleanup receipts stay secondary in reader/technical surfaces. Optional managed-session cleanup preserves coordinators, shared/reused/moved sessions and roots with descendants. ## Lifecycle and recovery For one-time missions: - **Play** starts/resumes explicit mission intent; **Pause** parks mission dispatch/notifications and interrupts the observed active native family. - **Stop** is terminal and interrupts observed descendants deepest-first, then registered roots/coordinator, with bounded rechecks for parent wakes caused by child cancellation. - Native inbox cancellation uses exact authorized mission/subagent work. Pause preserves deferred results for explicit Play; Stop removes the identified queued work/results that would wake a stopped coordinator. - Per-target receipts record observed interruption and family coverage. Incomplete or unconfirmed interruption is shown as **Some sub-agents may still be running**, never as proven recursive suspension. - **Refresh** reconciles state first; an explicit refresh click may retry a still-unconfirmed lifecycle action under its original identity. Reconnect and ordinary display reads never resend mutations. - **Play** offers targeted recovery only when native observation establishes the applicable interrupted state, not merely because activity is unknown. Active background descendants retain the active/Pause presentation. Native interruption does not undo completed filesystem/tool effects. Resuming a paused mission lets the coordinator decide how to continue or re-delegate interrupted work; there is no hidden task replay engine. ## Recurring missions Recurring setup adds permanent instructions, a title, a daily local time/timezone and explicitly followed project conversations. Saving creates a paused schedule; Play arms it and Run now requests one finite passage. The OpenCode service/plugin owns scheduled passages while both CodeNomad UI and its intermediary backend are closed. One native Job per running schedule sleeps until the earlier of the next due time and one hour. On waking it rereads the clock/document and admits only the latest due civil day newer than the stored daily cursor; there is no backlog. Native execution terminal events also wake observation after a debounce, but are not settlement evidence. Before native effects, conditional storage records deterministic passage, coordinator and start-message identities. Lost replies reconcile those exact identities rather than creating new attempts. A passage archives only after the coordinator and descendants are inactive, inboxes are empty and no relevant native Form, permission, Shell or background subagent remains. Unknown coverage stays pending. Passages end as completed with a final report, native terminal failed, or ended-without-report/interrupted. Only completed passages advance followed-conversation cursors. Schedule history is bounded to 30 passages. Civil-time DST gaps/repeated times and entirely skipped days resolve deterministically. Pause/Stop cancel the schedule Job; those schedule actions do not prove an already-running passage family stopped. Stopped is terminal. After service restart, a desired-running schedule without its Job is **Interrupted**, awaiting explicit Resume. Resume reconciles pending work, never sends a continuation; a turn cut by restart settles interrupted/ended-without-report. ## Durability and UX Mission journals and schedule documents retain tasks, roles/profiles, results, plan revisions, controls, notifications and bounded history. Conditional writes and original request identities protect mutation retry. Authority, Location ownership, fresh per-send environment and connection/deletion fences are checked at admission. Ordinary native permissions govern tool use. UI remains compact and square, localized in all supported languages, keyboard-accessible and usable on touch/narrow/RTL layouts. Cache-first display reads revalidate on visible demand and native invalidation, without polling or clearing known data on uncertain recovery. Loading, missing capability and uncertain effects remain explicit. ## Shared integration scope The PR also includes supporting shared-runtime corrections; these are not limited to the Missions tab: - Session outcome and generation-recovery reconciliation retains uncertain interruption state across reconnects and checks native outcomes before clearing it. Native message pages clamp to the service's 200-message limit. - Pending-request recovery retains known requests through incomplete coverage and connection transitions; native ownership and deletion fences remain authoritative. - Keyboard offset and the compact composer help strip preserve reachable input controls without changing composer height limits. Touch overflow actions suppress duplicate compatibility clicks. - Workspace text saves enter the existing worktree mutation fence; sandboxed panel asset reads fence connection changes. Worktree scans retain validated family identity and custody. - The worker-based Git process runner uses an ESM-safe worker entry, and CLI service discovery shares bounded command deadlines. - Desktop/backend profile identity is explicit for Missions' owned storage. Profile-scoping signals are internal to that relationship, not permission for independently launched applications to inherit a profile. - Shared rendering/localization includes a Turkish tool-call label correction. - Session-list startup restoration exposes a settled signal (`stores/session-list-restoration.ts`, hooked in `session-api.ts` and `instances.ts`). Missions display reads wait for it so the session list loads first; it settles on success, failure, timeout or abandonment and is reset when a workspace is removed. Session-list components and styles are unchanged. These callers are included in integration review and their regression tests, rather than treated as an unchanged dependency surface. ## Current limitations - Editing/deleting recurring schedules is not implemented; those icons in the selected mission's action bar are disabled for schedules. - An uncertain one-time creation (lost reply after the request was sent) is held in window memory with no status endpoint; Create stays blocked for that window until reload. Definitive refusals before any native effect re-enable Create immediately. - Saving a brief from an existing recurring schedule is not implemented; the selected-mission action currently covers one-time missions only. - Task conversation lookup for older unbound native tasks reads a bounded coordinator-message window and recognized exact assignment evidence. Older/unrecognized delegations may have no shortcut; no conversation is guessed from titles or timings. - Running native calls may not expose their child ID until completion. The panel can instead identify a direct child by its first canonical assignment message, within a bounded direct-child page; unrecognized or out-of-bound children remain unlinked. - Native task profiles are recorded, but ordinary subagent launch still relies on the coordinator passing the declared agent/model/variant to OpenCode. Omitted model parameters can inherit the coordinator's model; profile storage alone does not enforce launch parameters. - One-time recursive interruption is best-effort and bounded, not a durable guarantee that every descendant stays stopped. Partial/unknown coverage remains visible. - Recurring Pause/Stop cancel scheduling, not guaranteed recursive suspension of a running passage. - Native qualification uses isolated services; mock-only and source-review evidence never substitute for real native acceptance. Final validation results are published separately in the PR reviews. - Managed-service restart and some lost-reply/clock-conflict/human-decision journeys still have offline-only evidence. - If an admitted passage start is removed by pruning before its lost durable write is reconciled, that original start identity can become unavailable for deduplication. ## References - [Mission contract](https://github.com/NeuralNomadsAI/CodeNomad/blob/experiment/missions-native-subsessions-20261003/dev-docs/MISSIONS.md) - [Recurring contract](https://github.com/NeuralNomadsAI/CodeNomad/blob/experiment/missions-native-subsessions-20261003/dev-docs/MISSIONS_RECURRING_SIMPLE.md) - [Native qualification](https://github.com/NeuralNomadsAI/CodeNomad/blob/experiment/missions-native-subsessions-20261003/dev-docs/MISSIONS_RECURRING_SIMPLE_QUALIFICATION.md) |
||
|
|
8484cf0a57
|
fix(desktop): separate the update feed from the local data profile (#891)
# Separate update feed from desktop data profile ## Problem A single "channel" value currently drives two unrelated things on desktop: - which releases CodeNomad offers as updates; - which local data profile (tabs, windows, drafts, WebView storage, per-profile backend) is opened. The channel is inferred from the installed version string (`-dev-…` → `dev`, otherwise `stable`) or from `CODENOMAD_UPDATE_CHANNEL`. Installing a `0.20.1` build over a `0.20.1-dev-…` build therefore silently reopened a different, empty profile: same application, same OpenCode sessions, but previous tabs and drafts gone from view. Users had no setting to choose updates and no indication of which profile was active. The Windows update action always targeted the stable winget package, and `dev-v2` builds received no prerelease notifications. ## Expected behavior **Normal users** install or update CodeNomad and get their projects, tabs and drafts back. The installed version never selects a data location. **Update feed** is a visible user preference in Settings → Info → Updates: - *Stable releases*; - *Previews and stable releases*. When unset, builds labelled `-dev-*` default to previews, others to stable. Changing the feed never touches local data. Windows runs winget only for the stable feed; previews open the release page. **Data profile** is explicit developer isolation: - packaged builds use the normal default profile; - `CODENOMAD_PROFILE=<name>` opens an isolated named profile, using the existing scope formula so existing folders remain reachable; - `CODENOMAD_UPDATE_CHANNEL` remains a deprecated alias for the profile only, mapping existing values to exactly the same folders; - unpackaged development runs keep their own `dev` profile; - Electron and Tauri normalize and validate names identically; invalid explicit names fail visibly. Settings → Info shows the active profile only when it is not the default. **Startup restore settings are reachable on desktop.** Desktop Settings open in the separate Preferences window, which previously hid the Startup card, so *Restore previous state* and *Clear saved state* were unreachable. Preferences now shows them. Each change applies to the exact main window that opened Preferences, through that window's existing saved-state handling; Preferences never becomes a client-state writer. If the opener is gone, the card stays visible, disabled and explained. **One-time transition** for existing installs without an explicit profile: CodeNomad checks, read-only, which of the default and previously version-selected profiles (`dev`, `dev-v2`) for the same configuration hold restorable state. One → use it; none → default; several → ask once with a native dialog before any profile is opened. The answer is remembered by profile name, never by path. Nothing is moved, merged or deleted. OpenCode sessions remain shared across profiles. **Other saved profiles can be deleted.** When other data profiles exist on the machine, Settings → General → Startup shows one row — *Other saved profiles: N profiles, X GB — Delete…* — hidden otherwise and in plain browsers. The confirmation lists exact names and sizes and states that OpenCode conversations are unaffected while those profiles' tabs, drafts, layout and web storage are deleted. Profiles in use (or of unknown state) by either host are skipped and reported. The renderer sends only listed IDs; the host re-lists, re-validates and deletes only paths a profile provably owns. The default profile's storage contains other roots, so only its own known children are removed, never a parent root. The open configuration's remembered choice is dropped when it names a profile deleted for that configuration; other configurations' entries are dropped only once no folder of that profile remains. At launch, a remembered named profile whose folder is definitely gone reruns detection instead of opening an empty profile; unreadable folders keep the choice. If the profile folder is a link whose target is unavailable (for example a disconnected drive), detection decides that launch only and the remembered choice is kept for when the target returns. ## Out of scope - Moving existing profile data to the standard location. ## Documentation A developer document explains installed version, update feed and data profile as three separate notions, with precedence, the legacy alias and the transition. ## Implementation choices - Both hosts resolve the profile before the singleton, storage folders or client-state path are fixed. Grammar for `CODENOMAD_PROFILE`: after trimming ASCII whitespace and lowercasing ASCII letters, 1–64 characters from `a-z 0-9 . _ -`, starting with a letter or digit; `default` and `stable` mean the default profile. The legacy alias keeps each host's previous normalization for exact folder parity. - A store counts as restorable only if a window with restore enabled has at least one workspace tab, read with the existing client-state parsers. - The remembered choice lives in `<appData>/CodeNomad/profile-selection/choices.json`, keyed by a hash of the config path, storing only the profile name. Writes are atomic; corrupt entries rerun detection; concurrent first launches serialize on a lock (stale after 15 s) so only one asks. - Tauri asks synchronously with `rfd` before the builder. Electron asks from a throwaway temporary folder, records the answer and relaunches, because Chromium storage and the singleton are fixed before the app is ready. - The backend receives the resolved profile as `CODENOMAD_DESKTOP_PROFILE`. ## Known limitations - The transition question is English-only: no native localization exists before a profile (and its saved language) is open. - With three candidate profiles the native dialog has no separate Quit button (`rfd` allows three buttons). Closing it quits on Windows and Linux; on macOS the user must pick a profile, which moves nothing. - Two launches racing on a stale lock may both ask; the first remembered answer wins. - On macOS, Tauri profiles share one WebKit data store, so deleting other profiles keeps that shared web storage (sign-ins, cache); the confirmation says so on macOS. - Scope hashes keep each host's historical case folding so existing folders do not move; only the new remembered-choice key uses a shared Unicode fold on Windows. - Real native dialogs and Electron's relaunch path are covered by unit tests, not exercised interactively on every OS. ## Validation - Shared cross-host vectors (`data-profile-vectors.json`): legacy scope hashes, grammar, precedence, client-state fixtures. - Electron full `test:native`: 273/278 pass, 4 POSIX-only skips; the one failure, `process-stop.test.ts` (unchanged from `dev`, PowerShell under a 5 s timeout), is flaky on the Windows test machine and passes when rerun. - Tauri full `cargo test`: 245/246 pass; the one failure, `cli_service_lifetime_tests` (unchanged from `dev`, Node fixture with a 5 s deadline), passes when rerun. `cargo check` clean apart from pre-existing dead-code warnings. - UI browser tests for other profiles, Preferences startup state, Preferences window and Settings → Info: 19/19. Server `desktop-profile` and update-feed tests pass. - Electron, server and UI typechecks clean. - Covered cases: none/one/several restorable profiles, remembered and corrupt/newer choices, keying by config, stale and live locks, a concurrent launch waiting for the answer, and that the installed version is not an input. - Developer documentation: `dev-docs/DESKTOP_DATA_PROFILES.md`. |
||
|
|
9dd4b3f059
|
feat(remote-control): add Remote Control over OpenTunnel alongside direct access (#668)
Adds Remote Control alongside direct/LAN access. A phone or another computer pairs with CodeNomad and continues its sessions from anywhere, without an inbound port. The transport is OpenTunnel, the blind TLS relay used by OpenCode: TLS ends inside the CodeNomad backend, and nothing has to be deployed. - packages/remote-tunnel wraps @opentunnel/client. The server build bundles it with its own Effect 4.0.x, so the published server has no runtime dependency on a private workspace package. CodeNomad claims its own route on the device's shared identity and never deletes it. - A remote-only loopback ingress marks its sockets as remote, so local privileges come from isLocalRequest(), never the peer address. The gate runs before CORS, auth and routing: - exact tunnel Host, and the public Origin on mutations; - stripped forwarding headers; - origin-form targets only, judged as routed (decoded, cut at ';'); - host-only paths denied; - a paired device required, except for the public UI bundle. - Host-owned pairing: a single-use five-minute code, hashed device credentials with 30-day idle expiry, and a __Host- cookie. Revocation or eviction closes live streams. A revoked device is asked to pair again, keeping drafts. - The Cloudflare Worker/Durable Object relay, the custom E2EE protocol and the browser transport shims are removed. Electron and Tauri keep the backend alive after the last window only while Remote Control is enabled. Validation: - the real createHttpServer is exercised through the ingress, plus raw-socket canonicalization tests and device registry tests; - recovery unit and browser tests; - an opt-in end-to-end run through the hosted relay; - a packaged smoke import of the bundled runtime; - five gatekeeper rounds to zero findings, and green CI on all desktop targets. |
||
|
|
c995044b64
|
feat(extensions): install independently distributed right-panel addons (#862)
## What changes I add independently distributed right-panel UI extensions and an official online catalogue in Customize right panel. Users browse/search available addons, choose one and confirm installation directly from its exact GitHub Release, without a manual ZIP download, rebuilding CodeNomad or restarting OpenCode. Manual ZIP installation remains available. I publish the curated index, contribution rules and Session info demo at https://github.com/NeuralNomadsAI/CodeNomad-Extensions. That repository can host several official addons; the index can also reference author-owned repositories. Separate means independent of the main application repository, not a mandatory repository per addon. I show the manifest and exact archive SHA-256 before trust confirmation. Installation starts disabled; users enable it for all projects in the server profile or for the exact opened folder. Replacement requires the previous digest and revokes every activation grant. Removal is explicit. Packages and grants stay outside project/OpenCode storage. I keep author code out of the main renderer. API 1 exposes only session ID, locale and appearance through a per-mount MessageChannel. It does not expose filesystem, transcript, images, credentials, native commands or the OpenCode proxy. Frames are sandboxed without same-origin access and receive a restrictive CSP; obsolete responses and ports are fenced on project/session changes, disconnects, revocation and replacement. I document the package, permissions, API compatibility, scope, release/checksum and maintainer rules in `dev-docs/PANEL_EXTENSIONS.md`, with a standalone starter in `examples/panel-extension/`. GitHub's source ZIP is not an installable package. There is no arbitrary URL installer or automatic update. I load catalogue metadata only during discovery. Inspection and installation each revalidate a fresh index, exact ZIP digest and full manifest; unsupported APIs/permissions cannot install. Downloads are bounded, deadline-limited, credential-free HTTPS requests to GitHub's exact release hosts, with constrained redirects. A withdrawn or changed selection cannot become a different trusted package. Offline catalogue failures leave installed addons and ZIP installation available. ## Scope and limits I keep #801's assets gallery for a separate follow-up. It needs a bounded, authorized image/history capability rather than access to internal stores. This PR only establishes external distribution and a minimal context API. Windows Tauri may inject native bridge objects into subframes: object presence is not a grant. My isolated WebView2 fixture proves parent command execution while direct/raw child calls do not reach it, and verifies context delivery plus DOM/network restrictions. A trusted hostile extension can still stall its renderer or attempt self-navigation; this is not process isolation or a universal offline guarantee. The installer warns users to trust the author. I have not run a native Electron/macOS/Linux qualification or changed the shared daemon. The runtime implementation is shared between desktop hosts; native GUI validation here is Tauri only. ## Validation - UI and server typechecks. - 14 focused server/registry/manifest tests. - Real right-panel browser tests for ZIP consent, activation scopes, replacement, revocation, context changes, stale reads and frame isolation. - Five catalogue/server checks and seven right-panel browser scenarios cover metadata-only browse/search, online consent, withdrawal, incompatibility, offline ZIP fallback, hashes/manifests, redirect restrictions and size budgets. - Live public GitHub index and Release download matched SHA-256 `cf80226a40dd077a6a8cc2a4b65bbb46bf33619d62007982bd7dcea34ae4545f`; installation and activation used a disposable isolated store. - `node scripts/test-panel-extension-native.mjs` on Windows, using the application's locked Tauri dependencies and an isolated browser profile: parent native call allowed; child native calls, parent DOM and network APIs blocked; session context delivered. - UI build, Windows Tauri release build (`--no-bundle`) and packaged-resource smoke passed. Full browser suite results are recorded in the follow-up validation comment. Existing oversized files touched only for integration: `packages/server/src/api-types.ts` (~735 lines), `packages/server/src/index.ts` (~713), `packages/server/src/server/http-server.ts` (~2,438). |
||
|
|
c954841f09
|
revert(missions): undo PR #673 without dropping later dev changes
Revert merge
|
||
|
|
bbbc5e3ff9
|
merge(dev): resolve mission integration conflicts
Integrate current dev while preserving the mission routes, durable execution controls and specialist cleanup. Retain native usage route dependencies and align local plugin dependencies and architecture guidance with OpenCode 2.0.21. Combine the workspace file reader with the mission reader in the central session surface. Explicit reader selection dismisses the competing preview without losing stored editor drafts or the composer. Extend the real-session browser regression to cover switching between both readers. Validate server and UI typechecks and all ten mission browser/i18n tests. Preserve the upstream Tao patch unchanged, including its original whitespace and provenance. |
||
|
|
43e3ba72bc
|
chore(opencode): qualify and recommend stable 2.0.21
Align server/UI client and bundled-plugin pins with OpenCode 2.0.21 while keeping the demonstrated 2.0.7 application minimum and the separate 2.0.20 Codex Usage requirement. The native contract changes only by optional form-cancellation text, so existing callers need no production adapter or proxy expansion. Extend recommendation/status coverage and update maintained architecture and compatibility references. Scope the lockfile to published OpenCode packages, including optional OpenTUI peer metadata, without refreshing unrelated dependencies. Qualify minimum/current native suites, generated cancellation with and without a message, selected native Codex credentials, ordinary pruning/UI acceptance, standalone plugin, historical migrations and isolated upgrade retaining daemon version/PID. Typechecks, builds, 71 UI tests and 32 browser cases pass. Preserve the full server suite cleanup EPERM and its successful focused rerun as separate evidence rather than claiming a fix. |
||
|
|
e3924113f4
|
chore(opencode): qualify and recommend stable 2.0.20
Synchronize server/UI client and plugin pins with OpenCode 2.0.20 while retaining the demonstrated 2.0.7 step-timestamp minimum. Review the authenticated runtime contract: existing routes remain stable, while credential operations and optional connection/error metadata are added without requiring production adapters. Protect the workspace proxy boundary with credential export/create rejection coverage and verify optional provider response bodies survive UI normalization. Update the maintained compatibility and architecture references, including explicit native service startup with the new disabled setting and the unresolved historical Windows import failure. Validate minimum/current native runtimes, ordinary pruning/UI acceptance, standalone plugin installation, historical migrations and native npm upgrade with daemon version/PID preservation. Clean-install the scoped lockfile and revalidate typechecks, production builds, 745 server tests and 66 UI tests; browser qualification covers 30 scenarios. |
||
|
|
824d94dabd
|
chore(opencode): qualify and recommend stable 2.0.19
Align server/UI client and bundled plugin pins with OpenCode 2.0.19 while retaining the demonstrated 2.0.7 timestamp minimum. The authenticated native schema and published declarations preserve the consumed API contract; runtime improvements concern compaction, context limits, provider cache affinity and Shell conventions. Extend setup version coverage and update the maintained compatibility and architecture references. Add per-import native/UI fixture diagnostics after late Vite loading stopped on both the new runtime and the 2.0.18 control; do not claim that eager-import diagnostic acceptance fixes that failure. Qualify both minimum/current native runtimes, historical migrations, isolated npm upgrade without daemon restart, standalone plugin installation, UI/browser behavior and production bundles. Retain the original Windows fixture failures and their bounded diagnostic results in the PR evidence. |
||
|
|
b584ffcb3a
|
merge(dev): reconcile Missions with the current V2 baseline
Integrate dev into the Missions PR without rewriting its reviewed history. Retain mission CRUD routes, authenticated report admission and the 512 KiB bridge limit alongside inspected-window automation and plugin controls. Keep dev's canonical transport, clean builds and 2.0.18 client/plugin dependencies; align the local plugin contract check with the same SDK. Combine architecture guidance and preserve the technical runtime minimum of 2.0.7. Keep the isolated Missions fixture in the latest-runtime CI lane because its test-only ctx.tool.list driver is absent at that minimum; do not reintroduce legacy compatibility paths. Validation: server, UI and plugin-contract typechecks; full server/UI/plugin build; 84 backend/compatibility/packaging tests; 59 UI/persistence/browser tests; isolated OpenCode 2.0.18 Missions fixture and workflow YAML parsing. Merge resolutions have no conflict markers or diff-check errors relative to dev. |
||
|
|
c76edff89f
|
feat(missions): add revisable plans and persistent mission control
Make Mission Control actionable with create/edit/delete, persistent disclosures and selection, task dependencies, native attention requests, execution comparisons and a long-content reader above the mounted transcript. Preserve drafts and native per-window layout, and arbitrate browser/reader gestures without losing the preview target. Add coordinator-only mission.revise with revision CAS, idempotent replay, linked replacements and explicit dependency changes. Retain withdrawn task contracts and late reports, require terminal settlement for outstanding native admissions, and attribute human metadata edits in the bounded history. Mission deletion tombstones the map without deleting conversations. Cover lifecycle and revision semantics with backend regressions and the isolated OpenCode 2.0.18 fixture, including the repaired authenticated late-report notification. Validate real Solid UI restoration, editor retry identity, native background Forms, transcript/draft preservation, layout cleanup and ten-locale parity. Record Kandev research, scope decisions and separate follow-up opportunities. |
||
|
|
4d7408631d
|
feat(missions): bundle project coordination with the desktop runtime
Provision codenomad.missions through connected-daemon discovery and independent backend presence instead of requiring a source plugin in every project. Bundle the integration for Electron and Tauri, retain project-scoped mission journals across shutdown, and use the same secondary surface as Status. Complete the existing native actor execution work: persist explicit agent/model/variant choices, validate catalog selections and avoid switching busy actors. Admit assignment and report writes through the authenticated desktop bridge with durable-contract verification, session ownership, connection and worktree fences, and per-send profile environment synchronization. Advance the older source branch client/plugin pin to 2.0.11 and retain its bounded runtime metadata adaptation. The isolated 2.0.16 mission fixture passes native catalog, selection, busy queues, conflict, environment, reports, reconnect and idempotence checks. Server, UI and plugin typechecks, 31 mission tests, 10 lifecycle/transport tests and six resource-layout tests pass. |
||
|
|
f26bed2f8f
|
chore(opencode): qualify and recommend stable 2.0.18
Align server/UI client and bundled plugin pins with the latest stable runtime while preserving the demonstrated 2.0.7 timestamp minimum. Review the published declarations and authenticated native schema: pairing and Shell signal additions require no CodeNomad API adaptation. Make the isolated native upgrade fixture follow the recommendation while retaining its 2.0.15 source boundary and live-daemon PID assertion. Extend setup version coverage and update the current compatibility and architecture references. Validate both minimum/current native runtimes, historical migrations, server/UI tests, setup and tool-image browser scenarios, typechecks and production bundles. Record the intermittent Windows Node pruning/UI heap exit and successful diagnostic rerun without claiming its cause is fixed. |
||
|
|
1eb42feaae
|
chore(opencode): qualify 2.0.16 with aligned clients and plugin (#772)
Align the server/UI client, bundled plugin and recommended runtime at 2.0.16 while retaining the demonstrated 2.0.7 minimum. Verify the real generated-client detailed errors without duplicate proxy prefixes or failed mutation replay; retain explicit installation and daemon restart boundaries. Independent gatekeeper audited all 63 upstream commits and the full comparison, published packages, native consumers and targeted regressions: zero actionable findings. Native pruning/UI and historical migrations pass across Windows, Linux and macOS; minimum/current runtime contracts and dedicated Tauri jobs pass. Generic browser failures were independently reproduced on the exact 2.0.15 base and documented in the published review. Admin squash merge explicitly requested by the user. |
||
|
|
ea3aeb9e3e
|
fix(opencode): qualify 2.0.15 and preserve generated proxy URLs (#752)
Validation includes isolated minimum/current native suites, historical migrations on Linux/Windows/macOS, targeted unit and browser tests, production builds and two independent gatekeeper reviews with zero actionable findings. Retain startup diagnostics for an unexplained intermittent Windows pruning/UI process exit; the complete instrumented Node 24.20.0 rerun passes locally. Known system-message search fixture timeouts remain documented. Admin merge explicitly requested; runtime activation and desktop installation remain separate actions. |
||
|
|
e76e4484ab
|
fix(opencode): ground compatibility retirement in native contracts
Replace the arbitrary 2.0.11 floor with the 2.0.7 native step-timestamp boundary, keeping 2.0.11 as the separately recommended qualification target. Unlisted, prerelease and custom runtimes negotiate authenticated API requirements; preserve complete CLI labels so unknown builds neither fail solely by name nor enable unintended automatic upgrades. Finish retiring pre-2.0.4 location/worktree/credential/Form serialization and obsolete catalog events while preserving internal identity, import/cursor authorization, pruning claims and connection fences. Remove the unused global package-manager installer and clean generated server output before packaging so deleted modules cannot survive incremental builds. Distinguish missing setup, technical incompatibility and optional updates in the shared UI, including minimum rationale and optional restart wording. Retain a usable daemon through older discovery CLIs, check reload capability independently, and suppress installation when bundled npm is unavailable. Validated 622 server tests, 7 browser scenarios, real reducers and fixture guards, production native suites on 2.0.7 and 2.0.10, and synthetic 2.0.3-to-2.0.7 history migration. Independent gatekeeper re-review closed the production version-parser finding. CI now qualifies the source-defined minimum and latest; rebuilt desktop acceptance is recorded separately. |
||
|
|
4a77d162eb
|
docs(opencode): record final native acceptance and gatekeeper closure
Record completed historical migrations, bounded installation/reload fixtures, canonical WSL provisioning, cross-selection service-action fencing and packaged Electron/Tauri acceptance. Document the native watcher and reload semantics, read-only old-daemon registration fallback, final evidence roots and reproducible isolated commands. Close local review gates after every actionable finding was corrected and independently re-reviewed. Record the final 621-pass server suite and seven browser regressions while keeping final-head remote CI distinct from earlier green test jobs. |
||
|
|
7869e609b3
|
feat(opencode): enforce stable runtime support and add managed setup
Require stable OpenCode >=2.0.11 <3.0.0 from authenticated daemon metadata before functional clients and plugin provisioning. Keep bounded contract recognition, connection-generation fencing and native ownership checks while retiring old request, response and event conversions. Unify missing and outdated runtime recovery with Preferences. Install exact stable releases through bundled Node/npm into a verified versioned user prefix, preserve custom and WSL selections, and separate installation from explicit shared-service restart through the native-parent starter. Fence stale setup responses, retain pending folder opening and never replay prompts. Certify isolated 2.0.3-to-2.0.11 history migration with executable hashes, untouched seed storage, paginated messages, forks, compaction checkpoints, location moves and pending inbox data. Add minimum/latest cross-platform migration and installation gates, packaged npm closure checks, real Solid recovery regressions and supported-contract authority tests. Validated server/UI types, focused unit and reducer suites, browser captures, actual packaging-prepared Node 24.20.0 installation without system Node, and native location, automation and pruning fixtures. Document packaged-desktop, WSL, broader historical-state and remote-CI evidence as remaining release gates. |
||
|
|
ca94224b74
|
fix(opencode): align current contracts and fence native message settlement (#728)
Align the server/UI OpenCode client and bundled plugin at 2.0.11. Route canonical server.info through authenticated discovery, preserve legacy step timing, and honor hidden Forms protocol fields without rendering their inputs or dropping defaults. Reconcile terminal tools into the bounded visible transcript and fence native reducer history reads against intervening events. Discard stale pages and coalesce trailing reads so a late settlement snapshot cannot remove a newer streaming assistant. Preserve lifecycle, generation, disposal, location and historical-data safeguards. Qualify the latest stable runtime in CI and record the resolved version. Each CodeNomad release fixes its minimum supported OpenCode version to the latest stable available when that CodeNomad release ships. Keep one shared compatibility reference and detailed evidence in PR/CI history rather than per-version reports. Validation includes isolated native runtime/proxy/pruning, automation, environment and fork acceptance; hidden Forms browser coverage; deferred settlement/new-execution regressions; 112 final targeted UI tests, typechecks and production builds. Gatekeeper findings were fixed and independently re-reviewed before merging. |
||
|
|
19daab1bbe
|
merge(dev): resolve Missions against current native runtime
Merge dev
|
||
|
|
bdac05bb25
|
fix(environment): refresh profile variables before each prompt (#714)
## Summary Apply the existing CodeNomad profile environment **before every prompt, custom command and session-shell send**, then forward the request only after OpenCode acknowledges it. This makes profile changes available to local commands even when the shared daemon is already running. No per-conversation settings UI, polling, session-opening writes or daemon restart. The implementation lives in the shared server for Electron/Tauri/web parity. close #711; awaiting reporter validation rather than automatically closing the issue. ## Implementation - Build a complete execution-host snapshot; preserve PATH and other inherited values, normalize Windows key collisions, and exclude internal authentication/storage variables. WSL reads its selected distro's environment instead of sending Windows PATH/HOME. - Apply after ownership checks and worktree mutation admission, using the pinned native connection. Fail the send on environment errors, stale connection or disconnect; never log the native environment request body. - Update help and failure messages in every locale. Changes and removals take effect on each conversation's next send. ## Validation - Server suite: **586 passed, 2 platform skips**. - Focused UI send/SDK/authority tests: **112 passed**. - Server, UI and Electron typechecks; production UI build passed. - **OpenCode 2.0.9 / Windows native fixture:** real WorkspaceManager + guarded proxy + native shells, two conversations, changes/removal, no mutation on read, Git Bash, unchanged daemon PID. Independent configuration/database/port; only the fixture service was stopped. - Reproduction: `node scripts/test-session-environment-native.mjs <absolute-opencode-executable>`. ## Scope This changes local session command environments, not provider/MCP/LSP configuration or daemon-internal temporary files. The native environment belongs to a session: another client or a new send during existing work can replace it. Queued prompts do not get individual snapshots, and native-created subagents are not automatically intercepted. Details: `dev-docs/SESSION_ENVIRONMENT.md`. Existing oversized files touched narrowly: `packages/server/src/server/http-server.ts` (~2,300 lines), `packages/server/src/workspaces/manager.ts` (~1,200 lines), and `packages/ui/src/lib/i18n/messages/*/settings.ts` (~600 lines each). |
||
|
|
f0a6e2e0dd
|
feat(browser): add autonomous native previews (#666)
## Summary
- Add autonomous native browser previews for Electron and Windows Tauri,
using the authenticated backend/native bridge already shared with
desktop inspection.
- Ship one bundled **`codenomad.automation`** V2 plugin for browser,
inspect, act and screenshot. All tools are available by backend
presence; ordinary desktop startup prepares the instrumentation. Remove
the Developer Mode toggle, marker-based activation and activation
restart requirement.
- Provision through native discovery using the **connected daemon's
authenticated `config.get` roots**, including WSL and reconnects. Share
installation/lease mechanics with pruning, preserve user-authored
entries and older backends' leases, and unwind stale or interrupted
preparation.
- Preserve session/location ownership, inspected-host pinning, browser
registration/navigation generations, local-window targeting and
authenticated transport. The OpenCode daemon remains externally owned.
## Gatekeeper review — September 18, 2026
Merged current `dev` at `
|
||
|
|
cf537740f1
|
fix(desktop): preserve shared OpenCode service after CodeNomad exits (#702)
## Summary Fixes #691. On Windows, an OpenCode daemon started by the Tauri backend could inherit its kill-on-close Job Object. Closing CodeNomad would then terminate the shared daemon even though the server never called `service stop`. - Delegate only the official `service start` command through the private backend-to-native-parent bridge. - Launch the starter outside backend containment in both Tauri and Electron, preserving the selected host/WSL CLI, environment, working directory and Windows wrapper arguments. - Keep status, password retrieval and authenticated health in the server lifecycle. Standalone servers continue using the official CLI directly. - Bound starter deadlines/output, redact failures, and never fall back into backend containment after a native-start failure. - Leave daemon descendants externally owned; starter cleanup never terminates them. ## Validation - Server and Electron typechecks passed. - Server suite: 458 passed, two platform skips; final native bridge/failure tests: two passed. - Electron native suite: 197 passed, four POSIX skips; final starter tests: three passed. - Tauri backend tests: 29 passed; starter tests: two passed, including verbatim Windows `.cmd` quoting. - Isolated fake services remain reachable after actual Windows backend Job Object destruction and Electron process-tree enforcement. The final lifetime regression also passes after fixture-cleanup hardening. - Rust module/tests compile-check for macOS ARM64 passed; this is not a macOS runtime test. - Tauri Windows release build and packaged-resource smoke checks passed, with five pre-existing dead-code warnings. The lifetime tests do not use the real shared OpenCode service or a user database. The built artifact has not been installed over the other active development build. ## Maintenance notes Touched existing oversized source files: `packages/server/src/workspaces/manager.ts` (~1,040 lines), `packages/server/src/index.ts` (~680), `packages/electron-app/electron/main/process-manager.ts` (~640), `packages/tauri-app/src-tauri/src/cli_manager.rs` (~2,340), and `packages/tauri-app/src-tauri/src/main.rs` (~2,510). New starter and regression modules keep the added behavior separately scoped. ## Gatekeeper follow-up Updated against dev and corrected the findings in `b66cdb50`: - Fence native side effects before Electron dispatch so a closing/superseded backend cannot start a service from buffered stdout. The new regression failed before the fix. - Reproduce and fix the Linux lifetime fixture's premature cleanup assertion: wait for Node to reap the child, then require final containment confirmation. - Align the native bridge test with the current status contract after the dev merge. Post-fix review found no further confirmed issue in the reviewed paths. Current validation: 533 server tests passed (two skips); 198 Windows Electron native tests passed (four skips); 30 real Linux starter/bridge/stop tests passed (three Windows skips); 29 Tauri backend and two starter tests passed. Server/Electron typechecks passed. CI is running on the updated head. |
||
|
|
83a4124b37
|
feat(v2): manage session families across worktrees (#649)
## Summary Manage complete session families across the opened local repository's native OpenCode worktrees. This supersedes #642 with the V2 implementation and addresses #319. - OpenCode owns `worktree.refresh/list/create/remove`; CodeNomad supplies the default directory, named-branch policy, local repository scope and verified family transactions. - A project is the opened local checkout and its registered worktrees, identified through the physical Git common directory. Independent clones sharing an OpenCode project ID stay separate. - Session rows, composer selection, search and the Git panel follow native `SessionInfo.location.directory`. Durable metadata is preserved, but old `worktreeSlug` metadata does not override native placement. - Creation uses the selected checkout's revision and the main local checkout's `.codenomad/worktrees` parent. Uncommitted edits stay in the source checkout. External registered worktrees remain discoverable. - Keep copy/open/delete actions in the accessible selector, remove the redundant action bar, hide root-workspace badges, and explain “Create and use” in all ten locales. ## Current base and native contract This branch includes merged `dev@e47e01c6`, including #697's separately reviewed discovery/status compatibility fix. UI/server pin `@opencode/client@2.0.4`; the independently managed daemon has no exact-version startup gate. - Complete bounded inventories use opaque native cursors; continuations send only the cursor. - Moves are serialized across complete families, block active sessions, verify authoritative native locations and roll back partial failures. - Native move events refresh placement and the catalogue without speculative cross-project transfers. - Opaque worktree identifiers are separate from mutable branch labels. The main checkout cannot be removed. - Native detached creation is followed by ordinary Git branch selection, preserving Git's refusal to reuse a checked-out branch; branch-attachment failure cleans up through the native API. - Agent placement instructions distinguish creating a checkout, one-off commands and moving the conversation's execution context. Explicit attachment choices are preserved. ## Deletion safety - Physical checkout reservations cover published and in-flight logical workspaces. - Project serialization and deletion fences cover all family source/destination checkouts. - Complete inventories and cross-project checks run inside the deletion fence, including nested workspaces and owned Shell/PTY resources. - Canonical path, filesystem identity, registration, branch, HEAD and active sessions are rechecked before removal. Replacement checkouts fail closed; rollback requires the original identity. ## Recovery and Git-panel corrections Validation on the real repository exposed serial enumeration of 162 worktrees and concurrent ownership misses launching overlapping inventories. Git annotations now run with bounded concurrency, pending catalogue reads are shared, and negative ownership results are snapshot-cached. A regression exercises 40 concurrent misses. The Git panel now treats its complete local staged/unstaged inventory as authoritative instead of resurrecting native-only stale rows. It also rechecks the selected worktree/request after waiting for native VCS status. ## Validation Latest integration validation: - Isolated official **OpenCode 2.0.0 and 2.0.7**: production discovery/status, native worktree discovery/create/remove, selected HEAD/default parent/named branches, independent-clone scope, stable IDs, nested paths, checked-out/dirty guards, complete family moves and rollback. - Real Solid selector browser tests: mouse, keyboard, touch, actions without session movement, creation source and returned stable ID. - Targeted server ownership/cache/manager/proxy/route/location tests; UI session projection/request-authority/lifecycle tests; family evacuation/rollback and Git model regressions. - UI/server typechecks and production server build including the UI. - Installed Windows Tauri application on the actual repository: dedicated session creation/use, native location and row/composer badges, Git marker visibility, move back, and agent `session_move` reflected in both badges. - Rebuilt UI/server resources installed; full Developer Mode restart restored the original conversation. Disposable sessions, marker, worktrees and branches cleaned up. The original conversation remained attached to `pr649-final`. - `git diff --check`. An immediate post-restart desktop run exceeded a 30-second refresh-button wait; the subsequent completed run passed. These checks validate the workflows, not a startup latency bound or exhaustive compatibility of every OpenCode payload. Earlier branch validation also covered Electron/Tauri native actions, packaging and desktop parity; those results remain in the PR's historical validation comments. Detailed contract and latest evidence: `dev-docs/WORKTREE_SESSION_PLACEMENT.md`. ## Residual limit OpenCode and Git expose no shared snapshot/CAS transaction. CodeNomad narrows races with reservations, locks, fences and repeated authoritative checks; unrelated processes can still mutate state outside those controls. |
||
|
|
e47e01c660
|
fix(opencode): support server.info discovery without breaking earlier V2 (#697)
## Summary Follow-up to #695: restore connections to OpenCode 2.0.7, whose authenticated service metadata endpoint is `/api/info`. Built directly on current `dev` (`aa51cbb9`). - Probe `/api/status`, then `/api/health`, then `/api/info`, advancing **only on HTTP 404**. - Preserve credentials, the absolute deadline, bounded/validated responses, and reject redirects. - Record the discovered route and adapt the pinned client's `GET server.status()` call to `/api/info`. - Preserve OpenAPI contract negotiation for unknown releases; no 2.0.7 special case or new minimum version. **OpenCode 2.0.0 remains supported by the existing health path.** Its real isolated daemon passes the connection and native location regression fixture with this change. This PR contains only the service discovery/transport fix and its tests/docs. Worktree catalogue performance/cache changes remain in #649 and are not dependencies of this fix. ## Evidence Comparing all 132 generated-client HTTP method/path pairs against the installed 2.0.7 OpenAPI schema found 131 unchanged pairs and the status/info difference fixed here. Experimental routes were already covered by #695; no additional experimental-route migration is needed. ## Validation - [x] 44 focused host/WSL lifecycle, shared-service, transport and negotiation tests - [x] Server TypeScript check - [x] Real isolated OpenCode **2.0.0**: production health discovery, canonical `client.server.status()`, legacy location identity, Forms, Shell/PTY scoping, SSE, foreign cursor/session refusal and exact move rollback - [x] Real isolated OpenCode **2.0.7**: production info discovery, canonical `client.server.status()`, modern worktree location and obsolete-selector rejection - [x] Staged whitespace check Native fixtures use dedicated temporary databases/configuration and do not target the shared user daemon. These checks establish discovery and targeted contract behavior, not an exhaustive certification of all runtime features. Signed commit: `16d10fcd`. |
||
|
|
fb07e299c7
|
merge(dev): migrate Missions to the current native plugin contract
Integrate dev
|
||
|
|
aa51cbb9ff
|
fix(opencode): support earlier and modern V2 runtime contracts (#695)
Closes #694 ## Status This PR contains the stable 2.0.4 client migration, authenticated V2 discovery fallback and shared cross-runtime compatibility implementation. The validation results below are local execution evidence; the newly added CI matrix must also run on the updated PR head. ## Published changes - Pin UI/server to official `@opencode/client@2.0.4` and the bundled pruning plugin to `@opencode/plugin@2.0.4`, with the corresponding lockfile migration. - Probe authenticated `/api/status` first. Fall back to earlier V2 `/api/health` **only on HTTP 404**, retaining the endpoint, credentials, 64 KiB response bound and absolute deadline. Authentication, transport, server and malformed-status failures do not trigger fallback. - Migrate the canonical UI/server contract to stable Forms, permission decisions, command names, interrupts, renaming, forks, message lookup and inbox delivery. - Update the guarded proxy for stable methods/paths, native active-session envelopes, native `cursor.next`, global Form directory headers and current resource/plugin events. - Follow the renamed upstream platform binary `bin/opencode(.exe)` while retaining public CLI aliases. Discovery success alone does not establish compatibility with an earlier runtime's conversation APIs. ## Shared cross-runtime compatibility ### Shared cross-runtime integration - Introduce one connection-scoped adapter under `packages/server/src/opencode/compatibility/`, used by both the guarded UI proxy and direct server callers, including Yolo. - Select the contract using authenticated daemon identity rather than the CLI executable's version. Recognize unknown publications through authenticated, bounded OpenAPI negotiation instead of an exact runtime-version gate. - Bind authorization, client, transport and profile to one connection generation. Fence actual mutation dispatch after asynchronous body preparation; prevent late old streams from publishing or invalidating their replacement. - Translate earlier V2 routes, methods and payloads before sending. Never retry a mutation speculatively after 400, 404, authentication or transport failures. - Normalize legacy HTTP inbox timestamps, including compaction admission, before the pinned Solid reducer. Preserve the distinct native SSE inbox schema and durable event metadata. - Restore legacy catalog/content invalidation and permission-event convergence. Preserve meaningful method/path/status/profile diagnostics and native 401 error envelopes. ### Location authority and pruning - Preserve legacy workspace identity internally through request serialization, catalog/cache keys, Forms, imports, cursors, events and exact move rollback. Modern public APIs continue to reject obsolete workspace selectors. - Authorize complete locations before translating directories or synthesizing upstream Form/location headers. Keep native cursor tokens unchanged. - Preserve session/path ownership, worktree mutation fences and the restricted proxy allowlist. Generic RPC, plugin management and destructive revert commit remain blocked. - Carry verified legacy identity through pruning membership checks, preview and the existing transactional storage/claim fence; do not relax deletion checks. - Treat native idle records as control records, retaining identity/outcome without fabricated assistant text. - Add a common multi-runtime CI matrix and the audit/evidence register in `dev-docs/OPENCODE_V2_COMPATIBILITY.md`, including preserved historical architecture findings. ## Local validation All native tests use isolated synthetic daemons, configuration and databases, never the shared daemon or user storage. | Check | Result | | --- | --- | | Same native suite on beta-19271, 2.0.3, 2.0.4 and 2.0.5 with pinned client/plugin 2.0.4 | Passed | | Full native pruning suite with non-null legacy workspace identity on beta-19271 and 2.0.3 | Passed | | Rendered UI on modern 2.0.5 and beta-19271 with non-null identity | Passed | | Native 2.0.5 suite inside Ubuntu/WSL, using a temporary Linux filesystem root | Passed | | Server tests (after CI follow-up) | 500 passed, 2 skipped | | UI store tests | 441 passed | | Electron native tests | 194 passed, 4 skipped | | UI/server/Electron typechecks | Passed | | UI/server and Electron production builds | Passed | | Windows Tauri release executable (`--no-bundle`) | Passed | | Electron/Tauri packaged-resource smoke checks | Passed | | Desktop packaging invariants | 4 passed | | `git diff --check` | Passed | The native matrix exercises the actual shared connection, generated client, UI fetch adapter and guarded proxy: voice-off/on instructions, prompts, commands, session Shell, background Shell output cursors/removal, UI/Yolo permission acceptance and rejection, busy inbox delivery/cancellation, interrupt/wait, staged revert clearing, session/global/worktree Forms, native pagination, export/import, same-directory legacy identities, scoped events, foreign authority refusal and exact rollback. Pruning coverage includes actual storage identity and execution claims, busy refusal, idempotency, competing admission, next-model payload, fork isolation, pre-compaction history, restart, backend presence disposal/reopening and crash expiry. Rendered tests cover individual/group/response/session cleanup, confirmation counts, persistence and reload. ## Autonomous gatekeeper review Review/fix/retest loops concluded with no remaining actionable findings in the reviewed transport/lifecycle/proxy, identity/UI/events/pruning/rollback, scripts/CI and rendered-fixture scopes. Corrections included dispatch-generation races, compaction admission normalization, independent negotiation cancellation, first-request profile resolution, preservation of streamed 401 envelopes and direct Shell/PTY identity propagation. A final rendered failure was traced to the fixture awaiting only the first RPC of a cross-message deletion; the fixture and regression now await every affected message. Production deletion guards were not relaxed. This scoped approval does not close the separately preserved historical architecture findings. ## Validation boundaries ### CI follow-up The first run on `a0c1c943` ([35142559235](https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/35142559235)) failed in five native jobs. The local bundle tests had missed the standalone npm archive's missing sibling import, and Windows legacy jobs exposed a short-path versus canonical-path project comparison. The dependent artifact-comment job reported that same build failure. The follow-up makes the plugin's identity primitives self-contained, adds an isolated npm-file-list regression for all exported entrypoints, and corrects project identity selection with alias and nested-repository regressions. The packed-plugin failure was reproduced before correction; the corrected installed package passes the native suite on Windows 2.0.4 and Linux/WSL 2.0.4/2.0.5. The corrected 2.0.4 shipped bundle also passes rendered/native pruning. Fresh full beta-19271 and 2.0.3 `--legacy-pruning` suites pass under a reproducing Windows short-path TEMP root after the final exact-directory fix. Independent final reviews approve packaging/documentation and worktree identity with zero actionable findings. Remote checks on the new head remain the CI authority; these are local follow-up results. - Full interaction with the installed desktop application through Developer Mode was not verified because Developer Mode is inactive. The release executable and packaged-resource checks above are build/smoke evidence, not a fresh-install interactive certification. - Remote run [35146390688](https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/35146390688) at `486e856d` passes all runtime-contract jobs, Windows/Linux native pruning, service compatibility, general tests and both Tauri checks. macOS passes packed-plugin loading/pruning, then times out on late bundle discovery. The fixture now canonicalizes its root before daemon startup to align `/var` configuration paths with `/private/var` FSEvents paths. Late installation remains mandatory and asserts the plugin was initially absent; failures now upload isolated diagnostic logs/inventory/captures. Actual macOS confirmation remains pending on the new head. - Interactive native TUI validation was not performed. - The passing WSL result is Linux-native execution inside WSL, not a complete Windows-host/WSL desktop traversal. With the fixture's configuration directory under `/mnt/c`, conversation/proxy checks passed but late plugin discovery timed out; the otherwise equivalent Linux-filesystem run passed. Mounted-configuration late discovery remains a documented environment limitation. - Other audited publications are declaration-reviewed, not individually native-certified. The four-runtime matrix does not imply universal V2 compatibility. - Earlier PR artifacts do not contain the completed cross-runtime implementation; use artifacts built from the updated head. Local passing results do not imply that the updated remote CI has completed. |
||
|
|
dec86c5d96
|
feat(missions): enforce native playbook contracts
Require structured Pocock evidence for completed diagnosis, implementation, independent standards/spec reviews, resolution, and final validation. Fence fresh reviewer and validator roots while requiring review resolution to reuse the implementer, and cover a full dynamic Pocock cycle plus a breadth-first Wayfinder map. Align the project-local plugin with beta-18999 runtime behavior by emitting native typed system parts, JSON-normalizing optional RPC output, using the typed RPC call as the capability probe, and keeping the runtime entry free of an SDK import. Add a dedicated compile-time plugin contract check to CI. Record the private-runtime spike proving busy-root queue delivery, resume, correlated synthetic reporting, restart restoration, idempotent admissions, typed invalidations, owned broker access, and shared project storage across worktrees. Targeted mission, plugin, and broker tests pass alongside server and plugin typechecks. |
||
|
|
366d934e3a
|
feat(missions): add native session mesh control plane
Introduce the project-local codenomad.missions V2 plugin with a durable append-only mission map, deterministic OpenCode inbox admissions, and the compact mission.inspect, mission.delegate, and mission.report tool interface. Root sessions remain visible native actors, only coordinators may change topology, and blocked tasks are mapped without a hidden workflow interpreter. Add constrained CodeNomad snapshot brokering instead of exposing generic plugin RPC. Workspace-owned locations, active plugin inventory, project identity, root-session membership, actor limits, and foreign-session fences are checked at their respective seams. Queue/resume delivery supports busy actors and deterministic IDs make interrupted dispatch and report notification retries idempotent across restarts. Ship dynamic custom, Pocock bug-expedition, and Wayfinder playbooks plus provenance and architecture documentation. Pin the local plugin contract to beta-18999 alongside the reviewed V2 client. Validated with the server TypeScript check and 12 focused mission, plugin registration, recovery, authorization, idempotence, and broker tests. |
||
|
|
52f0e62935
|
feat(opencode): migrate CodeNomad to native V2 (#647)
# OpenCode V2 Migration and Desktop Restructuring
## Summary
This branch replaces CodeNomad's OpenCode V1 SDK, custom plugin, and
per-workspace runtime architecture with the native OpenCode V2 client
and one shared OpenCode service. It intentionally ships no V1 runtime
fallback.
The scope includes native location ownership, Forms and Shell resources,
project-wide cursor pagination, bounded resident message windows,
streaming reconciliation, duplicate-folder instances, multi-window
Electron/Tauri behavior, content-addressed restore, worktree mutation
fencing, and reproducible desktop packaging.
The reviewed implementation head is `
|
||
|
|
ca06bd99d7
|
feat(yolo): move permission auto-accept (Yolo) to the server (#561)
## Summary Yolo (permission auto-accept) currently lives entirely in the UI. Each browser keeps its own toggle in `localStorage` and auto-replies to permission requests over a 4-hop path (`OpenCode → server SSE → UI → server proxy → OpenCode`). The server — which already sits on the event stream that carries every `permission.asked` — does none of the work. This PR makes the **server authoritative**: it owns the toggle state, resolves family-root inheritance, and performs the auto-reply in-process via loopback using the same `"once"` semantics the UI used to send. The UI becomes a pure view: it toggles via REST and mirrors state from a `yolo.stateChanged` SSE event. ## Why - **Correctness**: the server already consumes the instance SSE stream (`InstanceEventBridge`); auto-accepting there is the natural choke point instead of bouncing to the UI and back. - **Multi-client**: previously each browser had independent `localStorage` state and never synced. Toggles now broadcast to all connected clients in real time. - **Headless**: Yolo keeps auto-accepting even when no UI is connected (useful for long autonomous runs). - **Latency**: drops from 4 hops to a single in-process loopback call. ## What changed **Server (new, authoritative)** - `permissions/auto-accept-store.ts` — in-memory state keyed by family root. Faithful port of `resolvePermissionAutoAcceptFamilyRoot`: fork/`revert` sessions root at themselves; enabling any member enables the whole family. - `permissions/auto-accept-manager.ts` — subscribes to `instance.event`, builds the session tree from `session.created/updated/deleted` (`properties.info`), intercepts `permission.v2.asked` / `permission.asked`, dedupes in-flight replies, emits `yolo.stateChanged` / `yolo.autoAccepted`, clears per-instance state on `workspace.stopped/error`. - `permissions/opencode-replier.ts` — default replier calling OpenCode directly (`getInstancePort` + auth header), mirroring `background-processes/manager.ts`. - `server/routes/yolo.ts` — `GET/POST /workspaces/:id/yolo/sessions/:sid[/toggle]`, following existing route conventions. - `api-types.ts` / `events/bus.ts` — `YoloStateResponse` + the two new event types registered in `onEvent` so they flow over `/api/events`. **UI (pure view)** - `permission-auto-accept.ts` — removed `localStorage`, persistence, and drain logic; now a runtime (non-persisted) projection. `resolvePermissionAutoAcceptFamilyRoot` is **retained as a display aid** so the badge still lights up for child/sub-sessions of an enabled family (preserving the inheritance UX). - `instances.ts` — toggle calls REST (optimistic, reconciled on success, reverted on failure); subscribes to `yolo.stateChanged`; `ensureYoloStateSynced` backfills the active session's state on first connect (deduped per session, reset on SSE reconnect so it re-syncs after a server restart). - `session-events.ts` — removed the three `drainAutoAcceptPermissionsForInstance` hooks (the server drains now). - `api-client.ts` — `getYoloState` / `toggleYolo`. ## Behavior parity | Aspect | Before | After | |---|---|---| | Reply semantics | `"once"` | `"once"` (unchanged) | | Inheritance | whole family (root + non-fork descendants) | **same** | | Fork isolation | `revert` session is its own root | **same** | | Persistence | UI `localStorage` | none (intentional, see Notes) | | Multi-client sync | ❌ independent per browser | ✅ real-time via SSE | | Works with UI closed | ❌ | ✅ | | Auto-reply path | 4 hops | 1 in-process hop | ## Testing 32 unit tests added (`node:test`), all passing. Server + UI typecheck clean. - **Store (16)**: inheritance (parent/child/sibling), fork isolation, cyclic parent chains, late parent discovery, `revert` re-rooting, per-instance independence, tree maintenance. - **Manager (13)**: real `properties.info` event shapes, v2 vs legacy reply, in-flight dedup + retry-after-resolve, `yolo.stateChanged` emission, `session.deleted` keeps toggle, `workspace.stopped` clears state, `stop()` unsubscribes. - **UI (3)**: retained `resolvePermissionAutoAcceptFamilyRoot` display-projection tests. ## Notes for reviewers - **No persistence is intentional** for this milestone — server restart resets all Yolo state (matches the agreed scope). The UI mirror self-heals via SSE reconnect + `ensureYoloStateSynced`. Persistence can be layered on later (e.g. into `~/.config/codenomad/config.json`) without touching the manager. - **Family-root resolution lives in two places on purpose**: the server resolves it to decide whether to auto-reply; the UI resolves the same pure function to render the badge instantly (synchronous memo). Both are faithful ports; no network round-trip is added for display. - **`properties.info` nesting**: OpenCode wraps session records under `properties.info` for `session.*` events (permission events are flat). The manager handles both and the tests use the real nested shape to guard against regressions. - `getYoloState` / `yolo.autoAccepted` are wired but `yolo.autoAccepted` is not yet consumed by the UI — it's available on the wire for future observability (e.g. an audit log / toast). ## Risk / rollback The change is additive on the server and the UI gracefully degrades to the SSE mirror. If the server lacks the new routes (mixed-version), the UI's optimistic toggle still flips locally and `toggleYolo` failures are logged + reverted, so no hard breakage. --------- Co-authored-by: Pascal André <pascalandr@gmail.com> |
||
|
|
d9ff1e03cf
|
revert: remove tracked NomadWorks task artifacts (#531)
## Summary This PR removes tracked NomadWorks/OpenCode/task-tracking artifacts that were accidentally committed to the repository and now interfere with local NomadWorks usage for other contributors. NomadWorks generates local workflow state such as `tasks/`, SCR registries, and codemaps as needed. Keeping those generated artifacts tracked in the shared repository creates stale state, false active tasks, and confusing/broken NomadWorks behavior for other users who initialize or run the workflow locally. ## Problematic commits / artifacts The cleanup addresses artifacts introduced by the following Shantur-authored commits: - ` |
||
|
|
b142c2a681
|
feat: add CodeNomad architecture guide skill for contributors (#493)
## Summary
Add comprehensive architecture and SDK navigation skill to help
contributors navigate the codebase without missing related code.
## What's Included
- **Architecture Overview** — 6 functional areas (UserInterface,
ServerBackend, DesktopClient, SpeechAndAudio, BuildAndPackaging,
CloudflareDeployment), package map, and key entry points
- **UI Conventions** — SolidJS patterns, i18n system (7 locales),
signal-based stores, component styling
- **Server Conventions** — Fastify route patterns, API types,
configuration, testing approach
- **Desktop Conventions** — Electron + Tauri parity rules, native API
abstractions
- **SDK API Reference** — All 10 OpenCode SDK V2 categories used by
CodeNomad with signatures and wrapper locations
- **SDK Critical Behaviors** — Schema gotchas (assistant part metadata,
ignored flag asymmetry), decision matrix, race conditions
- **SDK Integration Patterns** — Client lifecycle, worktree routing,
error handling, optimistic updates
- **Feature Traces** — 5 end-to-end flows with decision branches:
permissions, sessions, speech, background processes, git clone
- **Anti-Patterns** — Common mistakes with file references to correct
implementations
- **Implementation Checklist** — Actionable steps before submitting
changes
## Design Decisions
- All navigation guidance uses standard grep/file search tools (no RPG
MCP server required)
- Split into 8 reference files to stay under 300 lines each
- File references included for every anti-pattern and convention
- Decision branches in feature traces (not just linear flows)
- Weighted quick start by contribution frequency
## Files Added
`
.opencode/skills/codenomad-architecture-guide/
├── SKILL.md
└── references/
├── architecture-overview.md
├── ui-conventions.md
├── server-conventions.md
├── desktop-conventions.md
├── sdk-api-reference.md
├── sdk-critical-behaviors.md
├── sdk-integration-patterns.md
└── feature-traces.md
`
|
||
|
|
0eca320d5e | Use never release notes format |