Commit Graph
263 Commits
Author SHA1 Message Date
Ryder Sun 5054553a16 fix: the agent avatars no longer draw over the composer's @ menu
In a group chat the strip of member avatars above the composer (the run
status for the latest topic) was painted on top of the @ menu, covering its
'Agents' heading and the first rows.

The avatars overlap each other and order themselves with z-index 100, 99, 98
and so on. Nothing around them created a stacking context, so those numbers
competed with the page directly and beat the menu (z-index 4). The strip is
now its own stacking context, so the ordering only applies between the
avatars. The composer box gets the same treatment for the member chips (z-index
1-6): they were only contained while the box was focused, because the box's
focus transform happened to create a context.

Checked in a real renderer (headless Electron, the built frontend with a stub
bridge, a six-member group with a finished run and with a running run, composer
focused and not): the points of the menu covered by something else go from 36
to 0 in both states. jsdom has no layout, so composerStacking.spec.js pins the
CSS that keeps the numbers contained; two of its three cases fail without the
fix.

Checked with: npm --prefix frontend test (336 pass), build:desktop.
2026-10-16 16:02:48 +08:00
Ryder Sun e1500a73ef fix: conversations no longer wait for each other, even in the same folder
Sending to an Agent while the same Agent (or any Agent) was busy in another
conversation made the new conversation sit on 'Running' until the first one
finished. The cause was the writer lease, which was keyed by the real folder:
every writable conversation that used the same folder (and most keep the
default one) took turns, one at a time, across groups and direct chats.

9198bf6 had deliberately scoped the lease of direct chats to the chat so that
one writable chat could not block another Agent. 17cbd32 reverted that as a
regression and added a 'waiting for another Agent writing in the same folder'
notice. That was the wrong call: it made the product behave like a single
queue. This commit reverts 17cbd32 and goes one step further than 9198bf6:

- the writer lease is scoped to the conversation for groups as well as direct
  chats, so conversations never wait for each other; writers inside one
  conversation still take turns
- the waiting notice, the waitingForWorkspaceKinds snapshot field and the
  scheduler queue callbacks that only existed for the folder lock are removed
  with the revert
- the old rule 'group chats serialize writes across symlink aliases' is
  replaced by its opposite; new tests cover the same Agent in two direct chats
  and a group at once, group chats sharing a folder through a symlink alias,
  and that turns of one conversation share a lease scope while another
  conversation in the same folder does not
- architecture.md states the new rule and the trade-off

Trade-off: two Agents in different conversations can now edit the same files
at the same time, like two terminals in one directory. Output capture compares
.meldwork-output/ before and after a run, so when two conversations produce
deliverables in the same folder at the same time one may attach a file the
other wrote. No guard was added for that.

The new write-scheduling tests fail on the previous commit (two fail, one
never gets its second Agent started).

Checked with: local-workspace-write-scheduling (6 pass), run-scheduler,
run-coordinator, state, harness, npm --prefix frontend test (333 pass).
2026-10-16 15:10:35 +08:00
Ryder Sun 4a0915594f test: pin that unsupported ACP client requests get an error, never a success
fs/* and terminal/* requests from an Agent that never was offered those
capabilities, and unknown methods, must each receive an error response. The
behaviour held partly through parameter validation; the test now states the
contract (no result field, numeric error code, unknown methods get -32601).
2026-10-16 11:55:16 +08:00
Ryder Sun 5641969445 fix: switching between read-only and write no longer restarts the ACP process
The ACP runtime was identified by a signature that included the session mode
(plan/build for MiMo and OpenCode, default/accept_edits for Hermes). Group
discussions alternate between a read-only proposal and a write-enabled turn, so
the signature changed, the process was closed and the stored native session was
reported invalid, losing the conversation's context on every switch.

The mode is applied on every turn with session/set_mode, so it does not
identify a process. What genuinely needs another process (Hermes' and
OpenCode's permission policy is passed through the environment) is already part
of the signature through the environment, so those still start separately.
MiMo, whose arguments and environment are identical in both modes, now keeps
one process and one session across a read-only turn, a write turn and another
read-only turn.

The new test fails on the previous commit with LOCAL_AGENT_SESSION_INVALID.

Checked with: cli-native-acp-lifecycle (16 pass).
2026-10-16 11:51:00 +08:00
Ryder Sun 4b8ddd917f docs: describe the module layout and reliability rules, and fix dead links
architecture.md pointed at docs/flows.md, permissions.md, variables.md and
automation.md, which exist on no branch, and at three more that exist only on
main (this branch keeps /docs/ untracked). The related-documents list now
links only files tracked in the repository.

Adds a Code Map (what each invocation, prompt and auto-runner module owns and
where new behaviour should go) and the Reliability Rules the harness now
enforces, so the next change starts from the layout instead of the 6000-line
class.
2026-10-16 11:43:34 +08:00
Ryder Sun 0e4f1620e6 refactor: split the 6000-line auto-runner into files grouped by what they do
LocalWorkspaceAutoRunner was one class of 6000 lines. Its 99 largest methods now
live in eleven files named for their topic (recovery, collaboration,
natural-discussion, v4-context, v4-delivery, v4-synthesis, v4-results,
v4-phase, v4-discussion, task-graph, rounds) and are assembled onto the same
prototype the way the existing natural-decisions and v4-outcomes parts already
were. local-workspace-auto-runner.cjs keeps the constructor, start/resume and
run-level helpers (285 lines); the largest remaining file is 965 lines.

This is a move, not a rewrite. The split was generated by a script that copies
method source verbatim, and checked three ways before the tests ran:
- all 135 prototype methods exist with the same name and an identical source
  hash before and after (only the class constructor text differs, because the
  mixins are listed after it)
- a scope analysis finds no identifier that is read but not declared or
  imported in any of the 15 auto-runner files
- node --check on every file

The V2 round and V3 task-graph runs, which only exist to resume older runs,
are in their own files so they can be deleted together when that support ends.

Checked with: npm --prefix desktop run test:workspace (627 pass).
2026-10-16 11:43:34 +08:00
Ryder Sun 958d18152b fix: MiMo/OpenCode turns with tool calls are no longer cut short, and a CLI's own error is no longer masked by EPIPE
Two ways a CLI run ended early or with the wrong reason:

- MiMo and OpenCode print a step_finish after every model step. A step that
  ends with reason tool-calls is followed by more steps, but the transport
  terminated the process 250 ms after the first step_finish, so every turn
  that used tools came back as a partial answer. Only a final step now ends
  the run.
- Codex reads its prompt from stdin. A CLI that exits at once (expired
  sign-in, rejected flag) while a prompt larger than the pipe buffer is still
  being written produces EPIPE, which was reported as LOCAL_AGENT_SEND_FAILED
  instead of the CLI's own message. A closed pipe now waits for the process to
  finish and reports its stderr (so a sign-in failure is recognised as one);
  a process that stays alive without reading is still a send failure after
  5 seconds.

Both regressions fail on the previous commit.

Checked with: cli-adapters (74 pass incl. cli-process-support).
2026-10-16 11:29:28 +08:00
Ryder Sun bf49afcd92 feat: a member that is not ready no longer blocks messages to the whole group
Sending to everyone in a group failed with 'this local Agent is unavailable'
as soon as one member was not ready, so one broken CLI made the whole group
unusable. When the recipients are implicit (everyone, or auto discussion),
members that are not ready are now left out and the user is told which ones
were skipped. Agents the user picked or @mentioned explicitly are kept so the
send can still report them, and when nobody is ready the full list is kept so
the problem is not hidden.

Checked with: composerContext spec (3 new cases), npm --prefix frontend test
(333 pass).
2026-10-16 11:21:36 +08:00
Ryder Sun 49ed8aee0f fix: an Agent stays available through an inconclusive probe, and keeps its shell environment
Two ways a healthy Agent used to drop out of use without anything being wrong
with it:

- readiness: OpenClaw's 7 second status check, or any probe that crashes,
  marked the Agent unavailable at once, so it vanished from the picker until
  the next successful probe. A timeout is not a 'not signed in' answer. An
  Agent that was available now stays available through inconclusive results
  for up to 10 minutes; a definitive answer (signed out, incompatible version,
  a recorded auth failure) still applies immediately, and an Agent that was
  never available is not made available by it.
- login shell: when the shell used to capture PATH and API keys did not answer
  (slow rc file, cold boot), the bare app environment was used and cached for
  30 seconds, so Agents started without the user's PATH or keys and failed
  with sign-in errors. The last environment the shell produced is kept and
  reused; the timeout is 10 seconds; with no earlier success the failure is
  cached for 5 seconds instead of 30, measured from when the capture ends.

Both new tests fail on the previous commit.

Checked with: local-workspace-agent-catalog (22 pass), local-agent-readiness
(39), cli-network-environment, main-security (51).
2026-10-16 11:21:36 +08:00
Ryder Sun 462c1bd783 fix: an ACP turn no longer dies on traffic this client does not know
The ACP transport failed the whole turn on anything it did not recognise: a
banner line on stdout, a notification with an unknown method, a session update
kind added by a newer Agent, or an unknown request. Every Agent upgrade that
adds a message therefore broke Meldwork until it was updated, and a single
large tool result (over 1 MiB on one line) failed the turn.

- stdout lines that are not JSON objects are ignored
- unknown notifications and session updates that fail validation are dropped
  before they reach the SDK, which logs rejected messages with their params
- unknown requests are forwarded with their params stripped, so the Agent gets
  a proper 'method not found' answer instead of waiting, and nothing
  secret-bearing is logged
- the per-line limit is 4 MiB (still bounded; total input and reply limits are
  unchanged)
- truncated JSON that starts like a message, an invalid response payload and
  invalid permission requests still fail closed

The Kimi 'unsafe protocol input' test described the old behaviour; it now
checks that malformed JSON still fails closed and that unknown traffic carrying
a secret neither fails the turn nor reaches a log. The new tolerance test
fails on the previous commit (LOCAL_AGENT_PROCESS_FAILED).

Checked with: cli-adapters-agent-protocols (69 pass), cli-native-acp-lifecycle
(15), cli-acp-tolerance, cli-adapters (64).
2026-10-16 11:21:36 +08:00
Ryder Sun a97afa9b5b feat: deliver attachments and knowledge bases to group Agents; one prompt module per mode
Group chats with several Agents run on the V4 path, which never forwarded the
user's attached files to the Agents (the send was validated against what each
Agent can read, then the files were dropped), and its prompts omitted the
knowledge-base hints, the answer language and the deliverable folder contract.

- attachments are now staged for manual group replies and for every turn of
  an automatic discussion; frozen prompts only gain the staged-file section
- manual group replies no longer use the phased 'proposal' template (asking
  for capabilities, work items and a receipt). prompts/manual-reply-prompt
  tells each Agent that everyone answers on their own, whether it may change
  files, and to answer in the user's language
- natural discussion prompts move to prompts/natural-discussion-prompt with
  named sections (brief, writer, owner, routing, receipt), now including the
  group name and topic, knowledge bases, the answer language and, for the
  writer, the .meldwork-output contract
- shared language and delivery contracts live in prompts/prompt-contracts

Also made the hanging-ACP-initialize test independent of spawn counting: under
load the 300 ms timeout killed the first process before it recorded itself, so
the next spawn counted as the first one and hung (16 of 32 stressed runs).

Checked with: new tests for each prompt module and for attachment delivery
(both fail on the previous commit); the V4, context-pack and delivery test
files pass.
2026-10-16 10:49:44 +08:00
Ryder Sun 3ce566f152 refactor: split the invocation's session, outputs, budget, prompt and failure handling into modules
The 1500-line invokeLeased still mixed session bookkeeping, workspace output
capture, budget accounting, prompt assembly and failure classification with
the run lifecycle. Each is now a small module with unit tests:

- InvocationSession: one place that resumes, adopts, discards (rebuilds) and
  completes the native session; the three copies of the 'start a fresh
  session' dance, one of them dead code, are gone
- InvocationOutputs: workspace baseline, media import and outcome descriptors
- invocation-budget: usage recording; a payload without a recorded wire size
  no longer fails the turn
- invocation-prompt: the prompt one Agent receives (frozen, direct, group)
- invocation-failure: why an invocation ended (stopped, timed out,
  interrupted, cancelled, failed) and the hidden error metadata
- permission helpers for resumed decisions moved next to the permission policy

invokeLeased is about 1000 lines shorter and reads as the run lifecycle.
Behaviour is unchanged; focused invocation tests and the new module tests
pass.
2026-10-16 10:21:25 +08:00
Ryder Sun 68145eb319 refactor: extract receipt parsing, watchdog, stream marker filter and permission policy from the invocation
local-workspace-agent-invocation.cjs held four independent pieces of logic
inside one 1500-line method. They now live in small modules with their own
tests, and the invocation only wires them together:

- collaboration/collaboration-receipt.cjs: parse and normalise the receipt
  (unchanged behaviour; the existing receipt tests now import it directly)
- runs/invocation-watchdog.cjs: startup, inactivity and stall windows
- collaboration/answer-marker-filter.cjs: hides control markers while the
  answer streams
- agents/agent-permission-policy.cjs: automatic answers to permission
  requests, read-only turns only approve side-effect-free tools

Two latent defects fixed on the way:
- the watchdog cleared its timer on the first event without re-arming it, so
  an Agent that went silent right after its first event was never stopped
- the marker filter upper-cased the buffer to find markers, which shifts the
  cut position for characters whose upper-case form is longer (e.g. ss)

Checked with: node --test on the new module tests; npm --prefix desktop run
test:workspace (595 pass).
2026-10-16 10:09:38 +08:00
Ryder Sun c3c090f83b fix: write state compactly and durably, and record main-process faults
- The workspace state is rewritten synchronously on the main process for
  every save. It is now compact JSON written through the private atomic
  writer, which fsyncs before renaming (the old path could leave a
  truncated file after a crash). The Run Ledger snapshot is compact too.
- Unhandled rejections and uncaught exceptions in the main process are
  written to a size-capped, secret-redacted meldwork-diagnostics.log in
  userData instead of disappearing, and a renderer that crashes is
  reloaded instead of leaving a blank window.

Checks: run-ledger, local-workspace-state, local-workspace and
main-security tests (185 pass). Full desktop suite: 1540 pass; frontend
web and desktop builds pass (existing large-chunk warning only).
2026-10-15 19:38:33 +08:00
Ryder Sun 26d4be2404 fix: compare installed Agent CLI versions as releases
The installer decided "up to date" and "already installed" with a
substring test, so 11.2.3 counted as 1.2.3 and a newer CLI was offered a
downgrade. It now extracts both versions and compares them as releases
(installed is current when it is the recipe's version or newer), falling
back to the old string match only when a version cannot be parsed.

Checks: agent-installer and the installer facade API test (37 pass,
including a new version comparison test). Full desktop suite: 1540 pass.
2026-10-15 19:38:33 +08:00
Ryder Sun 00ba2d3b38 fix: import only files an Agent wrote, including paths with spaces
28127b3 imports files whose absolute paths appear in a reply, to catch
outputs written outside .meldwork-output. Those candidates skipped the
baseline and start-time checks, so a file the Agent merely mentioned
(the README it read, the user's staged attachment) was imported as an
output, and paths with spaces were cut at the first space.

Reported paths are now imported only when their content changed during
this run and they are outside the .meldwork-input staging folder.
Backticked, quoted and Markdown-linked paths keep their spaces.

Checks: agent-output-importer (11 pass, including a new reported-path
test). Full desktop suite: 1540 pass.
2026-10-15 19:38:33 +08:00
Ryder Sun 17cbd32387 fix: keep one writer per folder and show when an Agent waits for it
9198bf6 gave every direct chat its own scheduler key so that one writable
chat would not block another. That broke the one-writer-per-folder rule:
two Agents could edit the same files at once, and a direct chat and a
group could write the same folder concurrently. The underlying problem
was that a writer waiting for the folder lease showed nothing and looked
like a dead Agent (no queued event, no watchdog, no output).

- Scheduler requests report onQueued/onGranted when they actually wait.
- Direct chats use the real-folder key again; while an Agent waits for
  the folder, the run lists it in waitingForWorkspaceKinds and the run
  status card says it is waiting for another Agent writing in the same
  folder (zh/en). A stopped wait clears the mark.

Checks: run-scheduler (new queue notice test), write-scheduling (the
concurrent-direct-chat test now asserts the second writer waits, is shown
as waiting, then runs), run-coordinator public run keys. Full desktop
suite: 1537 of 1538 before adding the new public key to that list, which
now passes; npm --prefix frontend test (330).
2026-10-15 19:17:03 +08:00
Ryder Sun 8d8f9e65f6 fix: let discussion peers see workspace file paths instead of [path]
Peer transcripts in natural discussions replaced every token that starts
with "/" by [path]. Agents working on the same repository could not tell
each other which file they changed, and API routes such as /api/users or
commands such as /login were erased too.

Natural discussion transcripts now show files inside the shared
workspace as workspace-relative paths, keep non-filesystem tokens, and
still redact other absolute local paths (/Users, /tmp, ...) and secrets.
Phased-V4 delivery text keeps the previous redaction because its hashes
take part in resume checks.

Checks: collaboration-records (new peer path test), natural discussion
(new end-to-end relative path test), natural transcript and delivery
suites. Full desktop suite: 1537 pass.
2026-10-15 19:04:42 +08:00
Ryder Sun b2249f0859 fix: stop skipping every WorkBuddy permission check in write mode
28127b3 added --dangerously-skip-permissions next to acceptEdits when a
conversation allows workspace writes. That flag lets the CLI run any
command and write anywhere on the machine without confirmation, which
goes beyond Meldwork's opt-in workspace-write boundary and differs from
every other Agent. Write mode now relies on acceptEdits, which accepts
file edits in the working directory.

The local machine has no CodeBuddy CLI, so an edit-only tool allowlist
was not added; an unverified flag could break every WorkBuddy turn.

Checks: new cli-adapters test for WorkBuddy write/read-only arguments;
WorkBuddy adapter and protocol tests (7 pass). Full desktop suite: 1537.
2026-10-15 19:04:42 +08:00
Ryder Sun 6e0becfb70 fix: refuse unsafe ACP permission requests during read-only turns
Local invocations answer ACP permission prompts automatically. The
handler picked the "allow" option for every request, ignoring whether the
turn was read-only, so a read-only discussion participant (for example
Hermes running with command approval prompts) had edit, delete, move,
command execution and mode-switch requests approved.

Read-only turns now approve only side-effect-free tool kinds (read,
search, fetch, think) and refuse everything else, including requests
without a recognised kind. Writable turns and the explicit Human Gate
mode are unchanged.

Checks: new local-workspace-permission-policy tests (read-only refusal
matrix, writable approval). Full desktop suite: 1537 pass.
2026-10-15 19:04:42 +08:00
Ryder Sun 6c0f773d3f fix: ask discussion Agents to engage with each other and stop nudging them to stop
The natural discussion prompt told the owner "another reviewer is
optional", told every Agent it "may finish with nextKinds: []", and showed
a receipt example with empty nextKinds and deliverables. Proposals were
told to "engage with peers" although they run independently; sequential
discussions advertised routing that the code ignores; and the response
scope pointed at an "authoritative" label that natural prompts never
show. Agents therefore rarely requested each other and discussions
collapsed into one owner turn.

- Proposals: say peers answer independently and will be discussed next
  round. Discussion turns: respond to peers' specific points, dispute
  with reasons, build on their work; end every turn with the receipt.
- Owner: before completing, make sure the relevant peers reviewed the
  actual deliverables, otherwise request them with a concrete question.
- Peers: answer the points raised; blocked or needs-human goes to the
  owner, who decides.
- Routing: list every peer whose input is needed and ask them a concrete
  question; the receipt example names a real peer and shows the completed
  form with deliverables.
- Sequential discussions no longer advertise routing and instead say the
  next participant runs after this invocation ends.
- The response scope refers to "the current user task stated above".

Checks: local-workspace natural discussion, natural writer, delivery,
transcript, context-pack and harness suites (152 pass). Full desktop
suite: 1532 pass.
2026-10-15 18:50:46 +08:00
Ryder Sun d22c8eb1f0 fix: keep natural discussions going instead of ending on one slip
Automatic group discussions (the production auto path) ended as
"partial" for reasons that had nothing to do with the task:
- any receipt whose nextKinds named an absent or paused Agent stopped the
  whole discussion with "no valid task completion decision";
- a peer's blocked or needs-human status ended the run on the spot,
  although only the delivery owner judges the task;
- an owner who failed, was paused, or handed off to an absent Agent ended
  the run silently;
- one missing owner receipt stopped the run without asking again;
- strict receipt and taskDecision grammar failed the Agent's whole turn
  for "Done", an @handle, a single string instead of a list, a trailing
  comma or code fence, an extra key, or a long summary, and the failed
  Agent was then excluded from the discussion.

Now absent recipients are dropped with a notice and valid requests still
run; a peer blocker is forwarded to the owner, who decides; the next
active selected Agent takes over ownership with a notice; an ignored
handoff keeps the current owner; an owner without a readable decision is
asked once more and the run stops only after two undecided owner turns;
completing without stopped participants explains why the run is partial.
Discussion receipts are normalised (status synonyms, @handles, case,
lists, smart quotes, trailing commas, closing fences, extra keys, missing
summary) before the strict parser runs, and an unreadable decision is
treated as no decision instead of failing the turn. Phased-V4 receipts
keep their strict contract. New zh/en notices explain each case.

Checks: natural discussion, natural writer, receipt, task-decision and
human-gate recovery suites (99 pass on this tree, including a new fenced
loose-receipt test and updated tests for the new routing, blocker and
handoff behaviour); npm --prefix frontend test (330). Full desktop suite
with the following prompt commit: 1532 pass.
2026-10-15 18:50:46 +08:00
Ryder Sun f994225990 test: give the hanging ACP initialize test a realistic second-spawn timeout
The test used a 100 ms initialize timeout for both turns. Under a loaded
full-suite run the healthy second fake-Agent process also needed more than
100 ms to start, so it fell back too. Only the first process hangs; the
second turn now uses the default timeout.

Checks: the lifecycle test passes three runs in a row.
2026-10-15 18:28:52 +08:00
Ryder Sun 06e1e8772c fix: render group replies in the order Agents were dispatched
No message carried a turn order. The timeline rebuilt one from round,
phase, the Agent's current position in the group and the save time, and
those disagreed:
- live bubbles had numeric startedAt, which Date.parse turns into NaN, so
  every running Agent was pinned under the user message and the list
  reshuffled each time a reply was saved;
- manual concurrent mode wrote failure notices before the barrier
  committed successful replies, so failures always rendered first;
- round-less notices sorted after every round, the 'discussion' phase
  had no rank, and editing the group reordered history;
- natural proposals were saved in completion order and peers read the
  transcript in that order, unlike what the user saw.

Now every group topic message gets a per-topic turnSeq. Batch
dispatchers (manual concurrent replies, natural proposal and discussion
batches) reserve numbers in slot order before dispatching; other turns
reserve at invocation start; failure and stop notices take their turn's
number; other topic messages take the next number when written. The
harness exposes the number on live Agent runs, so a live bubble and the
reply that replaces it share one position. Numbers are derived from saved
messages after a restart (no ledger or journal field changes). The
renderer sorts group topics by turnSeq with one shared rule for the
timeline and the trace panel; older history keeps its saved chronological
order. A failed attempt whose retry was already saved no longer lingers
as a ghost bubble, and peers read turns in dispatch order.

Checks: new local-workspace-turn-order tests (slot order with a failing
middle Agent and reversed completion; numbering continues after restart;
none on direct chats), natural discussion, manual durability and write
scheduling tests (63 pass on this tree); npm --prefix frontend test
(330 pass, including a new conversationOrdering spec and a
production-shaped live round test). Full desktop suite on the combined
tree: 1529 of 1530, the remaining failure being the ACP timing test fixed
in the next commit.
2026-10-15 18:28:52 +08:00
Ryder Sun 6522d357e0 fix: keep long-lived ACP Agents usable across stops, restarts and hangs
Persistent ACP runtimes (Hermes, Kimi, MiMo, OpenCode) were fragile:
- any turn error, including a user stop or watchdog timeout, destroyed
  the process and its native session; Hermes rejects cross-process
  resume, so the conversation then fell back to the silent legacy CLI;
- the process identity hashed the whole child environment, so a fresh
  login-shell PATH (fnm uses a per-shell directory) restarted the process
  and invalidated the stored session;
- initialize had no timeout and ignored stop while holding the
  conversation lock, leaving that Agent stuck until the app restarted;
- stderr kept the first megabyte of the process lifetime, so new
  failures were classified from stale lines.

Now a stopped or timed-out turn waits up to 3 s for the Agent to answer
the cancelled prompt and keeps the process and session when it does;
volatile shell values (PATH, TERM, TMPDIR, fnm variables, ...) no longer
change the process identity; initialize times out after 60 s (settable
per call) and honours stop without falling back; stderr keeps only the
current turn's last 64 KB. Disposable runtimes still close after every
turn.

Checks: cli-native-acp-lifecycle with three new fake-ACP tests (hanging
initialize releases the lock, a cancelled turn reuses one process and
session, a changed PATH keeps the process), plus the existing lifecycle,
adapter and protocol suites (185 pass). Full desktop suite: 1528 pass.
2026-10-15 18:04:17 +08:00
Ryder Sun 28fb01eff5 fix: stop the watchdog from killing Agents that are still working
Group runs gave an Agent three minutes to produce a mapped runtime event,
and only mapped events lifted that deadline. ACP agent_thought_chunk was
mapped to nothing, so Hermes, Kimi, MiMo, OpenCode and OpenClaw were
killed while thinking, and auto mode never retries timeouts. The 3/5
minute inactivity windows also cut off real builds and slow providers.

- Any sign of life (stdout/stderr bytes, ACP traffic) now lifts the
  startup deadline. In automatic discussions a separate no-progress cap
  (three inactivity windows) still stops CLIs that only emit heartbeats,
  so a stalled participant cannot block the round; manual and direct
  turns keep running while the process is active.
- Defaults are 10 minutes of inactivity and 20 minutes while a tool runs.
- ACP thinking is reported as a text-free reasoning status event
  (running, then completed when the answer starts); the private thought
  text never leaves the main process.

Checks: local-workspace-harness (74, including a new slow-starting Agent
test that failed with the old hard deadline, and the existing
heartbeat-only stop test), cli-adapters and cli-adapters-agent-protocols
(event order now includes the reasoning status). Full desktop suite:
1528 pass.
2026-10-15 18:04:17 +08:00
Ryder Sun 5fc70afde9 fix: explain run failures in Chinese and English instead of raw codes
Several codes that end an Agent turn or a whole run had no translation,
so the timeline showed a generic error or the raw code (for example
LOCAL_RUN_PERSIST_FAILED), and users could not tell why a discussion
stopped. The round-limit notice also claimed "no consensus" although
natural discussions have no consensus step.

- Map access-denied, session-invalid, output-limit, send-failed,
  refused, permission race, version/capability/protocol mismatch,
  task-decision and receipt errors, context overflow, persistence
  failures and the circuit breaker to zh/en messages.
- The round-limit notice now says the latest replies are the current
  result and how to continue (backend fallback text updated too).

Checks: npm --prefix frontend test (325 pass); updated assertions that
expected the raw code and the old round-limit wording.
2026-10-15 17:40:04 +08:00
Ryder Sun 35ed0d4e4a fix: send Hermes image attachments over ACP instead of dropping them
eb2234b stopped switching Hermes to its legacy transport for image
attachments to preserve the ACP session, but the ACP runner only sends a
text block, so images reached Hermes as nothing at all (the adapter test
for this failed on bb55fad).

Hermes 0.21.5 advertises promptCapabilities.image during initialize. The
runner now keeps the initialize capabilities, and when an ACP spec
carries imageAttachments it sends them as ACP image content blocks
(png/jpeg/gif/webp, up to 10 MB each) on the same session. An Agent that
does not advertise image prompts fails before prompting, so the existing
setup fallback uses the legacy transport with its --image argument.

Checks: cli-adapters (Hermes invocation spec) and a new
cli-native-acp-lifecycle test with fake Hermes ACP agents covering the
image-capable path and the legacy fallback. The capability response was
verified against the locally installed Hermes 0.21.5 with an
initialize-only handshake (no session or model call).
2026-10-15 17:39:43 +08:00
Ryder Sun 624a099bdd fix: give direct chats the current request, delivery contract, and full task
Commit 9198bf6 made direct chats send only the latest message text and
rely on the native session. After 1c9aabb a rebuilt session received the
continuation text instead, and that text deliberately excludes the
latest user message, so the Agent never saw the request it was answering.
Direct prompts also lost the deliverable contract (.meldwork-output/),
the read-only media warning, staged attachment paths, and regeneration
and recovery instructions, which is why generated files were not
captured and three media tests failed on bb55fad.

- New directPromptFor() leads with the user's own words. A new or rebuilt
  native session gets the earlier conversation plus "Current request:";
  a resumed session gets the request alone. The full delivery and
  language contract is sent once per native session, a one-line reminder
  afterwards. Staged inputs, recovery and regeneration instructions are
  appended again.
- The shared deliveryContract() is used by group and direct prompts.
- Isolated (task-graph) invocations again neither resume nor persist the
  conversation's native session (3ce8ee4 made them resume it, breaking
  the "approved prompt only" contract).
- The current task is no longer cut to 6,000 characters, and longer
  messages no longer fail every turn with
  LOCAL_RUN_REQUIRED_CONTEXT_OVERFLOW: submitted messages are already
  capped at 20,000 characters, so the full request is delivered.

Checks: local-workspace-harness (73) and local-workspace-context-packs
(15) pass on this tree, plus the direct, media and custom-label tests in
local-workspace and native-streaming (18), five of which failed on
bb55fad.
2026-10-15 17:39:18 +08:00
Ryder Sun 2da40db63d fix: tier authentication failures and retry transient provider errors
The merged branches disagreed on authentication failures: feature/1.0.5
marked every runtime auth failure 'unknown' so readiness never flipped,
while main's 22f811c classified any auth-looking diagnostic as
LOCAL_AGENT_AUTH_REQUIRED. Together with broad regexes (a bare
"forbidden" anywhere, a credential regex matching "login" or "403"),
proxy refusals stopped Agents while real sign-outs left them "ready".

- New pure module runs/failure-signals.cjs classifies CLI text:
  explicit sign-in or API-key statements are definitive; line-leading
  403/forbidden/unauthorized and permission_error are ambiguous; tool
  output that merely mentions 403 is neither. It also recognises rate
  limits (with Retry-After hints), network failures, provider 5xx and
  context overflow.
- Definitive failures stay LOCAL_AGENT_AUTH_REQUIRED and now mark the
  credential 'missing' (the catalog clears it after the retry window or
  when native credentials verify). Ambiguous refusals become
  LOCAL_AGENT_ACCESS_DENIED, are retried once, and never touch readiness.
- Process failures whose diagnostics show throttling, network loss or a
  provider outage are retried in that category. Rate limits honour
  Retry-After up to 60 s and wait at least 2 s without a hint.
- A resumed session that no longer fits the model context is classified
  as LOCAL_AGENT_SESSION_INVALID so the existing fresh-session retry
  rebuilds it; Rust panics and JSON parse errors no longer discard a
  healthy session.
- Automatic retries no longer re-run the whole Agent catalog refresh
  before each attempt, which flipped busy Agents to unavailable.

Checks: failure-signals (new), failure-policy, cli-process-support,
cli-adapters-agent-protocols, agent-runtime-contract and the auth/retry
tests in local-workspace and local-workspace-auto pass on this tree,
including three readiness tests that failed on bb55fad.
2026-10-15 17:37:57 +08:00
Ryder Sun 1033d086d3 fix: keep group members after Agent failures and recover emptied groups
An authentication or compatibility failure in an automatic discussion
called removeAgent, which rewrote and persisted group.agentKinds. One
proxy 403 or expired OAuth refresh made the Agent disappear from every
later turn of that group, and when the last member was removed the group
could no longer load: normalizeLoadedGroup rejects an empty member list,
so the next start silently dropped the group together with all of its
messages.

- The auto runner now pauses a failed Agent only for the current run.
  Group membership is never edited; the run-scoped exclusion already
  persisted in orchestration activeKinds keeps resume behaviour intact.
- The notice says the Agent is paused for this discussion, with the
  failure reason, and stays in the group (system.agentPausedAfterFailure,
  zh/en). The removal notice text is kept so history still renders.
- removeAgent refuses to remove a group's last member.
- Loading rebuilds an emptied group's members from the Agents that
  replied in it instead of dropping the group and its history.

Checks: node --test local-workspace-state.test.cjs (3 pass, including a
new recovery test) and the membership tests in
local-workspace-auto.test.cjs. Two tests there that also expect a
'missing' credential state stay failing until the next commit (they
already failed on bb55fad).
2026-10-15 17:36:07 +08:00
Ryder Sun 4f31b77503 chore: remove scratch files committed at the repository root
Commit 6aef211 added temporary icon exports, two large PNG screenshots
and a confirmation.json backup to the repository root. AGENTS.md forbids
placing screenshots and temporary files there and nothing references
them.

Checks: rg found no references to the removed paths.
2026-10-15 16:33:10 +08:00
Ryder Sun 6b6be1403e Merge main into feature/1.0.5
Bring main's 22f811c (auth classification from errors[], OpenClaw runtime
scope per CLI version, full participant round and cross-review gate for
natural discussions) and eac015d (removal of the managed shared Provider)
into the V1.0.5 branch before the stability work.

Conflict resolution:
- local-workspace-agent-catalog.cjs: keep feature's guard that an
  'unknown' runtime credential does not downgrade an authenticated Agent;
  drop the provider-credential-unavailable clause removed on main. The
  tiered auth policy is reconciled in a follow-up commit.
- README.md / README.zh-CN.md: keep feature's V1.0.5 summary and apply
  main's wording that Agents use their own CLI's model provider.
- docs/*: keep feature's untracking of local documentation drafts.
- cli-adapters-discovery.test.cjs: both sides were equivalent.

Checks: npm --prefix frontend test (325 pass). npm --prefix desktop test:
1503/1515 pass. The 12 failures are pre-existing on feature/1.0.5 at
bb55fad (verified by running them on a detached worktree of bb55fad) and
are addressed by the follow-up fixes.
2026-10-15 16:32:53 +08:00
Ryder Sun eac015dbfa refactor: remove the managed shared Provider capability
Each Agent CLI now runs only with its own native credentials. The central
path of configuring one provider inside Meldwork for every Agent added
instability without being realistic to maintain, and it depended on
machine-local configuration details.

- Delete the provider store/options modules, the local-agent-provider IPC
  handlers and preload API, per-CLI env injection (CODEBUDDY_*/ANTHROPIC_*/
  KIMI_* ...), the managed OpenClaw provider runtime, and shared-provider
  catalog gating; startup removes the legacy encrypted
  meldwork-provider.json.
- OpenClaw always resolves its native runtime now; native credential
  passthrough, the isolated gateway/guard runtime, and the
  runtime-auth-failure state machine stay unchanged.
- Remove the Provider settings UI, onboarding slide, providerMode display,
  ~100 i18n keys per language, provider CSS, and update the architecture,
  security, and discoverability docs to the native-credentials boundary.

Checks: npm --prefix desktop test (1512 pass), npm --prefix frontend test
(325 pass), frontend build and build:desktop, desktop pack.
2026-10-14 16:59:21 +08:00
Ryder Sun 22f811cde2 fix: harden local agent runs and broaden natural discussion rounds
- Extract WorkBuddy/Claude/Qwen error-result lists (errors[]) into failure
  diagnostics and classify authentication failures as
  LOCAL_AGENT_AUTH_REQUIRED instead of a bare LOCAL_AGENT_PROCESS_FAILED,
  so the catalog marks the Agent as needing a fresh login and retries stop.
- Scope the isolated OpenClaw runtime directory by session, workspace, and
  CLI version, so an upgraded OpenClaw gets a fresh managed scope instead
  of failing on legacy workspace state written by an older CLI.
- Natural agent-led discussions now open with a full participant round and
  the delivery owner cannot declare completion before peers had a
  discussion round; sequential runs get the same cross-review gate
  (system.autoCrossReview).

Checks: npm --prefix desktop test (1574 pass), npm --prefix frontend test
(343 pass), frontend build and build:desktop, desktop pack.
2026-10-14 16:52:25 +08:00
Ryder Sun bb55fad008 docs: reposition product as General Agent workspace
Refresh bilingual README and landing copy around evidence-backed review, local boundaries, and V1.0.5 capabilities. Update public download metadata and links.
Meldwork-V1.0.5
2026-09-17 16:13:45 +08:00
Ryder Sun 8995f5f627 docs: point download links to V1.0.5 2026-09-17 15:24:22 +08:00
Ryder Sun f562c68075 test: align Pi capability timeout expectation 2026-09-17 14:57:48 +08:00
Ryder Sun 6aef211188 chore: sync current workspace changes 2026-09-16 10:10:02 +08:00
Ryder Sun 28127b3706 fix: import reported agent outputs and authorize workbuddy writes 2026-09-15 18:38:50 +08:00
Ryder Sun d47bff5433 fix: retain agent readiness after transient auth failures 2026-09-15 18:29:55 +08:00
Ryder Sun 1c9aabbf8e fix: preserve direct context after session recovery 2026-09-15 18:16:55 +08:00
Ryder Sun eb2234b598 fix: preserve Hermes sessions across transport changes 2026-09-15 18:05:44 +08:00
Ryder Sun e7c0223bfa fix: canonicalize conversation session persistence 2026-09-15 17:28:29 +08:00
Ryder Sun 3ce8ee4f49 fix: persist isolated group agent sessions 2026-09-15 17:10:10 +08:00
Ryder Sun 07396fbf29 fix: remove ineffective duplicate attachment cleanup
Keep deletion on the existing IPC attachment cleanup path; remove an unused callback wired to the wrong coordinator and a nonexistent blob-store method. Verified focused conversation deletion test and git diff --check.
2026-09-15 17:02:26 +08:00
Ryder Sun 9198bf6548 fix: isolate chat runs and preserve agent sessions
Keep direct and multi-round conversations on stable Agent sessions, isolate writable direct chats in the scheduler, and remove orphaned local attachments when deleting a conversation.
2026-09-15 16:57:51 +08:00
Ryder Sun 956ddd0dd9 fix: unify window titlebar controls and distinguish conversation settings
Move preferences and shortcuts into a global titlebar 12px from the right edge. Remove hidden duplicate controls and preserve shortcut dismissal. Replace conversation settings gear with sliders.

Verified: frontend tests 343/343, web and desktop builds, Electron position and interaction checks.
2026-09-14 15:21:04 +08:00
Ryder Sun 5465609d54 fix: place workspace preferences in titlebar 2026-09-14 14:01:33 +08:00
Ryder Sun 31f2d43826 fix: place workspace preferences in header 2026-09-11 17:16:20 +08:00