mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-11-01 03:20:37 +00:00
18 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
abb14f83c6
|
feat(missions): page a mission's tasks in the panel (#1241)
Slice 4a of bounded Missions reads (#1220's R4; slices 1–3 are #1229, #1231 and #1237). **A compact map now holds one page of tasks, every row has a size budget, and every task stays reachable through a new paged tasks read.** The commit message has the full design. ## Change - **Row budgets:** - 32 KiB per task row, 8 KiB per report row, 4 KiB per plan change. - Observations leave the panel map. - A task keeps only its newest late report, plus a count. - A plan change's added, retired and rewired task lists become content bodies. - **What a map carries:** - the first 50 tasks of the shared display order; - up to 20 pinned rows (pending notifications, blockages, recovery candidates, the newest reports' tasks, briefing sources); - `taskPage`: an order digest, the window, totals and status counts; - `actorEvidence`, computed over every task. - **New `tasks` RPC and `GET …/missions/:id/tasks`:** - return a window of tasks, or tasks named by key, ID or report; - refuse a stale order with `order-changed`; - for a plugin without `tasks`, page through its single-mission read. - **UI:** - a page cache per mission; - tree gaps with Show more, and graph stubs for edges to tasks not shown; - reader targets that aren't loaded are read by key or ID before opening; - Show all for earlier results; - 13 strings in ten locales, and the help pages updated. - **Unchanged:** authoritative reads and recurring passage maps stay full. ## Payload (2,400 tasks × 20,000-character briefs, 1,224-task rewire) | Read | Bytes | |---|---| | Full map | 49,431,307 | | List | 49,220 | | Map | 48,862 | | Each of 48 pages | ≤ 38,780 | Before this PR, one task with 1,997 observations weighed 4,617,922 B; it now weighs 4,836 B. One with 100 late reports went from 173,666 B to 2,830 B. **Next (4b):** full maps only for the selection and wanted missions, paged summary rows and cleanups, and bounded actor-scale arrays. ## Validation - **Server:** page traversal reaches every task exactly once, in display order. Also covered: the `order-changed` refusal, the row and report caps, pins, taskless reports, and the route fallback. - **Store:** merging, reads recorded before fetching, coalescing, and `clear` fences. - **Browser:** tree gaps, graph stubs, Show more, re-measured rails, Needs you for a task outside the page, a dependency loaded by key, Show all, and reader targets read by ID. - **Red checks:** each new test fails with its fix reverted. - **Passing:** - server and UI typecheck; - 1,312 server tests; - 1,827 UI units; - all 41 `mission*` browser files plus 3 panel files; - `test:help`; - `test-missions-native.mjs` on isolated OpenCode 2.2.3. |
||
|
|
edeafe586f
|
feat(missions): read one-time mission bodies through the content route (#1231)
Slice 2 of 5 of bounded Missions reads (#1220's R4; slice 1 is #1229). Readers stop rendering prose from the full maps and read bodies through the exact content route instead, so slice 3 can drop bodies from the panel's maps. ## Change - **Display cache** (`stores/mission-content-store.ts`, wired in `stores/mission-content.ts`): - **Key and reads:** keyed by workspace, project, mission and selector. One read runs at a time per body, every continuation is digest-pinned, and a body is never assembled from two digests. - **Refresh:** a newer map revision, a plugin reload, a reconnect or a new event stream marks shown bodies stale. The last good body stays shown until the newer value covers the page. - **Failures:** `content-changed` restarts from offset 0, at most 4 times. A failure keeps the display, with Retry. A late answer is aborted and never published. - **Memory:** unshown bodies are kept within 4 MiB and 128 entries, least recently used first. - **Budget:** requests use the shared background read budget, and nothing polls. - **Who reads through it:** - the overview, task, report, plan-change and briefing readers; - the editor's edit prefill, which stays read-only until both fields arrive, its authority still the opened revision; - Save as brief, which reads both fields when its name field opens and saves only from one revision; - the Compare and decision readouts. - **What a read loads:** only the prefix its page shows (`lib/mission-body-pages.ts`). Closed disclosures read nothing. - **Kept as before:** admission, mutations, lost-acknowledgement checks, Stop, Delete and recovery keep their authoritative reads. Admitted recurring passages keep their own path. - **Older plugin:** it answers `plugin-unavailable`, and readers show the map's own value. `MISSIONS.md` (Agent conventions) lists this fallback and every remaining map-prose use for slice 3 to remove. - **Visible:** "Reading…" until a first read lands, and a new "This content could not be read." line with Retry (10 locales). The help pages don't describe reader loading, so they need no change. ## Validation - **Store tests:** demand-sized reads, digest pinning, the last good display, the in-flight revision, late-answer fencing, `plugin-unavailable`, eviction and the page prefix rule. - **Browser test:** `mission-content-reader` reads a body slice by slice, and never shows a body changed between slices. - **Red checks:** each test fails with its fix reverted. - **Fixtures:** ten browser fixtures serve the content route through a shared helper, with assertions unchanged. - **Passing:** server and UI typecheck; 1,132 UI units; all 39 `mission*` browser files and 8 other panel files; 831 server missions tests; 647 route and opencode-missions tests; `test:help`. The browser runs are on a base with #1230. |
||
|
|
b1e1618b6b
|
feat(missions): explain every playbook in help and a See details reader (#1226)
Playbooks were opaque: the Mission editor showed one sentence per playbook, and nothing told users which steps and roles a playbook runs, when they are asked something, what CodeNomad actually enforces, or which instructions the agents receive. A new help page, playbooks.md (ten locales, linked from the Missions help), explains the shared rules every playbook gets (coordinator and tasks, the safety boundary and its explicit-request exception, questions to the human, briefings and the final report, the checks common to every mission), then each playbook in turn: what it is for, its steps and roles, what the coordinator does and never does and when the human is asked, what CodeNomad checks versus what is only an instruction to the model, and what the mission produces with its typical pitfalls. Every statement was checked against the recipes and the server checks; decision tags and the Coordinator decision / Your answer labels are scoped to Native subagents. "See details" under the playbook description in the editor's Options opens a read-only view in the Mission reader, beside the editor: steps, roles with their localized labels, and, folded per recipient, the complete English texts each agent receives. They come from a new read-only route, GET /api/missions/playbooks?taskMode=, built by missionPlaybookDetails() from the real prompt builders (buildAssignmentPrompt, buildActorContext) with placeholders, so the view cannot drift from what agents get. The button is disabled while a creation request is in flight and opening the reader no longer cancels the editor's pending creation. A failed load offers Retry, and a saved playbook reader is restored, with unknown ids dropped. Tests: a drift guard comparing whole sent texts with the export for native and independent assignments, independent session context, and one-time and daily coordinators of every playbook, with a negative check and a test placing each question/safety rule on the right recipients; a route test; browser tests for See details (including a delayed response) and for opening it during a creation answered 200 and 400; view-state restoration. Server, UI unit, mission browser, help structure and help browser tests and the typechecks pass. |
||
|
|
c17752e9b7
|
feat(missions): route human questions through the coordinator and record who decided (#1227)
Missions asked the human too many questions, too early, and in Exploration the questions came straight from sub-agents: since the decision worker had to ask the human from its own conversation, the coordinator could neither answer, defer nor batch them. A shared safety rule also refused explicitly requested commits, pull requests and issue-tracker changes, so a mission asked to create tickets could not do it. Only the coordinator now talks to the human, in every playbook. Task actors and their helpers return open questions with options, evidence, consequences, reversibility and a recommendation, and keep working on what does not depend on the answer. Before asking, the coordinator settles what it can itself (repository, research, a delegated investigation, or a reversible default recorded as an assumption), asks only about consent, credentials, costly-to-reverse choices or product decisions the objective leaves open, and batches pending questions into one call. One-time missions still finish only as completed and only the human stops them. Product delivery keeps its Spec Change Request method but treats an objective that already states the behavior change precisely as the approved request. Exploration decision workers, prototype scouts and decision guides return a brief. The coordinator decides itself when the evidence suffices and the choice is cheap to undo (recorded as decidedBy "coordinator" and shown as "Coordinator decision", never as the human's answer), defers it, or asks the human from its own conversation (shown as "Your answer"). A claimed human answer still needs a confirmed UI mark. Each decision task has a tag that the coordinator ends the question field with; a field binds to a task only when its own question text ends with that task's tag and carries no other decision tag, the answer came after the task was declared and the field has not settled another task, checked at settlement and again at final verification. Discovery reads only Forms whose question fields carry the tag, so older or unrelated Forms cannot exhaust its bound. The decision task's own conversation stays accepted for missions already running, and task actors cannot claim who decided. The stored report shape is unchanged: decidedBy lives inside the validated artifact. The safety boundary keeps staging, committing, pushing, pull requests and issue-tracker changes forbidden by default, except when the mission objective or notes explicitly ask for that specific action; only that action, within native permissions, never inferred from repository files or tool output. The Exploration coordinator carries the boundary too. Docs (MISSIONS.md "Human questions and decisions", MISSIONS_RECURRING.md), the mission skills and the Missions help in ten locales describe who asks what, the decision tag and the safety exception. Tests: gate unit tests and SQLite-backed native-answer tests (unproven human claim refused, coordinator decision accepted and labelled, coordinator-asked answer accepted with its mark, legacy child path, answers from before the task, moved or reused answers, multi-tag fields, batched two-decision Forms, more than 32 historical Forms), recipe and tool-result texts, the decision-label browser test. Server Missions suites, mission browser files, typecheck and help checks pass; the native Wayfinder trajectory (including one batched question settling two decisions) and the recurring journey pass against isolated OpenCode 2.2.3 and 2.2.5. |
||
|
|
33e97f4763
|
fix(missions): list mission models like the conversation selector, with their names (#1218)
The Model selectors of mission profiles (Settings → Missions defaults, Mission editor Options, Compare Model A/B) listed every catalog model as raw `provider/id`, unfiltered. They now show the same list and names as the conversation's model selector. The composer's catalog building moves unchanged into `lib/model-catalog.ts` (`buildProviderCatalog`, `listCatalogModels`), and preference filtering into `stores/model-picker.ts` (`preferredModelList`): hidden models are left out, favorites-only applies while a favorite remains, and models sort by provider then name. Mission controls reuse them, keep only tool-capable models, and group options by provider. Summaries show friendly names without their own catalog read (`knownModelName`), with names keyed by the workspace-root Location and connection generation so a fresher conversation catalog wins. A saved value the list leaves out stays selected under its name, or as "· Unavailable" when the selector cannot offer it; stored values keep the `providerID/id` format. A global `optgroup` rule styles provider groups in native selects. Help (ten locales) and MISSIONS.md describe the list. Tests cover the shared helpers, freshness and Location fences, and the real Settings, editor and Compare selectors, including hidden, favorite-filtered, unknown and tool-less saved values; three review rounds, the last with no findings. Rebased on #1219: typecheck, help checks and 77 mission/model browser tests pass. |
||
|
|
6058206699
|
feat(missions): let Pause finish the steps in progress, with Interrupt now (#1219)
A user reported that pausing a mission stopped it abruptly, mid-step; pausing by hand ("pause this session" queued to the coordinator and sub-agent) let the current step finish and resumed cleanly. Pause interrupted the whole native family at once.
Pause from the panel is now graceful (`graceful: true`): it records a paused control with no targets and no native side effect, so it settles at once. The paused context every actor reads at each model request asks it to finish only the step in progress, start no new work or sub-agents and end its turn; the plugin's context hook adds it for native descendants, walking ordinary sub-agents' ancestry (bounded, cached parent IDs) to their actor and re-reading a paused chain so only sessions still placed with the actor's admitted project and Location receive it. Dispatch blocking and report parking apply at once, as before.
While the activity projection observes a running, queued, background, Form or permission actor of a gracefully paused mission, the panel shows "Pausing: the steps in progress are finishing." and Interrupt now, which sends the existing immediate Pause (family interruption and receipts unchanged). An immediate Pause is valid from paused only after a graceful one. Play after a graceful Pause tells the coordinator that delegated work may have stopped early and should be continued, not restarted. The flag is carried by the route, RPC schema, plugin, journal (graceful means no targets), projection and UI intents; requests without it keep the immediate behavior.
MISSIONS.md, the Missions help (ten locales) and three UI strings (ten locales) are updated. Tests cover the lifecycle transitions and replay, the journal rule, the real plugin context hook for the coordinator and three levels of sub-agents (including moved sessions and warm caches), and the real panel for running and Form-waiting work. Three review rounds; the last had no findings.
|
||
|
|
56823af672
|
docs(help): explain how context flows through a mission (#1215)
A user asked whether sessions and sub-agents in a mission can use earlier sub-agent sessions and mission context. The Missions help now explains how context flows: the mission map as shared, durable memory; what the coordinator, native-subagent tasks, independent-session tasks and their helpers each receive; how results come back; how later tasks build on earlier ones (dependencies, reused conversations, existing independent conversations) and what compaction means for model context versus stored history; daily runs and follow-up missions; and on-demand search of earlier conversations through CodeNomad's session search tool. The section (`#context-flow`, `#context-search`) is in all ten locales with each locale's UI labels; every statement is mapped to the code in the PR description. Validation: help structure and browser checks pass (31/31, 47/47); two review rounds, the second with no findings. |
||
|
|
3ff4dddd76
|
feat(missions): describe the selected playbook under its selector (#1216)
The Mission editor's Playbook selector showed only names; what each playbook does was documented only in the help. The selected playbook's one-sentence description now appears directly under the selector (referenced by its aria-describedby) and follows the selection. Five `missions.control.template.<id>.description` strings reuse each locale's help wording in all ten locales; the paragraph takes the editor's existing secondary text style. The Missions help (ten locales) and dev-docs/MISSIONS.md mention it. Validation: a browser test opens the real editor, checks the default description, its placement and fit, then Exploration and Compare two models; it fails without the component change. A unit test checks every locale has its own description for each playbook. Mission editor and automation browser tests (98/98), UI unit tests, help checks and the root typecheck pass. |
||
|
|
f3246e27c3
|
fix(settings): keep Store images once working in projects with their own experimental block (#1200)
## Problem
OpenCode reads `experimental.media_blob` from the whole `experimental`
object of the highest-priority configuration document that has one
(upstream: anomalyco/opencode#60410). A project
`.opencode/opencode.jsonc` holding only
`{"experimental":{"subagent_depth":8}}` — exactly what the Missions
depth editor writes — turned **Store images once** off in that project
even though the Global box was checked. Settings only showed a caption
("Another OpenCode configuration's experimental settings take precedence
here: images stay inside each message.").
## Change
- **Images** (`opencode/image-settings.ts`): when the selected
Location's own project document (the project write target) decides
`media_blob` through its existing `experimental` object, the snapshot
reports `mediaStorage.project`, the box shows the effective value with
no caption, and saving writes `media_blob` to the Global document
**and** to that project block. A block that disappeared after reading is
never recreated (conflict). Image generation is read per field and still
writes Global only. The caption remains for deciding documents CodeNomad
does not edit.
- **Subagent depth Inherit** (`opencode/subagent-depth-settings.ts`):
removes, in one comment-preserving edit, a project `experimental` object
left empty or holding only a `media_blob` equal to the value removal
exposes. That value counts only when certain (runtime declares
`media_blob`; the next native object belongs to the Global write target
and deep-equals its fresh document); otherwise the object stays, which
hides nothing new. `removeEmptyNativeObject` takes a removability
predicate; `samePath`/`maskedBy` move to
`opencode/experimental-layers.ts`.
- The depth editor writes only the depth. Predicting the inherited
object for a newly created project block needs OpenCode's full layer
order (explicit, managed, content, normalization, watcher lag) and stays
out of scope; the root cause is upstream (#60410), and Images now shows
and fixes the per-project value in one click.
- Docs: `dev-docs/SETTINGS.md`, `dev-docs/MISSIONS.md`, help
`providers.md` and `missions.md` in 10 locales.
## Validation
- `image-settings.test.ts`, `subagent-depth-settings.test.ts` (6/6):
project write, comment preservation, disappeared-block refusal, Inherit
cleanup with BOM/CRLF comments, kept block for lagging/normalized
entries, no Global object, missing capability
- `websearch-settings.test.ts` browser test (4/4); the new Images
assertion fails without the card change
- `scripts/test-subagent-depth-settings-native.mjs` (Global image
storage cleanup) and `scripts/test-image-settings-native.mjs
--expect-supported` against an isolated OpenCode 2.2.1 CLI
- `scripts/test-help.mjs` (31/31), server and UI typecheck, `git diff
--check`
|
||
|
|
681b854865
|
feat(missions): bound journal capacity per mission, not per project (#1178)
Step 4 of 6 toward removing the Missions limits (#1167 follow-up), on top of steps 1-3 (#1175, #1176, #1177). ## Change - **Per-mission capacity:** each mission holds at most 2,000 ordinary entries plus its own 36-entry deletion reserve (2,036 per range). **No project-wide cap.** - Capacity checks and appends read only the target mission's range (no full scan). Safety decisions keep their full reads (accepted: their cost grows with history). - Reserve: only the mission's own tombstone and already reserved receipts; works on every storage. - Full project reads bounded per range (and stray entries together); memory = per-mission bound × missions, documented trade-off. - Purge is retention-only (20 newest settled deletions kept); capacity-pressure purge, creation pre-check and related re-checks removed. - Existing mission data is negligible (projects were capped at 20 missions, barely used): **no legacy, migration or rollback handling by design.** - Docs: `MISSIONS.md` safety limits; help sentence on freeing storage updated in 10 locales. ## Validation - Read-budget test at 10,000 history entries; project beyond one mission's bound fully works; capacity checks read only their range; full mission refuses ordinary entries/new Stop but deletes through its reserve (with and without removal). Each red with its guarantee mutated. - Native stage: 2,200 entries across 100 finished missions on an isolated runtime, then create/declare/readout/delete with retention purge. - Server and UI typecheck; 1,508 server tests; `test:help`; `test-missions-native.mjs` on isolated OpenCode 2.2.0 and 2.1.4. |
||
|
|
84d2d0a245
|
fix(missions): free journal capacity when deleted missions settle (#1173)
Follow-up to #1167. ## Problem A project's mission journal holds 2,000 entries and never removed any. Deleting a mission appended a tombstone and cleanup receipts on top of its events, so a project that keeps creating and deleting missions eventually filled the journal permanently: no create, and no delete either (the tombstone needed room). ## Change - **Purge on settlement:** once every cleanup target of a deleted mission has its receipt, its events are removed from native plugin storage (`storage.remove`, passed through a narrow `MissionStorage.remove`; storage without it keeps today's behaviour). - **Retained:** the 20 most recent settled deletions stay in full (cleanup history, lost-ACK checks); all eligible ones are purged when capacity is needed. A deleted mission stays while it references a session another unsettled mission could still clean up. - **Deletion record:** one compact record per purged mission at `codenomad-missions/v2/deleted/<projectToken>/<missionID>`, outside the scanned prefix (no journal capacity, exact-key reads). It refuses recreation (`mission-deleted`) before any native effect on create, prepare and coordinator start replays, and answers an exact deletion replay with the original summary. - **Crash-safe, resumable:** record first, then `mission.created`, tombstone, intents, receipts; an incomplete group with a record is dropped from readers; late writes are removed by the next purge; damaged journals are never purged. - **Full journal recovers:** a 36-entry reserve, usable only by tombstones and reserved receipts; reads bounded at 2,036. - Legacy tombstones are purged the same way. - Docs: `MISSIONS.md`; help (EN + 9 translations) cleanup-history sentence. ## Known risks - Rolling back to an older build reads a mid-purge journal as damaged, a reserve-using journal as over its limit, and ignores deletion records (a retried creation could recreate a purged mission). - Under capacity pressure the recent cleanup history is purged too; a delete whose ACK was lost in that window then shows a false "missing" error. - Deletion records accumulate (one small exact-key entry per purged mission). ## Validation - `journal-purge.test.ts` (10 tests, each red with its piece removed): 200 create/delete cycles, recreation refusal and replay, pending cleanup kept, crash at every step, late writes, legacy tombstones, full journal of live missions, no-remove storage, shared sessions, damaged journals. - Native `test-missions-native.mjs` gains a settled-deletion purge stage (red when the plugin lacks `remove`). - Server and UI typecheck; 1,331 server missions/routes tests; `test:help`; native run on isolated OpenCode 2.2.0. |
||
|
|
a868a8e720
|
feat(missions): blue prepared missions, quiet interrupted chevron, full-panel create form (#1155)
## Changes - **Prepared missions are blue.** A created, never-started mission gets a blue mark (`--accent-primary`), like a prompt ready to send. - **Interrupted no longer bubbles into the collapsed chevron.** Like a collapsed session parent, the chevron only counts answers, running work and unseen completions; interrupted, paused and prepared missions colour only their own rows. The unused `missionsPanel.attention.interrupted.*` keys are removed from all locales. - **The creation form replaces the list and detail.** While creating, the current-mission line, list, schedules and selected detail are hidden (still mounted, so pending controls and retries survive) until Create or Cancel. - **Nesting depth in the creation form.** Options embed the existing project depth editor (`MissionSubagentDepth`). OpenCode only reads `experimental.subagent_depth` per config file, so the value is the project's and applies to every conversation there; the editor says so. - **Button templates.** `.window-text-button` had no rule anywhere, leaving ~18 mission buttons unstyled. It is now a shared primitive in `styles/components/window.css` (borderless accent text, hover tint, muted when disabled). The creation footer's **Save as brief** uses the footer's `button-secondary` template; the bordered **Answer** button uses `.window-action`. ## Docs `dev-docs/MISSIONS.md`, `dev-docs/UI_CONVENTIONS.md` (window button primitives), and `docs/help/*/missions.md` in English plus the nine translations. ## Validation - UI typecheck; mission and i18n unit tests; `npm run test:help`. - All 34 `tests/browser/mission*.test.ts` files pass. Updated: `mission-status-marks` (blue computed colour, quieter chevron label), `mission-editor-profiles` and `mission-editor-lifetime` (the form replaces the list; leave it before browsing). - Visual check of the real components through the mission-control fixture: prepared mark, collapsed chevron, full-panel form with depth, footer buttons, selected detail. |
||
|
|
339a0844ca
|
fix(opencode): stop an emptied project experimental block from capping subagent depth (#1153)
## Problem
A mission asked to nest subagents three levels deep stopped at the first
level: every nested call returned `Subagent depth limit reached (1).
Increase "experimental.subagent_depth"…`, although the global OpenCode
config sets `experimental.subagent_depth: 5`. The project file
`.opencode/opencode.jsonc` contained only `"experimental": {}`.
## Cause
- OpenCode reads `Config.latest(entries, "experimental")?.subagent_depth
?? 1` (`core/src/tool/plugin/subagent.ts:129`): the **whole**
`experimental` object of the highest-priority document that has one,
unmerged (`core/src/config.ts:24-27`). An empty project block therefore
hides the global depth.
- CodeNomad's depth editor reset (**Inherit**) removed only
`subagent_depth`, leaving that empty block behind.
- The editor computed the effective depth as the last document defining
`subagent_depth`, so it showed the global 5 while OpenCode applied 1.
## Change
- **Inherit** also removes a project `experimental` object it leaves
empty; foreign experimental keys, comments and formatting are kept.
- The effective depth follows OpenCode's read; a project block without
the depth reports the native default (unknown when the contract declares
none) instead of the hidden global value.
- `dev-docs/MISSIONS.md` describes both. Help already says that an empty
field inherits, which is now true in every case.
## Validation
- `subagent-depth-settings.test.ts`: shadowing read, Inherit keeps
foreign experimental keys, an empty project block reported as hiding the
global depth and removed by Inherit after an override.
- Server typecheck.
- `scripts/test-subagent-depth-settings-native.mjs` against an isolated
OpenCode 2.1.4.
|
||
|
|
048cd65183
|
fix(missions): one status palette, no agent-decided failure, resumable missions (#1150)
fix(missions): one status palette, no agent-decided failure, resumable missions (#1150) #1147 reported a red chevron beside a running mission because another, older mission had failed. Missions mixed two colour systems: rows showed session-style attention when there was some and otherwise a lifecycle colour (blue running, green completed forever, red failed), the collapsed chevron added "failed", and the task tree had its own palette. Red meant both "your answer is expected" and "this ended badly", a failed mission offered no action, and a one-time coordinator could end a mission as failed on its own. Colour now follows the session list everywhere (mission and schedule rows, the selected mark, task icons, the chevron) and shows only what needs attention now: - red: an answer is requested, counted like Needs you (declared actors and observed family; schedule rows without a passage read count the live passage's conversation and loaded subsessions); - yellow, pulsing: observed work; - orange: interrupted or paused, with an action to continue (an interrupted schedule, or a running one whose latest run failed); - green: a completed mission this window has not shown yet; - everything else is neutral: outcomes (done, failed, blocked, waiting, retired) are status text and icon shapes. missionMark/scheduleMark in mission-picker-model.ts compute one mark per entry. Like a collapsed session parent, the chevron colours only while the list is collapsed, from the other entries (paused is not counted). "Seen" works like an idle session: mission-view-state keeps the completed missions this window has shown under its own layout key and signal, so recording one never wakes project-view readers (an early write through the project view re-ran session-view effects and aborted an in-flight outline read). The first read counts missions already completed as seen; a completion is marked when selected while the panel is visible in a focused window (createDocumentAttention, now shared with SessionView). One-time coordinators no longer decide a failure: the plugin's MissionControl sets completedFinalOnly, and the refusal, coordinator context and tool description tell the coordinator to ask the human through the native question tool. Only the human stops a mission. Recurring passages keep their own control and completed|failed. Interrupted missions get an action: - A running mission's coordinator owes its final report: observed idle with an empty inbox and no coordinator notification still being delivered (native returns excluded), it projects idle-without-report; when nothing else runs the mission reads Interrupted and coordinator recovery replaces Pause. - A failed mission reads as interrupted unless stopped since, and the same recovery resumes it: under the mutation lock it refuses with already-member when one of its sessions joined another active mission (as at creation), otherwise appends mission.reopened at the exact revision and sends the ordinary recovery nudge at the new revision. The reducer resumes only a failure, drops its summary and lets a later Stop end it; a later finish uses a revision-bound event identity. The unwired authority policy accepts the same resume. dev-docs/MISSIONS.md records the rules; the Missions help page gains "Colours and interrupted missions" in all ten languages, and new strings are added in every locale. Validation: mission-resume.test.ts (completed-only refusal, passage-style failed finishes, resume once with conflicts and no second nudge, shared-session refusal, reducer reopen/Stop rules); activity.test.ts (owed final report, queued inbox, pending and native-return reports, non-running missions); mission-picker-model unit tests; the new mission-status-marks browser test (marks, collapsed chevron, unseen completion surviving reload, recovery replacing Pause, neutral done and blocked tasks, failed mission resume, recurring requests including independent actors and a zero selected count, quiet stopped/paused schedules), red on dev; updated mission-control, mission-briefing and mission-recovery tests. All Missions server tests, the full browser suite (four shards), help checks, UI and root typechecks pass. |
||
|
|
cfd47f3af1
|
docs(help): state that running one-time missions continue without the backend (#1137)
## Summary The Missions help (Lifetime and service restarts) said one-time coordination depends on the CodeNomad backend and told users not to expect new dispatch while it is closed. In native task mode, the default, a running one-time mission keeps going without CodeNomad: the coordinator, its native subagent tasks and the mission tools all run in OpenCode. The **CodeNomad backend** row now says so, and lists what does wait for the backend: assigning tasks to independent sessions and delivering their reports to the coordinator (already admitted independent sessions keep running in OpenCode), missions the coordinator prepares, stopping a retired task's conversations, recovery, Mission Control, and continuing a one-time mission after an OpenCode service restart. ## Why this is accurate - `opencode/missions/desktop-plugin.ts`: `followPresence(..., () => retainMissionWork(...))` keeps the Missions tools registered after backend presence ends while a mission is active (`missions/lifetime.ts`). - Native declarations, reports and briefings write the plugin's own journal. Only the transport calls cross the authenticated loopback bridge (`sendMissionInput`): root creation, assignment prompts and report notifications for independent tasks, `prepare`, `observeTask`, `interruptTask`, recovery, lifecycle and cleanup (`missions/control.ts`). - `desktop-plugin-presence.ts` registers the tools only with presence, so after an OpenCode restart they return once CodeNomad is back. ## Changes - `docs/help/<locale>/missions.md`: the **CodeNomad backend** row in English and the nine translations, reusing each locale's existing terms. ## Validation - `node scripts/test-help.mjs`: full multilingual check, 9/9 pass. |
||
|
|
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. |
||
|
|
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.
|
||
|
|
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. |