Commit graph

21 commits

Author SHA1 Message Date
Pascal André
7a206a9297
feat(history): rank past-session search and expose it to agents as session_search (#1161)
## Summary

Agents can now find past discussions themselves. The bundled
session-pruning plugin registers a Code Mode tool,
`codenomad.session_search`, ranked by relevance over the calling
session's own project history. This is PR 1 of 2: server/plugin only;
the search window keeps its current behaviour until PR 2 wires the same
engine.

- **Tool scope:** the caller's directory tree, native workspace and
project (plus `global`) history, never other projects. The caller's
location is checked before and after the read, and excerpts are flagged
as untrusted transcript data. The tool follows backend presence like the
plugin's RPCs.
- **Ranking:** up to six Unicode terms; a precise SQL prefilter over
rowid chunks (superset of the JS judge: ASCII folding, Unicode case
classes, literal `\u` escape fallback) yields per-term IDF weights. The
best candidates are judged one bounded body at a time on word
boundaries, with an exact-phrase bonus, prose before tool payloads,
recency as tie-break and one hit per session before repeats. Optional
inclusive UTC `since`/`until`. Candidate, session, judge and time caps
are reported.
- **Shared limits:** scope SQL, readable-part extraction, the 16 MiB
message bound and 40 ms slices move to `history-content.ts` and are
shared with the literal search.
- **For PR 2:** a versioned `historyRanked` RPC returns the same hit
fields plus per-session provenance, so the broker can validate ownership
as for `history`. Existing RPC methods, HTTP routes and UI are
unchanged; the generic RPC proxy stays closed.

Inspired by `@rizal72/oc-session-search`.

## Validation

- Session-pruning tests 98/98, including the package regression; native
plugin bundle 1/1; server typecheck.
- Regressions: Unicode terms and accented case variants, weights, phrase
bonus, diversity, dates, prefilter precision (multi-line and accented
messages lacking a term are not candidates), a rare old match outranking
600+ newer frequent ones, scope isolation, cancellation, caps, skipped
rows, tool registration and presence disposal.
- Isolated native history fixture on OpenCode 2.2.0: 23 checks,
including a ranked query (3 hits across 2 sessions). No shared daemon or
user database was used.
2026-10-27 19:41:50 +01:00
Pascal André
52133e2148
chore(remote-control): update OpenTunnel to 0.5.1 (#922)
Adopt the upstream fix for the hosted API's intermittent Cloudflare 525s (anomalyco/opentunnel#45): transient API failures are retried with capped backoff, errors name the HTTP status, and an unexpired saved certificate keeps serving when the check still fails. The PROXY protocol stays disabled. The adapter declares the workspace's single stable Effect 4.0.1, and the opt-in live test resolves the SDK wherever npm places it. Validated typechecks, build, 38 Remote Control tests, packaging checks, packaged Node imports and the live hosted-relay run; merged without waiting for CI at the user's request.
2026-10-12 17:52:07 +02:00
Pascal André
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.
2026-10-12 16:42:07 +02:00
Pascal André
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)
2026-10-11 14:55:49 +02:00
Pascal André
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.
2026-10-09 12:43:25 +02:00
Pascal André
c954841f09
revert(missions): undo PR #673 without dropping later dev changes
Revert merge c118478805 relative to its first parent after the user confirmed the merge was requested in the wrong conversation. Remove the published Missions plugin, control routes, UI, playbooks and packaging references; do not rewrite dev history or touch durable-refactor work in the separate missions-v2 checkout.

Preserve subsequent PRs #792, #829 and #830. Remove only #829's now-invalid Mission reader import, dismissal hook and dedicated reader scenario, retaining the native questions/permissions dock, file-preview navigation and its other tests. Keep the 2.0.22 package pin and parent-session creation fence.

Validation: revert applied without conflicts; all 139 original merge paths reversed; later-only paths retained except the three minimal interruption-dock integration adaptations. Server and UI TypeScript checks and 18 automation/plugin lifecycle/desktop resource tests pass using existing local dependencies. Staged diff checks are clean. Full hosted CI, browser suites and native 2.0.22 qualification were not rerun for this immediate user-authorized admin revert.
2026-10-02 16:18:06 +02:00
Pascal André
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.
2026-09-27 00:57:56 +02:00
Pascal André
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 `96ef38c6` and repeated independent UI, native
and server reviews after each finding until all three scopes reported
**zero remaining actionable findings**.

Corrections include ordinary-project discovery without Developer Mode;
connected-daemon namespace selection and stale lease cleanup; Tauri
child-webview capability isolation, native-window counting,
primary-renderer reload cleanup, fragment navigation, snapshot lock
ordering and deadline-fenced protocol dispatch; and Electron guest
readiness, redirects and explicit navigation intent. Shared-frame
regressions also cover insecure HTTP and late/rejected native IPC.

### Architecture decision

Current OpenCode V2 documents MCP `_meta.sessionID`; the historical
missing-session-metadata argument no longer applies. A single native V2
plugin remains appropriate for the requested unified automation surface:
it reuses the existing authenticated transport and native controllers,
supports backend presence, and needs no second protocol server or
mode-based permission framework. Plugin loading, tool availability and
execution targeting are separate concerns.

## Validation

- Full server suite: **570 passed, 2 skipped**.
- Electron native suite: **214 passed, 4 skipped**.
- Tauri native suite: **180 passed**.
- Real Solid/browser preview suite: **14 passed**, including real
isolated Electron guests and insecure HTTP.
- Actual isolated OpenCode automation fixtures: **beta-19271, 2.0.3,
2.0.5 and 2.0.7**. Covers mismatched backend/daemon environments, late
discovery, all four tools without activation, execution fences,
independent leases, shutdown and reopening.
- Full isolated native pruning fixture on **2.0.7**, including
concurrency, durable claims, payload isolation, backend presence,
restart and worktree/location integration.
- UI, server and Electron typechecks; Electron production build; Windows
Tauri release build (`--no-bundle`); focused Rust formatting and `git
diff --check`.
- Electron and Tauri packaged-resource smoke checks, plus five desktop
packaging regressions including loading the dependency-free automation
bundle from both layouts.
- CI now runs automation discovery across the runtime matrix, includes
2.0.7, and uses Xvfb for real Electron renderer regressions on Linux.

## Validation boundaries

The fixtures never use or stop the shared daemon or a user's database.
Actual WSL runtime execution and a live packaged WebView2 interaction
smoke were not performed in this pass; WSL resolution and Tauri
controller/capability behavior have focused regressions. The currently
running desktop artifact was not replaced. Agent interruption remains
deadline-based rather than end-to-end native cancellation.
Cross-platform CI must validate the pushed head.
2026-09-18 17:46:14 +02:00
Pascal André
ea37f97bea
feat(pruning): restore opt-in selective deletion through native plugin RPC (#686)
## Summary

Restore selective deletion of completed assistant tool/reasoning content
after OpenCode removed `session.messageUpdate`, without forking OpenCode
or opening a generic RPC proxy.

The original draft's unconditional `maintenance_required` stub is
replaced by a working **experimental, explicit opt-in** plugin path for
the audited `0.0.0-beta-19419` runtime. The default remains read-only.
Unknown runtimes/storage and active native execution fail closed.
Nothing is installed or enabled on app startup.

## Implementation

- Keep individual/message/group/session cleanup entry points. Send
selected technical indices and a canonical SHA-256 revision, never
arbitrary replacement content, SQL, database filenames or
caller-selected locations.
- Use an ownership-checked CodeNomad broker with a fixed RPC
ID/method/location and worktree-deletion fence. Keep the removed PATCH
and generic RPC routes blocked.
- Bind the plugin's explicitly configured database connection to the
actual daemon DB with a fresh `ctx.storage` challenge. Inside a
synchronous SQLite write transaction, recheck
directory/project/workspace ownership, native durable execution claim,
staged revert/compaction state, event ownership and retained payloads.
- Rely on the audited native **write-ahead execution claim before runner
history reads**, not an `idle` check, plugin mutex or `BEGIN IMMEDIATE`
alone. Never set or release the native claim ourselves.
- CAS only the completed assistant's content array. Preserve IDs,
ordering, text, snapshots, usage and metadata. Commit a content-free
idempotency receipt atomically with the change; identical retries cannot
delete a second shifted block.
- Emit the custom invalidation after commit. Re-read via the native API,
invalidate the SDK transcript and pending rotations, and fence late
reads against newer invalidations. Add a public-API TUI cache companion
and reconnect handling.
- Correct native Windows path encoding; support more than 4,096 selected
parts within explicit request/message budgets.
- Provide an independently packable plugin with main and `./tui`
entrypoints, deployment/safety docs, and a Windows/Linux/macOS native
package CI matrix. Plugin installation remains manual and separately
approved.

## Validation performed locally

| Check | Result |
|---|---|
| Server/plugin/SQLite/broker/proxy tests | 72 passed |
| UI actions, events, SDK projection and stale-read tests | 60 passed |
| Plugin/SQLite/TUI-companion tests under Node 22 | 30 passed |
| Server and UI TypeScript checks | Passed |
| Production UI build | Passed; existing large-chunk warnings |
| Official Windows x64 beta-19419 executable | Passed on a private
daemon and generated DB |
| Independently packed and installed plugin | Same native test passed,
outside the checkout |

The native integration test uses the real beta-19271 network client
against the official beta-19419 runtime, with a local synthetic provider
and no credentials. It verifies actual preview/prune RPC, refusal while
a primary generation holds the native claim, both prompt/transaction
orderings, idempotent retry, two event subscribers, native re-reading,
the subsequent primary model payload, fork isolation, pre-compaction
history without summary changes, and persistence after server restart.

The new three-OS native CI matrix must pass on this head before merge.
No CI result is inferred from the local Windows run.

## Boundaries and remaining validation

- This is a reviewable opt-in implementation, **not general availability
across OpenCode versions/providers/platforms**. Exact runtime gating is
intentional; don't widen it without re-auditing/testing.
- Interactive official TUI, two native CodeNomad windows/scroll
behavior, WSL, provider-specific continuation state and budget/token
estimates are not claimed as validated. TUI companion tests use its
cache contract, not an interactive terminal. Two HTTP subscribers are
not two GUI windows.
- Existing bulk cleanup is per-message and reports failure counts;
dedicated installation/capability and bulk progress/cancel UI are not
added here.
- Existing summaries/native checkpoints, fork copies and already
assembled/sent requests are not retroactively scrubbed. Historical usage
remains historical usage; mock token values are not a token-savings
measurement.
- This changes persisted V2 content, not only visibility. It frees
reusable SQLite pages but does **not** promise a smaller physical file.
No VACUUM, V1 cleanup, durable-event rewriting, automatic backup
restoration or universal repair is included.
- No active user DB was changed, no shared-daemon plugin installed, no
shared OpenCode service stopped/upgraded, and no native desktop
executable/profile rebuilt or replaced. Tests use isolated synthetic
data only.

## Documentation

- [Request flow and validation](dev-docs/SESSION_PRUNING_RPC.md)
- [Audited safety boundary](dev-docs/SESSION_PRUNING_SAFETY.md)
- [Explicit deployment and
recovery](dev-docs/SESSION_PRUNING_DEPLOYMENT.md)

References: anomalyco/opencode#44984, anomalyco/opencode#48043,
anomalyco/opencode#48090 and the maintainer's plugin/RPC direction. No
upstream API or distribution fork is introduced.
2026-09-10 13:31:40 +02:00
Pascal André
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 `dea20996`. UI and server resolve
`@opencode-ai/client@beta` to `beta-18999`; the runtime CLI is managed
independently. The official comparison baseline remains `upstream/beta`
at `eb1ac54d73`.

Full details: [`MIGRATION_V2.md`](./MIGRATION_V2.md),
[`DESKTOP_V2_COMPARISON.md`](./DESKTOP_V2_COMPARISON.md), and
[`dev-docs/DEV_V2_CODE_REDUCTION.md`](./dev-docs/DEV_V2_CODE_REDUCTION.md).

## Stabilization Fixes

- Preserve manual scroll escape across pagination, remote updates,
capped-window shifts, tab changes, and desktop restore; only a local
prompt submission forces the bottom.
- Keep the timeline resident window capped at 200 messages. Ordered
window slides use Virtua shift, while reorder, pagination, and
non-aligned replacement remount with a fresh measurement epoch.
- Finalize the temporary `200 -> 201 -> 200` transition in a
generation-guarded microtask before paint and compensate followed
content growth from a `ResizeObserver` attached to the mounted Virtua
root.
- Keep all pending inbox prompts after delivered transcript messages in
native inbox admission order.
- Add a persisted `steer`/`queue` follow-up preference; the alternate
shortcut uses the inverse while idle sends remain `steer`.
- Edit a pending prompt only after authoritative inbox cancellation
succeeds, then restore its text, structured payload, files, and agent
references to the composer.
- Expose native `session.background` through the ownership-checked
proxy, a prompt action, and `Ctrl/Cmd+B`.
- Remove the duplicate model-selector "show all" action and make the
favorites toggle label reflect its current action.
- Restore permission/Form synchronization plus skill, reference,
MCP-resource, and websearch-provider reads in the reviewed proxy
allowlist.
- Validate and preserve native location workspace identities for
root/worktree requests, session moves/imports, cursors, and global
Forms.

## Capability Decisions

| Capability | Native V2 availability | CodeNomad `DEV-v2` decision |
Revisit or complete when |
| --- | --- | --- | --- |
| Assistant content mutation | `session.messageUpdate` authoritatively
replaces the text, reasoning, and tool content of a completed assistant
message. There is still no generic deletion of a complete delivered
message or mutation of user messages. | Restores individual
tool/reasoning deletion through the native update route. Arbitrary
whole-message deletion remains absent rather than locally simulated. |
Add broader deletion only if V2 exposes an authoritative operation for
the required message type. |
| Bulk tool and reasoning cleanup | No native bulk operation, but
`session.messageUpdate` can safely compose cleanup one assistant message
at a time. | Restores selected-group and full-session technical-part
cleanup through authoritative per-message updates. | A native bulk
operation is only needed if per-message updates become a measured
performance problem. |
| Delete-to-boundary / undo | `session.revert.stage` and
`session.revert.clear` use V2 staged-revert semantics instead of
arbitrary deletion. | Command-palette Undo uses `revert.stage`; Redo
clears the staged revert through `revert.clear`. | Revisit only if V2
adds broader authoritative transcript deletion. |
| Compaction | Native checkpoint compaction summarizes the older head
and retains a server-selected recent tail controlled by
`compaction.keep.tokens`. | Uses `session.compact`; there is no
message-level selective compaction. CodeNomad displays the partial
summary through the same reactive streaming path as text and reasoning,
then replaces it with the terminal summary. | Add scoped controls only
if V2 defines scoped compaction semantics. |
| Transcript pagination authority | Message pages expose only opaque
previous/next cursors. They provide no transcript revision, total,
absolute range, position, or random seek target. | Uses bounded cursor
traversal and a 200-message resident window, with defensive
reconciliation after destructive events. It cannot prove that pages
loaded across compaction or revert belong to one snapshot. | V2 adds
snapshot revision authority
([#43766](https://github.com/anomalyco/opencode/issues/43766)) and
navigable position metadata
([#44660](https://github.com/anomalyco/opencode/issues/44660)). |
| Full-session search | `session.list(search)` filters session titles
only. There is no server transcript-search endpoint returning message
identity, excerpt, navigable position, and transcript revision. |
Retained through exhaustive message-cursor traversal while keeping only
the 200-message resident window and collected matches. Large searches
still fetch every page. | V2 exposes transcript search
([#45801](https://github.com/anomalyco/opencode/issues/45801)) with a
target that composes with transcript revision and seek metadata. |
| Queued prompt management | Native inbox list, cancel, steer, and queue
operations cover authoritative follow-up delivery. The TUI's edit action
cancels a queued prompt before restoring it to the composer; it is not
an atomic inbox update. | Implements persisted primary `steer`/`queue`
delivery, inverse alternate shortcut, delivery switching, cancellation,
cancel-first composer restoration with structured payload retention, and
native-order timeline projection. | Revisit atomic editing or reordering
only if V2 adds an authoritative operation and a concrete product need
is established. |
| Background execution | Native `session.background` moves blocking
tools out of the foreground; Shell resources separately support listing,
bounded output, and removal. | Exposes `session.background` through the
proxy and UI with `Ctrl/Cmd+B`, and replaces the custom process manager
with native Shells. Unsupported controls such as rename remain removed.
| Add controls only when the native session or Shell APIs support them.
|
| Service lifecycle | V2 uses one shared externally owned service rather
than one runtime per workspace. | CodeNomad discovers or starts the
service. Stop Workspace evicts the native location after its final
logical owner is removed; application shutdown never stops the daemon. |
No parity work planned unless V2 changes service ownership semantics. |

## Validation

Migration gate (`878550ca`):

- UI and server TypeScript typechecks.
- 86 focused UI tests covering follow, pagination, queue ordering,
bottom pinning, shortcuts, delivery resolution, and model visibility.
- 64 focused server tests covering proxy ownership/location enforcement
and shared-service workspace identity.
- Production UI/server build.
- Tauri `cargo check` and all 121 Rust tests.
- `git diff --check`.

Timeline stabilization (`dea20996`):

- UI TypeScript typecheck and all 68 focused timeline, pagination,
request-authority, and restore tests.
- Tauri release build against the `beta-18999` lock.
- Native Developer Mode validation: no remount or empty frame during
capped shifts, same-cycle growth compensation, preserved manual escape,
and inactive-tab anchor restore within 0.3125 px.

## Remaining Gaps

- Active-session-location authority for MCP/plugin status.
- Optional interactive PTY, session export, and reference/MCP-resource
attachment UI.
- Desktop release signing/notarization hardening.
2026-09-04 11:36:11 +01:00
Shantur Rathore
cf88dc06ef
Package CodeNomad OpenCode plugin (#433)
## Summary
- Rename the OpenCode config template into a versioned npm-packable
CodeNomad plugin package.
- Build and package the plugin through the server bundle, with
Electron/Tauri carrying it via existing server resources.
- Replace OPENCODE_CONFIG_DIR injection with JSONC-aware
OPENCODE_CONFIG_CONTENT merging that appends the CodeNomad plugin while
preserving user config.

## Validation
- npm run build --workspace @codenomad/codenomad-opencode-plugin
- npm run prepare-plugin --workspace @neuralnomads/codenomad
- npm run typecheck --workspace @neuralnomads/codenomad
- npm run typecheck --workspace @neuralnomads/codenomad-electron-app
- node --import tsx --test \"src/opencode-plugin.test.ts\"
\"src/workspaces/__tests__/spawn.test.ts\"

## Notes
- Production plugin loading uses an explicit npm file alias for the
packaged tarball.
- Dev loading still references the TypeScript plugin entry directly.

---------

Co-authored-by: Pascal André <pascalandr@gmail.com>
2026-05-12 09:00:22 +01:00
Shantur Rathore
fd57bd11a6
fix(desktop): restore managed Node server startup (#348)
## Summary
- revert the Bun standalone desktop packaging path and restore the
server's original `dist/bin.js` bootstrap flow
- add a managed Node runtime for Electron and Tauri that downloads only
the current platform/arch artifact into `~/.config/codenomad`
- update desktop startup and packaging scripts so packaged apps use the
managed runtime consistently, and clean up Electron's expected
navigation-abort log noise

## Testing
- npm run typecheck --workspace @neuralnomads/codenomad-electron-app
- cargo check
- npm run build --workspace @neuralnomads/codenomad
- npm run build:mac --workspace @neuralnomads/codenomad-electron-app
- launch
`packages/electron-app/release/mac-arm64/CodeNomad.app/Contents/MacOS/CodeNomad`
and verify the packaged server reaches ready with the managed Node
runtime
2026-04-26 13:20:47 +01:00
Shantur Rathore
67a10d12e0
Don't depend on Node anymore (#346)
## Summary
- package `packages/server` as a standalone desktop executable so
Electron and Tauri no longer depend on a system-installed Node runtime
in production
- align Electron and Tauri startup logic around launching the packaged
server, resolving binaries from the user shell, and bundling the same
server resources into both desktop apps
- replace the workspace instance proxy path that used
`@fastify/reply-from` with a direct streaming proxy so packaged
standalone builds can talk to spawned `opencode` instances correctly

## Why
Desktop production builds were still depending on a user-provided Node
runtime to launch `packages/server`, which made packaging less
self-contained and created different behavior across machines. While
moving to a standalone server executable, we also found that
Bun-compiled standalone builds could start `opencode` successfully but
failed when proxying requests to those instances through `reply-from`.

The goal of this change is to make desktop production startup
self-contained, keep Electron and Tauri behavior aligned, and restore
correct communication with local `opencode` instances in packaged
builds.

## What Changed
- added a standalone build path for `packages/server` and bundle
`codenomad-server` into desktop resources
- updated Electron production startup to resolve and launch the
standalone server executable
- updated Tauri production startup to resolve and launch the standalone
server executable with matching cwd and shell behavior
- added runtime path helpers so the packaged server can reliably find
its bundled UI, auth templates, config template, and package metadata
- improved bare binary resolution so commands like `opencode` can be
resolved from the user's login shell environment
- upgraded the server stack to newer Fastify-compatible packages needed
for the standalone/runtime work
- replaced the workspace instance proxy implementation with a direct
streaming proxy for requests to spawned `opencode` instances
- updated Electron and Tauri build/prebuild scripts to generate and
package the standalone server, while also repairing missing
platform-specific optional binaries during packaging

## Benefits
- desktop production builds no longer require Node to be installed on
the user's system
- Electron and Tauri now use the same packaged server model in
production, reducing platform drift
- packaged desktop apps can successfully create workspaces, launch
`opencode`, and proxy health/session traffic to those instances
- the server bundle is more self-contained and resilient to different
launch environments
- desktop packaging is more predictable because the required server
executable is built and bundled as part of the app build flow
2026-04-21 09:04:34 +01:00
Shantur Rathore
40634138bc feat(server): add authenticated remote access and desktop bootstrap
Adds cookie-based login with a bootstrap token flow for desktop apps, secures OpenCode instance traffic with per-instance Basic auth, and updates UI/plugin clients to use credentials.
2026-01-14 18:18:14 +00:00
Shantur Rathore
847faf1214 Fix Tauri builds and Windows opencode-config loop 2026-01-07 06:25:19 +00:00
Shantur Rathore
1fcf89b945 Isolate opencode-config install from workspace 2026-01-06 20:58:01 +00:00
Shantur Rathore
f5682ea246 Fix dev CI build tool resolution and Windows npm spawning 2026-01-06 20:45:40 +00:00
Shantur Rathore
ac8dfcc607 Improve opencode-config install on Windows 2026-01-06 20:30:40 +00:00
Shantur Rathore
dab1e0fa7a Bundle opencode-config dependencies 2025-12-24 20:25:19 +00:00
Shantur Rathore
722b523f92 Add packages/opencode-config and use it 2025-12-17 22:58:41 +00:00
Shantur Rathore
d6fdef68d9 Rename CLI package to @neuralnomads/codenomad and bin codenomad 2025-11-20 23:51:44 +00:00