Commit graph

4 commits

Author SHA1 Message Date
Pascal André
794ac20306
feat(integrations): recognise OpenCode integrations from the reviewed catalog and read their state (#1243)
## Summary

Slice C2 of the OpenCode integrations plan: CodeNomad recognises
configured OpenCode integrations from the reviewed catalog and reads
their state. This is the base for attaching an open application to a
conversation (C4) and for the Bundles extension (C3).

- **Catalog** (`opencode/integrations/catalog.ts`): newest
`catalog-v<n>` release of `NeuralNomadsAI/opencode-integrations` (GitHub
releases API, never "latest"), `catalog.json` asset through the API
origin, 256 KiB / 10 s bounds, zod validation, 30 s shared cache with
conditional list requests, last valid catalog persisted and served as
`stale`, `unavailable` with an empty list otherwise. No catalog release
exists yet: the real repository reads as `unavailable` today (no release
was created).
- **Recognition** (`recognition.ts`): registry package (aliases
resolved), plugin ID or exact `-<plugin>` rule (disabled plugins),
`sources.git` prefix; a source designating two integrations or loaded
under another plugin ID is non-conforming.
- **State route** `GET /api/workspaces/:id/integrations?directory=`
(`status.ts`, `integrations.ts`, `routes/integrations.ts`): absent /
inactive / failed / unsupported / non-conforming / unknown / ok; fixed
`status` method under the catalog's RPC ID only, 4 in flight, 8 s each;
full output validation, marker mismatch and path-like `appVersion`
refused; ownership rechecked with `assertCurrent` after the calls;
catalog internals never returned.
- **Plugin add** (AC-P7, D18): recognised `native` integrations are
Global-only (`global-only`, 10 locales); registry and Git specs of one
integration are duplicates.
- **UI store** `stores/integrations-store.ts`: demand reads, 300 ms
coalescing of `rpc.neuralnomads.<app>.*`, `plugin.updated`,
`config.updated`, no polling. Mounted by C4.
- Docs: `dev-docs/OPENCODE_INTEGRATIONS.md`, `PLUGIN_CONTROLS.md`; help
`integrations.md` in English and the nine translations.

## Validation

- `node --import tsx --test
packages/server/src/opencode/integrations/catalog.test.ts` (11 pass,
local release server)
- `node --import tsx --test
packages/server/src/opencode/integrations/recognition.test.ts` (8 pass)
- `node --import tsx --test
packages/server/src/server/routes/integrations.test.ts` (4 pass)
- `node --import tsx --test
packages/server/src/opencode/plugin-sources.test.ts` (11 pass)
- `node --import tsx --test
packages/ui/src/stores/integrations-store.test.ts` (4 pass)
- `node --import tsx scripts/test-integrations-recognition-native.mjs
<opencode 2.2.5 cli>`: PASS (added to the runtime matrix)
- Server and UI typecheck; `npm run test:help` pass.

File sizes: `http-server.ts` ~2500 lines (+7), `index.ts` ~790 (+2),
`pr-build.yml` ~770.
2026-11-01 01:47:20 +01:00
Pascal André
66a85afa1c
feat(plugins): add, remove and show the version of any OpenCode plugin (#1232)
## Summary

Status → Plugins can now **add**, **remove** and **show the version** of
any OpenCode plugin (SCR §4.1, slices C1/U1/D1/Q1, AC-P1…AC-P9).

- **Add**: a `+` icon beside Refresh opens a small `.window-*` popover:
package spec (`--surface-field`), scope (Global default; Project shows
the warning), trust sentence. Registry and remote Git specs only.
- **Remove**: each row's menu gets **Remove from Global/Project** for
declarations in that scope's own write target. `id`/`-id` rules stay;
the package cache is never touched.
- **States**: a just-added source shows **Installing** until
`plugin.list` reports its exact target (then an ordinary active/failed
row). After `PLUGIN_SOURCE_PENDING_TIMEOUT_MS` (120 s) it shows **Not
confirmed** with Refresh.
- **Tooltips**: version, **Update available**, failure + native `ref`,
GUI notice when a `features.gui` package is declared outside Global.

## Implementation

- Server: new `opencode/plugin-sources.ts` + `routes/plugin-sources.ts`
(`POST`/`DELETE /api/workspaces/:id/plugin-sources`), built on
`PluginControls.editConfigDocument` (ownership, scope resolution,
deletion fence, connection fence, lock, atomic replace, JSONC/CRLF/BOM,
WSL). Pure helpers in `plugin-source-document.ts` (npm-package-arg
validation, package identity, verified removal). Types in
`plugin-source-types.ts`. `plugin-controls.ts` only gains `pluginId` on
sources and the `gui` passthrough.
- Errors carry a stable `code`: `invalid-spec`, `local-path`,
`plugin-id` (422), `duplicate`, `stale` (409).
- UI: `stores/plugin-sources.ts`, `components/plugin-source-add.tsx`,
`components/plugin-row-actions.tsx` (replaces
`plugin-package-action.tsx`, memoized item descriptors), i18n part file
in the 10 locales, help in 10 languages, `dev-docs/PLUGIN_CONTROLS.md`
rewritten.

## Deviations to note

- `disabled` state for unloaded sources: `plugin.list` omits disabled
plugins and exposes no package→ID link, so an unloaded configured source
is shown as **Not confirmed** ("may be disabled, or installation not
confirmed"). A disabled package with an exact `-id` rule therefore shows
its ID row (switches) and its unconfirmed source row (Remove items).
Documented in `PLUGIN_CONTROLS.md`.
- AC-P7 "a GUI package is added Global-only, Project refused":
`features.gui` is known only once OpenCode has loaded the package, so
pre-install refusal is not possible. This PR keeps Global as default,
warns for Project, and flags a Project-declared GUI package in its
tooltip afterwards. Native-family Global-only enforcement (D18) waits
for the integration catalogue (later slice).

## Tests

- `node --import tsx --test
packages/server/src/opencode/plugin-source-document.test.ts
packages/server/src/opencode/plugin-sources.test.ts` (13 pass)
- Full server suite: 2931 pass, 0 fail (one load-timeout in
`index.test.ts`, passes alone)
- `CODENOMAD_TEST_WSL_PLUGIN_CONTROLS=Ubuntu …
plugin-control-document-wsl.test.ts` (9 pass, incl. new add/remove)
- `node --import tsx scripts/test-plugin-sources-native.mjs <opencode
2.2.5>`: PASS (loopback fake registry, 404 → failed with `ref`); added
to CI runtime contracts
- UI store tests (45 pass), browser
`plugin-sources`/`plugin-controls`/`plugin-packages` (14 pass), `npm run
typecheck`, `npm run test:help` (31 pass)
2026-10-31 18:43:49 +01:00
Pascal André
1dabb5110f
docs(help): bring the user guide back in line with the current app (#1079)
docs(help): bring the user guide back in line with the current app

The help was written on 2026-10-14 and about forty user-visible changes merged since without touching it, so several pages described controls that no longer exist: Missions still listed four playbooks and a Save step for preferences that now save on each change, the depth editor kept its old names, notifications still had their former switches, and voice input pointed to a microphone button that is not in the composer.

Every English page was re-checked claim by claim against the current labels (English UI messages) and behaviour, then the nine translations were updated to match, using each locale's own UI labels. Notable corrections: Missions (Compare two models, autosaving defaults with Apply to / Global / Reset, Subsession nesting depth, prepared hand-offs, retired-task interrupts, the named causes of "Mission Control is unavailable", standalone server support); conversations and history (reasoning/tool durations, token lines adding up the cleanup selection, presets including Nothing, timeline markers following Message content, in-place reveal of long text, Open in session, focus after send, Queue message / Steer now, Retrying); settings (notification routing table and defaults, Stats, Mode, info tips, Server setting badge, localized native menus); shortcuts (72 actions, Clear shortcut, Ctrl/Cmd+K); voice (More actions entries, Save status); files (live Workspace refresh, Show 200 more); OpenCode, install, server and updates (2.1.1 recommended, OpenCode 2 beside an older installation, version card first, private loopback listener for Missions, preview releases offered once all builds are published); providers, integrations, browser, SideCars, desktop and remote pages. Translations also repaired older drift, mainly the project-tab closing passages.

The Chat settings table header (Default state, its title, item column, the thinking row and its accessible label) was still English in eight locales; it is now translated so the help can cite what users see. AGENTS.md now asks every PR changing user-visible behavior to update the affected help pages in the same PR, since CI validates structure and links but not whether the text still matches the UI; it also corrects the needs-input notification default. USER_HELP.md no longer claims native menus stay English.

Validation: npm run test:help (all ten locales, 25 pages, heading ids unchanged), a full help build, and the i18n and transcript-visibility unit tests.
2026-10-21 14:38:29 +02:00
Pascal André
c0d53f13d4
docs(help): multilingual help site with in-app Help menu and palette entry (#859)
## Summary

A complete public CodeNomad help site in the app's ten languages,
published on GitHub Pages (https://neuralnomadsai.github.io/CodeNomad/)
and opened from the app.

- **Content:** 25 pages in 8 sections (Start, Workflows, OpenCode setup,
Remote access, Customize, Extensions, Desktop, Help), written for
OpenCode power users and covering the current version only. It includes
everything user-relevant from `README.md`, `packages/server/README.md`
(server, network, auth, TLS, Remote Control) and the user-facing
dev-docs, with flags, defaults, labels and safety boundaries checked
against source.
- **Languages:** en, fr, de, es, he (RTL), ja, ne, ru, tr, zh-Hans.
Interface labels reuse each locale's own app strings; native desktop
menu names, code, commands, flags, paths and anchors stay unchanged.
- **Site:** `scripts/build-help.mjs` renders
`docs/help/<locale>/<slug>.md` with translated chrome
(`docs/help/i18n/`), stable `{#id}` anchors identical across locales,
same-article language links with hreflang, a root language chooser, and
a first-party offline per-locale search (Ctrl/⌘+K, substring matching
for CJK, Devanagari and Hebrew, hidden without JS). No analytics or
remote resources.
- **Validation:** `npm run test:help` fails on any missing page or
string, heading drift, broken link/anchor/asset or invalid search
target. `.github/workflows/help-pages.yml` validates PRs and deploys
only from `dev`.
- **App entry points:** one `open-help` command for the palette and a
new **CodeNomad Help** item at the top of the Electron and Tauri Help
menus. It opens the help in the invoking window's UI language through
the existing external opener, falls back to the root URL for windows
without the handler, and reports failures without replay.
- Documents the strict boolean environment-variable rule from #959 and
the updater entry points from #960.

## Review

Delivered as a CodeNomad mission with independent review loops, each to
zero findings:
- English content audit (5 passes, 14 fixes) and technical gatekeeper (2
passes) before translation.
- After translation: QA, UX review, and a final multilingual gatekeeper
(35 translation/label findings fixed, then verified), plus a visual fix
for the search focus ring and a verified sync with #960.

## Validation

- `npm run test:help`: 9/9 (25 pages × 10 locales, strict, including
negative tests); `npm run build:help`: 250 pages.
- `node scripts/test-help-browser.mjs`: 44/44; Playwright: 500 page
visits at 390 and 1280 px, all locales, no overflow, no external
requests.
- UI help-command and desktop-updates browser tests 19/19; help URL unit
tests; Electron menu tests; UI and Electron typechecks; Tauri `cargo
test` 272/272.
2026-10-14 22:44:56 +02:00