Skip to content

v0.79.0

Choose a tag to compare

@davidfarah2003 davidfarah2003 released this 10 Oct 17:52
979312e

Cotal 0.79.0 is out!

Grab it: npm i cotal-ai@0.79.0

Changes in this release

  • Whether a consumer info or delete found no consumer is now decided by one predicate, isConsumerNotFound in @cotal-ai/core, which accepts only the broker's structured ConsumerNotFound error. It no longer accepts a bare name of ConsumerNotFoundError or a string code, so the run journal's replay cleanup no longer swallows those shapes. The stream, KV scan, run wait, delivery pending and auth scanner sites use it in place of their own copies, and isJetStreamMissing, the structured check it builds on, is exported beside it.
  • The hover docs for CotalEndpoint.serveControl and requestControl no longer describe manager control tiers, a manager wildcard reply grant or an agent-credential cutover that no longer exist. They now name the delivery daemon's ctl.delivery.*.*.reply.> grant as the reason boundReply is required, and the CONTROL_DELIVERY and requestDelivery docs match the bounded reply both control requests use. Comments on the session ledger, goal-writer, caller grant, invoke, endpoint-serve ledger, lease and slot-row declarations no longer cite internal planning labels that no spec or doc page defines; the mechanism text and the SPEC and §13.x citations stay. No behavior changes.
  • The persona catalog directory is now built in one place, personaDir in @cotal-ai/core. agentFilePath and listPersonaCatalog build on it, @cotal-ai/workspace keeps exporting it under the same name, and cotal status and cotal personas use it in place of their own copies, so the directory spawn loads personas from and the directory those surfaces name cannot drift apart.
  • reconcileEndpointGate, behind cotal reconcile-gate, the manager's boot self-heal and the auth host's remote-manager maintenance, no longer reports a completing reopen whose acknowledgement was lost as raced with "Nothing was reopened" while the gate is open at the repair's own coordinate. It chose that refusal by matching the error text of completeFrozenRegistrationFromSpec, which used one message for a lost reopen CAS and for a reopen whose outcome is unknown. completeFrozenRegistrationFromSpec now returns a lost CAS as { completed: false, raced: true }, and the repair refuses raced only on that result. A reopen whose outcome is unknown fails with an unavailable error that says it may have committed, as the same fault on the abort-reopen path already did, so the boot self-heal no longer continues past it.
  • Accept canonical space names containing underscores in issued-authority references, source coordinates and stores. Refuse malformed spaces without rewriting them and preserve endpoint-name validation.
  • A manager call that fails with a thrown envelope error now returns the error's code and details, the same as a refusal that arrives as a reply. The CLI's control calls, cotal spawn -f and the connector's manager tools each converted the thrown error by hand and dropped the code, and two of them also dropped the details and the lifecycle-blocked suffix. A cotal attach reconnect therefore kept retrying a permission-denied or not-found raised on the caller side, such as a broker refusal, instead of stopping on it. Core now exports controlReplyFromThrown, and each caller keeps its own message.
  • A failure a bridged host handler throws now crosses into the engine thread as the class it was raised as, with that class's own fields, and is rebuilt with nothing defaulted. Before, an EffectError missing its code or kind was journaled as L4000 / handler-fault, and an EffectRefused missing its code as L5016, while the in-process walker recorded the same failure with those fields absent. A bridged failure now journals the same as an in-process one.
  • A manager or delivery start that refuses a record it cannot attribute now names the pidfile it read. The cutover preflight, spawn -f, the delivery start and service install used to resolve the record's spelling a second time while formatting the refusal, so a record that moved between its space-keyed and pre-upgrade names in between was misnamed, and one that appeared beside the record that was read replaced the refusal and its NEXT: step with an ambiguous-record error. readProcessRecord in @cotal-ai/workspace now returns the path it read on every ProcessRecord, and service status --json reports that file as manager.path. The config and CLI pages describe both.
  • An installed extension whose package.json is not JSON or has no version is no longer reported as not installed or with a bare JSON parse error. installedExtensionVersion throws CorruptExtensionPackageError, which names the package and its package.json, so loading the extension, cotal status and the cotal setup card report the damaged file. cotal ext seed --repair reinstalls a seeded built-in in that state, including after a corrupt extensions manifest was rebuilt.
  • The manager and delivery daemon records are now read and attributed by one reader, readProcessRecord in @cotal-ai/workspace, which takes the record path and the component's attribution predicate and returns the state with the pid, content and command line behind it. The rule that a live pid is demoted to foreign only when its command line was read and is not the component's now lives in one place, and the delivery verdict keeps the command line it was decided on, as the manager's already did. No states or messages change.
  • The web dashboard's pidfile name is now one WEB_PIDFILE constant in @cotal-ai/workspace. The dashboard declares its record with it, and the cotal status Web process row, cotal status --components, the cotal setup card and the cotal clean all crash-residue sweep read it from there. They used to spell web.pid by hand, so renaming the dashboard's record would still typecheck while those readers reported a running dashboard as down or absent and clean all left its pidfile behind. The file is still .cotal/web.pid.
  • cotal logout, the account switch in cotal login, cotal down and cotal clean all now remove their registry entries as one batch that scans the registry for pre-hex records once. Before, each removed entry ran its own scan over the whole registry, so removing K entries from a registry of R records read about K × R record files. The removed entries and the pointer outcome are unchanged, also when a removal fails partway through the batch or a concurrent cotal use moves the pointer during it.
  • A seat writer generation file is now keyed by spaceKey of the space and of the seat name, joined by 00, and one builder names it for both the claim and the load. An empty space, a name with an unpaired surrogate and a space or seat name containing NUL are refused instead of written, so two different seats can no longer share one generation file and refuse each other's claim. Every key a valid seat already has is unchanged. The account record filename is also built in one place now, for both its file path and its store key.
  • The Claude Code AG-UI mapper's comments no longer restate its origin tables by hand. The module header listed human and channel as the only origins that open a run, while ORIGIN_RULE also opens auto-continuation; it now points to ORIGIN_RULE and ABSENT_ORIGIN_RULE as the only list. The promptSource field doc no longer says only "sdk" is read, and the run-opening comment no longer calls channel the only change from the plan's table. No behavior changes.
  • A Codex seat that stops while its event plane is armed but not yet bound to a rollout file no longer binds on the way out. A bind that resumes after the seat began stopping now stands down, whether it was looking for the file or reading where to start in it, and whether shutdown's own drain, the turn boundary from shutdown's interrupt, or the launch started it. The seat no longer logs another no rollout file yet line while it exits, and no longer adopts an emitter that nothing closes while it leaves the mesh.
  • The AG-UI emitter builds an error close's RUN_ERROR directly from the fixed run failed message, and packUnits bounds the closing frame as it does every other. The helper that could shorten an upstream failure detail behind a notice is gone: the close has passed only the fixed message since upstream detail stopped reaching the wire, so its truncation search never ran, and its notice-only fallback was larger than the event it replaced. A close whose envelope cannot fit still fails loud, now with packUnits' refusal. takeCodePoints is no longer exported, since the preview splitter is its only user. Code that imported it takes a string's first n code points with Array.from(s).slice(0, n).join("").
  • Remove the unused KNOWN_AGUI_EVENT_TYPES set from the AG-UI module. Its doc comment described a classification role that parseAguiFrame already plays without it. The egress-guard differential cell that carried its name now says it counts the event types AGUI_EVENT_TYPE defines.
  • The completion section of the CLI page, which ships in the bundled docs, now shows how to enable completion in the current bash, zsh, fish or PowerShell session, lists the files cotal completion install writes for each shell along with the XDG_CONFIG_HOME and ZDOTDIR overrides it honors, and explains that the installed stub resolves candidates through the local cotal __complete dispatcher. No behavior changes.
  • The CLI reference now says what running pnpm cotal from a dev clone needs: a pnpm build first, because bin/ loads the other packages from their built dist/, and COTAL_SKIP_CONNECTOR_SEED=1 for everyday commands, which otherwise refuse the operator-global seed store from a checkout. It also notes that pointing XDG_CONFIG_HOME at a scratch dir is not enough on its own. Docs only.
  • The connector's capacity limits now say what they bound. The inbox size, the overflow-evicted classification memory, the focus exclusion limit and the protected-disposition limit carry doc comments naming the structures each one caps, including that the focus limit bounds the exclusion list and the id-less copy tally separately. The in-flight hold ceiling, which was an unnamed twice-the-inbox expression, is now its own constant derived from the inbox size, and the endpoint notice log's cap of 16 is a named constant. No values or behavior change.
  • The auth service now builds its data account's signing context in one place. The authority plane's own mints, the remote manager credentials it issues and the delivery-admin endpoint all sign through it, where before the delivery-admin endpoint and the manager-service issue path each spelled their own copy. Credentials are unchanged.
  • The run attempt and run revoke parsers now parse their own registered-manager envelope. They used to rewrite the request into a run admission with a placeholder run and hand it to the admission parser. A manager-run-attempt that carries a run field is now refused as an unknown field, where it was accepted and the field dropped. Attempt and revoke refusals name their own kind and carry the manager run attempt request or manager run revoke request prefix. The manager-service authority parser also refuses a session request whose session carries a key other than id, endpoint, sessionId, epoch and exp, and returns a session built from the checked fields, where it returned the caller's own object.
  • cotal completion now skips the connector-seeding boot gate alongside __complete and help. Sourcing completion in shell startup profiles no longer acquires the operator-global reconcile lock or rewrites stamp.json, and running cotal completion <shell> from a development checkout no longer fails on the source checkout guard.
  • cotal console and cotal join now print a seat's harness-reported condition and its ages the way cotal endpoints and cotal status do. The console roster, NEEDS YOU rail and detail pane, the --plain line stream, and the cotal join presence lines, Present: line and /who show waiting (rate_limit for 40m) · unchanged for 5s · active 40m ago and the activity's (set <age> ago) instead of a bare waiting. The roster and each NEEDS YOU card put the status and these facts on rows of their own under the seat's name, wrapped to the pane's width at any terminal size, so neither a long name nor a narrow terminal cuts them and they no longer push the activity out of view. A seat that needs more rows than a short terminal leaves its pane takes the title's row and is cut at the bottom, keeping its name row, and Enter opens its detail pane with every fact. The console's ages use the shared compact format, so a heartbeat nine hours old reads 9h rather than 540m, and an age floors rather than rounds.
  • cotal spawn with COTAL_ENROLLMENT_URL or COTAL_ENROLLMENT_FILE against a registered remote user-mode mesh whose record pins no exchange URL now refuses before it redeems the enrollment, with the same "records no exchange endpoint" sentence and re-registration step the provisioning path gives. It used to spend the one-time enrollment and then refuse with "the enrollment's authServiceUrl does not match the registered mesh exchange", which hid the missing pin.
  • The delivery cutover preflight now checks the delivery-aware marker against the manager pid it attributed, without reading the manager pidfile a second time, and its stop signals only that pid. A delivery-aware manager that exits while cotal up runs the preflight is no longer reported as an old Plane-3-hosting manager, and a manager that replaces the record meanwhile is no longer stopped in place of the one the preflight judged. cotal status and the cotal up --runtime reuse warning check the marker against the pid from their own record read.
  • A spawn rolled back as an orphan on a user-auth manager no longer logs despawn <name>: retirement confirmed for a prior lifecycle of "<name>"; the current hold is left intact. That lifecycle was never despawned and has neither a successor nor a hold on its name, so the manager now logs retire <name>: lifecycle <uid> retired; the name had no hold to clear. A late answer that arrives while a successor holds the name keeps the prior-lifecycle line, and a despawn that clears its own hold keeps the retirement-completed line.
  • The cotal supervise --ws-port help and the user-mode session redemption refusal no longer cite internal plan labels. The manager's service endpoint, spawn action, session plane and console comments drop the same labels and their slice, checklist, ruling, pin and milestone tags, keeping the mechanism text and the SPEC references. The console page and client served to the browser carry the same cleanup. Only text changes.

What's Changed

  • fix(connector-core): say what each MeshAgent capacity limit bounds by @davidfarah2003 in #3689
  • fix(core): build the persona catalog directory in one place by @davidfarah2003 in #3690
  • docs(cli): say what running from a dev clone needs by @MehulNegi in #2383
  • docs(cli): document shell completion evaluation and persistent install by @apsian4352-coder in #2389
  • fix(auth): build the data account's signing context in one place by @davidfarah2003 in #3696
  • fix(core): decide reconcile-gate's raced refusal from the reopen outcome, not its message by @davidfarah2003 in #3699
  • fix(connector-core): remove the unused AG-UI event type set by @davidfarah2003 in #3703
  • fix(cli): refuse an enrollment spawn on a record with no exchange pin before redeeming it by @davidfarah2003 in #3706
  • fix(core): classify a missing consumer by one structured rule by @davidfarah2003 in #3709
  • fix(connector-core)!: remove unreachable RUN_ERROR detail bounding from the AG-UI emitter by @davidfarah2003 in #3710
  • fix(cli): read the manager and delivery records through one attribution reader by @davidfarah2003 in #3712
  • fix(lang): rebuild bridged failures from a class-keyed union with no defaults by @davidfarah2003 in #3717
  • fix(cli): skip connector reconcile on shell completion stub generation by @apsian4352-coder in #2388
  • fix(workspace): key seat writer generations through spaceKey by @davidfarah2003 in #3719
  • fix(manager): stop reporting a prior lifecycle and a hold for an orphaned spawn's retirement by @davidfarah2003 in #3724
  • fix(workspace): report a corrupt installed package.json instead of not installed by @davidfarah2003 in #3725
  • fix(manager): drop internal plan labels from the --ws-port help and manager comments by @davidfarah2003 in #3729
  • fix(core): drop deleted manager ctl tiers and plan labels from shipped comments by @davidfarah2003 in #3732
  • fix(auth): parse run attempt and revoke requests with their own envelope by @davidfarah2003 in #3734
  • fix(connector-claude-code): point the mapper header at its origin tables instead of a partial list by @davidfarah2003 in #3733
  • fix(remotion): frame the header reel's mode cards at MODE_STAGE by @davidfarah2003 in #3739
  • fix: keep a thrown envelope error's code and details in the control reply by @davidfarah2003 in #3742
  • fix(web): name the dashboard pidfile through one workspace constant by @davidfarah2003 in #3756
  • fix(cli): name the pidfile a start refusal read instead of re-resolving it by @davidfarah2003 in #3757
  • fix(connector-codex): keep a stopping seat from binding its event plane by @davidfarah2003 in #3758
  • fix(workspace): remove an account's or a root's registry entries in one batch by @davidfarah2003 in #3763
  • fix(cli): show the presence condition and its ages in the console and join by @davidfarah2003 in #3765
  • fix(cli): check the cutover preflight's delivery-aware marker against the attributed manager pid by @davidfarah2003 in #3766
  • fix(core): validate issued spaces with canonical routing grammar by @davidfarah2003 in #3768

New Contributors

Full Changelog: v0.78.1...v0.79.0