Skip to content

v0.82.0

Choose a tag to compare

@davidfarah2003 davidfarah2003 released this 15 Oct 15:04
8ca93e9

Cotal 0.82.0 is out!

Grab it: npm i cotal-ai@0.82.0

Changes in this release

  • Define opt-in delegated-child recovery contracts and closed request validators. Bind retained descriptors, scan pages and claim replies to their lifecycle and manager registration without enabling manager or provider recovery.
  • Accept canonical space names in workflow admission records, including underscores, while preserving the separate endpoint-name grammar and rejecting malformed spaces.
  • The Claude Code MCP server can now be hosted. serveClaudeSession({ env, input, output }), exported from @cotal-ai/connector-claude-code/mcp, serves one managed session over the streams it is given and reads its launch env only from env, so one process can serve several sessions. Each call snapshots that complete environment for its presence label, bearer commands, carried-fork records and feedback contact lookup, including Git; it does not merge the host environment. Hosted feedback reads only the session's global Git configuration, including includes, so the host repository cannot supply its contact. Legacy tool hosts that omit the environment retain their existing repository lookup. The runtime subpath exports only serveClaudeSession. EndpointOptions.environment accepts an explicit presence label, or null to omit it without reading COTAL_ENVIRONMENT; an omitted option preserves process inheritance. The subpath includes CommonJS declarations for TypeScript hosts. Direct stdio launches remain supported and also shut down on input closure; a failure in that teardown exits with code 1. Hosted teardown releases its input listeners, handles input EOF and transport closure, refuses input that ends during startup, and reports teardown failures without an unhandled rejection in the host. A pending broker dial that fails after shutdown begins no longer makes close fail or strands local inbox custody. Shutdown still waits for pending start and reconnect work, proves every owned connection closed, and propagates connection-close failures.
  • connectOrThrow and connectUserControlOrThrow now throw a user-auth mesh's login and exchange refusals (not logged in, auth service down, actor not granted) as a ConnectRefusal carrying the provider's sentence. connectOrThrow used to print that sentence and exit the process, so the console's delchan on a user mesh with no login on the machine ended the console instead of showing the refusal on its status line. connectOrExit and connectUserControlOrExit still print the same sentence and exit 1.
  • Launch the per-session MCP server with --optimize-for-size --max-semi-space-size=1 to cut its memory footprint.
  • cotal_status with an activity and no status now changes only the activity. It used to read the current status when the tool ran and write it back behind any status write still queued, so a pending waiting was published as working with its condition cleared, and a pending turn-end idle left the seat reading working.
  • A Jcode seat now passes its pre-join readiness proof when Jcode calls cotal_orientation through its deferred mcp_call tool. The proof matched only the completed tool's name, which is mcp_call on that path, so both readiness turns missed it and the seat exited without joining. The host now reads the call's streamed arguments and counts an mcp_call only when it names server cotal and tool cotal_orientation, and only for the mcp_call completion of that same call: a completion under another name, or a later call that reuses its id, does not count. An orientation call that fails or returns an MCP error result no longer counts on either path.
  • On OpenCode 2.x, a peer batch is acked only by the end of an execution that started after the batch was submitted. An end observed while idle, a replay of one, or an end positioned before the running execution started (even after a late copy of an earlier start) no longer acks a newly submitted batch, and a failed prompt submission no longer lets a second batch into an execution that is still running.
  • The OpenCode launcher now stops its server on SIGINT or SIGTERM from the moment it starts it. The handler used to be installed only after the plugin's session handshake, so a graceful stop during the boot, which can take a minute on a cold server, ended the launcher and left the server running on the agent's database, with a serve.pid record that refused every later launch of that name until the server was killed by hand. One handler now stops the server and, once it runs, the TUI.
  • The OpenCode launcher now records each server in a file of its own, serve.<token>.pid in the agent's directory, and removes only that file when the server exits. Every launch of a name used to share one serve.pid, and the launcher's exit handler removed it unconditionally, so a handler that ran after the next launch had started its server removed that server's record, and the launch after that started a second server on the same database. A launch now checks every record in the directory, including a serve.pid left by an earlier version, refuses while any names a running server, and removes the records of servers that are gone.
  • The OpenCode 2.x adapter no longer starts a turn once its teardown has begun. A message handled after the disposer started, or a drive waiting on session creation when it started, used to be submitted to OpenCode as a new turn whose batch was never acked because the seat was going away. drive now refuses on entry and again after the session await, as the 1.x adapter does.
  • cotal up --user-auth --idp <url> on a space that already pins an IdP now compares the normalized URL with the pin. Re-running the command that created the pin with a trailing slash was refused as a re-pointed IdP that "would re-key every derived owner", although both spellings name the same IdP. A malformed later value now gets the same URL refusal as a first enable, and a different IdP is still refused.
  • The manager-service authority request now refuses a redirect, as the other manager-authority requests already did. Before this, a 307 or 308 from the pinned endpoint re-sent the login proof to the address it named and returned that host's answer as the manager's authority material. All remote manager-authority requests now go through one endpoint lookup and one request path, so the redirect refusal and the refusal messages are the same for each of them.
  • cotal up --detach and cotal up -f now exit 1 when the control plane does not come up on a first boot. Both printed ! control plane degraded: ... and then exited 0, so a script or unit read success over a mesh with no manager or delivery daemon, while a refresh over the same failure already exited 1.
  • cotal up -f and cotal spawn -f now check --server against the rules a manifest's broker.servers already follows. A --server URL with embedded credentials used to pass: up -f --dry-run printed it whole in the plan, and spawn -f dialed it and printed it in its reach error. It is now refused with --server entry 1 must not embed credentials, a message that does not repeat the value. An invalid --server URL is refused the same way, and so is a value that names no URL: --server "" used to fall back to the default broker, and a blank or comma-only --server or broker.servers failed with a bare Invalid URL. Both now get names no server URL.
  • A bare re-run of cotal up now finds this folder's own mesh when its first boot ran on an auto-selected port. The re-run started from the default URL, missed the record, picked another free port, and was refused with space "<space>" is already in use by a mesh at <url>, so a refresh or repair needed --server by hand. With no --server, cotal up now starts from the URL this root recorded for the space, and --host keeps that URL's port.
  • cotal update no longer refuses its running-manager continuity check when the selected mesh is one this machine runs and it is stopped. A mesh selected with --space or by running inside its project, where no cotal supervise process on this machine may be serving that space and whose recorded broker address refuses the connection because nothing listens there, has no running manager to preserve, so the update now reconciles the connectors and extensions. This covers a local user-auth mesh too, which used to refuse on its stopped auth service first. Before this, cotal down followed by cotal update, the only way past a legacy manager verdict, refused with "no mesh running at ... run cotal up there to restart" and left every extension at the old version. Anything short of that proof still refuses: a mesh registered with cotal meshes add, a --server override, a cotal supervise process still running from any folder whose command line names that space or no space, or an address where anything accepts the connection or the dial does not finish in time.
  • A cancelled turn, ask or escalation whose relay withdrawal is refused for a reason a retry cannot change now fails its step at once with that refusal's code. Before this, every refusal was retried silently every two seconds until the relay's deadline, so a cancelled step against a manager that serves no cancel (not-found), or an accepting manager with no such relay pending (failed-precondition), stayed in its scope for the step's whole timeout. Only unavailable and deadline-exceeded are still retried until the deadline. A withdrawal the accepting manager refuses is now thrown as an EpEnvelopeError carrying its code.

What's Changed

  • fix(connector-opencode): stop the serve on SIGINT or SIGTERM during the boot by @davidfarah2003 in #3881
  • fix(workspace): throw user-auth connect refusals from connectOrThrow by @davidfarah2003 in #3883
  • fix(runtime): fail a cancelled step at once when its relay withdrawal is refused for good by @davidfarah2003 in #3884
  • fix(auth): refuse redirects on the manager-service authority request by @davidfarah2003 in #3891
  • fix(cli): exit 1 when a first up boot's control plane does not come up by @davidfarah2003 in #3893
  • fix(auth): compare a later --idp with the IdP pin after normalizing it by @davidfarah2003 in #3895
  • fix(cli): check --server on up -f and spawn -f against the broker.servers rules by @davidfarah2003 in #3896
  • fix(connector-opencode): record each serve at a path of its own by @davidfarah2003 in #3897
  • fix(cli): let update reconcile when the selected mesh is stopped by @davidfarah2003 in #3899
  • fix(connector-core): keep an activity-only cotal_status off the status by @davidfarah2003 in #3908
  • fix(connector-jcode): prove readiness on a deferred mcp_call orientation by @davidfarah2003 in #3909
  • fix(cli): start a bare cotal up re-run from the URL its mesh recorded by @davidfarah2003 in #3910
  • fix(connector-opencode): refuse a 2.x drive once teardown has begun by @davidfarah2003 in #3911
  • fix(connector-opencode): settle a 2.x batch only from the execution that carried it by @davidfarah2003 in #3912
  • feat(core): define delegated recovery contracts by @davidfarah2003 in #3913
  • perf(connector-claude-code): launch the MCP server with memory-saving V8 flags by @caffeinum in #2403
  • fix(core): validate run admission with the canonical space grammar by @davidfarah2003 in #3919
  • feat(connector-claude-code): expose the managed session server by @davidfarah2003 in #3921

Full Changelog: v0.81.1...v0.82.0