[{"name":"compaction","kind":"directory","size":0,"lastCommitHash":"419643717a968f6cacae6d180d1c60baa070e4ee","lastCommitWhen":"2026-09-17T07:10:10+03:00","lastCommitMessage":"feat(coding-agent): support automatic compaction thresholds via /compact at <tokens>\n"},{"name":"export-html","kind":"directory","size":0,"lastCommitHash":"844e85545af6858dcb3d6cfe42bbfcf2ca0be4e5","lastCommitWhen":"2026-09-06T21:56:32-04:00","lastCommitMessage":"Harden session persistence, worker recovery, and daemon refreshes (#2028)\n\n* refactor(coding-agent): move the semantic-edge ledger onto the event-log substrate\n\nThe recorder's private append/replay/repair IO is deleted; EventLog owns it, the same move #1987 made for the RLM spawn ledger. One durability rule is unified in the substrate rather than dropped: an unterminated final line is an uncommitted append, skipped on read and truncated before the next append — never newline-completed and never surfaced to a consumer whose next append destroys it.\n\n* fix(coding-agent): make the explicit ledger reader's ENOENT contract atomic\n\nreadSemanticEdgeLedger probed with statSync before reading through EventLog, which swallows ENOENT; a ledger deleted between the two returned [] instead of throwing. The missing-file decision now lives at the single open (replaySync missingFileThrows), so no check-then-read window exists.\n\n* docs(coding-agent): state the event-log tail rule once\n\nThe unterminated-tail contract was restated four times (module doc, replaySync doc, two test comments). It now lives once in the module doc; the method doc keeps only its own parse/missing-file semantics and the test comments reference the contract.\n\n* fix(coding-agent): write event-log appends fully and gate appends on tail repair\n\nwriteSync may write short (ENOSPC after a prefix); appendSync now loops until the payload is fully on disk so write-before-action callers never act on a torn record reported as success. A tail-repair failure (e.g. append-only ACL permitting O_APPEND but not r+) now propagates instead of being swallowed: writing through an unrepaired torn tail would weld it to the new record as permanent interior corruption. ENOENT and the concurrent-writer instability path keep their existing semantics.\n\n* fix(coding-agent): reclaim short event-log writes instead of completing them\n\nThe rlm spawn ledger is multi-writer by documented design (supervisor plus each worker over one file), so completing a short O_APPEND write with a second write could interleave with a rival append and weld two records. A short write now truncates its own torn prefix back off (only while this writer still owns the tail) and fails the append; a torn tail is read-tolerated, a weld is permanent corruption. The append fd opens a+ so the ownership check can read the tail.\n\n* fix(coding-agent): leave the torn tail on a short write instead of reclaiming it\n\nThe tail-match reclaim could truncate a rival's committed record whose final bytes coincide with our torn prefix - committed-data loss, strictly worse than the torn tail it prevented. A short write now just fails the append: the torn tail is the one tolerated shape, skipped on read and truncated by any writer's next repair (verified for both topologies: a resumed single-writer recorder repairs on its first append; every rlm-ledger writer repairs before each append).\n\n* refactor(coding-agent): compress event-log comments\n\n* fix(ai): omit the default service tier, reprice cache writes from message_delta, repoint the zai default\n\nIncorporates #2032 at f82c7fa3688b7e25cef80e2663fe77ed153c5cd9.\n\n* fix(tui,coding-agent): survive lone surrogates in table cells and terminate the WebP EXIF scan\n\nIncorporates #2033 at a3d1139ee6e1f77337ab134b0f0c0cede8c942af.\n\n* fix(coding-agent): restart dead kernels on ensure() and read mcp>=2 tool schemas\n\nIncorporates #2034 at 749e216e901304b310ead9f46c3813a032608d7b.\n\n* fix: one crash-safe owner for durable state writes\n\nIncorporates #2035 at f0f02d2fb090ec427307a65b9e9578ae3c8fc783.\n\n* fix(coding-agent): one zombie-aware process-liveness probe\n\nIncorporates #2041 at 92a0eacf47efc831444b0b4e412f35bd17ac3f28.\n\n* fix(coding-agent): snapshot transfer ids from the materialized cursor; mismatches settle the transfer, not the worker channel\n\nIncorporates #2044 at 5af3bbe8090240507d6b0297d0da007159e15305.\n\n* fix(coding-agent): failed workers recover on touch; roster gaps answer a structured recovering error\n\nIncorporates #2047 at 77b747afab402a9e2f5eada227ffe6fed626a634.\n\n* fix(coding-agent): seven session and IO correctness defects\n\nIncorporates #2037 at 41b5d72d7758723f22ba07f8738d217868ed7baf.\n\n* fix(coding-agent): coalesce child-usage attribution and gate agent-status persistence on real changes\n\nIncorporates #2050 at 6b0af5d2679ddff987ef3b4d43235a872fe2b315.\n\n* fix(coding-agent): incremental single-flight session metadata scans\n\nIncorporates #2043 at df032c1192dd2e38d35fcbaca589db7194f26b6c.\n\n* fix(coding-agent): memoize the passive RLM topology derivation\n\nIncorporates #2051 at 0ee114ce77942d9298136ca193ddc2c0b5d27d58.\n\n* fix(coding-agent): preserve accounting and metadata across deferred updates\n\nKeep durable child-usage aggregates separate from pending sibling usage. Retry optional topology metadata after transient reads. Completes #2050 and #2051 integration.\n\n* fix: preserve session accounting and read-only persistence boundaries\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"extensions","kind":"directory","size":0,"lastCommitHash":"419643717a968f6cacae6d180d1c60baa070e4ee","lastCommitWhen":"2026-09-17T07:10:10+03:00","lastCommitMessage":"feat(coding-agent): support automatic compaction thresholds via /compact at <tokens>\n"},{"name":"kernel","kind":"directory","size":0,"lastCommitHash":"6b8fbd8b0831e14a085634ea8a395b60d8041c3b","lastCommitWhen":"2026-09-17T20:40:32+03:00","lastCommitMessage":"fix(coding-agent): harden kernel bootstrap lock, staging checks, import isolation and postinstall\n"},{"name":"mcp","kind":"directory","size":0,"lastCommitHash":"b6ac5d014d99401b55820835a4966584271e9a3c","lastCommitWhen":"2026-09-16T16:20:18-07:00","lastCommitMessage":"mcp service catalog and oauth engine (#2330)\n\n* add a shared service catalog and generic mcp connections (#2256)\n\n* style(coding-agent): apply biome formatting to daemon-mode.ts\n\n* feat(coding-agent): add /plugins service catalog with verified MCP connections (ENG-6108)\n\n- Add /plugins and bare /mcp as the same searchable external-service picker with\n  honest states (Connect, Connected with verified tool counts, Reconnect,\n  Verifying, Requires setup, Disabled) and connect/disconnect actions\n- Add mcp.list_plugins, mcp.search_plugins, and mcp.list_connections host\n  requests with strict status filters, bounded limits, and honest nextCursor\n- Add local connection records (connectionId distinct from catalog serviceId);\n  verify every login with a real MCP handshake so token presence alone is\n  pending, never Connected; rejected credentials recover via Reconnect\n- Serve connected catalog services (Linear, Notion) through the generic mcp\n  runtime route: system-prompt inventory and mcp.config, no per-service wrappers\n- Drop the McpIntegration import from the kernel ready check ahead of the\n  Linear/Notion wrapper-package removal\n- mcp.connect is registered only behind an explicit UI-approved callback and\n  stays unregistered in daemon-hosted sessions (honest \"no handler\")\n\nTests: mcp-service-catalog, mcp-manager handlers, service-catalog-picker, and\nthe eng-6108 activation regression covering login -> verify -> session reload ->\nprompt inventory in the real services path without a restart.\n\n* fix(coding-agent): harden MCP verification, activation, and connection records (ENG-6108)\n\nReview follow-ups on the /plugins service catalog slice:\n\n- Verification now runs through the official @modelcontextprotocol/sdk\n  client (negotiated protocol version header, CRLF SSE support, explicit\n  session termination via HTTP DELETE) instead of a handwritten transport\n- Failures persist as fixed safe categories only; endpoint URLs,\n  server-controlled text, and tokens never reach records or messages\n- Connection records use the auth.json file-lock read-modify-write pattern\n  with unique temp files; concurrent UI/daemon writers no longer lose\n  records, and pending operations queue while a flush is in flight\n- Every verification result is bound to the exact grant it verified\n  (credential hash); stale probes after logout or token rotation are\n  discarded, never marking a newer or removed account Connected\n- An OAuth connection without a usable token is never probed anonymously\n- A login made while streaming or compacting queues automatic activation\n  at the next safe boundary (agent end / compaction end); the UI never\n  instructs the user to run /reload for MCP changes\n- /plugins and config-menu connect paths share the queue; failure categories\n  render as fixed user-readable wording\n- metadata-reviewed / legacyBuiltin rename absorbed from the catalog lane\n\nTests: probe (SDK fake server incl. CRLF/401/timeout/secret-leak), store\n(two-writer races, guard discard, mid-flight queueing), service catalog\n(stale verify after logout/rotation, non-connectable transports), manager,\nactivation queue (streaming/compaction/tool boundaries), regression suite.\n\n* fix(coding-agent): bind MCP credentials to endpoints, reconcile providers, honest connect (ENG-6108)\n\n- Endpoint binding everywhere a stored grant is consulted: catalog services and\n  user-declared servers require cred.endpoint === current URL before any token\n  fetch or probe (views, verify, dispatch inventory, demand-driven listing);\n  unbound legacy grants surface as Reconnect with the fixed credential-unbound\n  category and are recorded once on demand-driven verification\n- Provider ownership is one atomic reconciliation: legacy built-ins, eligible\n  catalog services, and user-declared OAuth servers are re-registered first and\n  only previously-owned ids unregister; the ModelRegistry reset hook calls the\n  full reconciliation, so catalog providers survive refresh and a removed user\n  override restores the catalog provider after a single manager.refresh()\n- Flush-time verification guards re-read fresh credential-source state\n  (authStorage.reload() under the backend lock), so probes that finish after\n  another client logged out or rotated the grant are discarded — no stale\n  Connected record survives across clients\n- mcp.connect (explicit-approver seam) verifies the real handshake before\n  reporting connected (tool count included) and reports fixed failure\n  categories on rejected handshakes\n- /plugins stdio user servers get a real management action: Enter disables the\n  server in global settings, refreshes providers, and reloads; already-disabled\n  and vanished entries report honest status\n- Catalog views keep the Reconnect action on error rows and add unverified/\n  unbound view tests; all oauth test fixtures now carry bound endpoints\n\nMinimal type-only addition in connection-probe.ts (lifecycle lane owns the file):\nMCP_PROBE_ERRORS.UNBOUND_CREDENTIAL.\n\nTests: manager 29, service-catalog 23, activation-queue 8 (incl. stdio\nmanagement), probe 7, store 6, picker 4, regression 2, slash-commands 18 —\n97/97; reviewer's mcp-service-safety suite verified 12/12 green against this\ntree (their file, their branch).\n\n* feat(ai): merged MCP service catalog with deterministic importer (ENG-6108)\n\n* feat(ai): metadata-reviewed catalog status, legacy builtins, local JSON sources, literal endpoint checks (ENG-6108)\n\n* fix(ai): harden local catalog loader and endpoint checks (ENG-6108)\n\n* feat(coding-agent): shared catalog resolver, local sources, per-account connections (ENG-6108)\n\n- resolveMcpServiceCatalog merges the built-in SERVICE_CATALOG with\n  settings-declared local sources (Settings.mcpCatalogSources): ~-expanded\n  before loadLocalServiceCatalog (which does no expansion), declared-but-missing\n  files and cross-source duplicate ids surface as visible diagnostics, first\n  source wins, total capped at 500 entries\n- The SAME resolution feeds the /plugins UI and the mcp host handlers; the UI\n  re-reads connection records from disk before rendering (no stale cache) and\n  shows resolver diagnostics on open\n- One-click Connect is metadata-reviewed-only (plus user-placed local files,\n  which still go through the login dialog's explicit approval); unreviewed\n  imported entries stay candidates with an honest setup hint\n- Per-account connections: \"Add another account\" allocates a distinct\n  connectionId (mcp:<serviceId>-N) with its own credential key, record, and\n  OAuth provider; the account picker lists accounts with per-account\n  Reconnect/Disconnect; alias ids join integrations, dispatch inventory,\n  mcp.config, and demand-driven verification through the same machinery; the\n  record's serviceId keeps the parent catalog id\n- test/mcp-service-catalog.test.ts settles the theme's cli-highlight preload\n  in beforeAll (deterministic fix for the pre-existing initTheme fire-and-forget\n  teardown race, evidence in ENG-6108 notes); ServiceCatalogPickerComponent\n  gains title/subtitle/hideSearch options for the account listing\n\nCatalog commits f8a4cf61a -> 50b79c3af -> be7445c3c integrated via authorized\nlocal cherry-picks; no catalog-source files modified.\n\nTests: manager 31 (alias integrations/provider lifecycle, demand-driven unbound\nrecord, reconciliation), service-catalog 29 (resolver, candidates, allocator),\nactivation-queue 9 (stdio management, add-account), probe 7, store 6, picker 4,\nregression 2, slash-commands 18 — 105/105; npm run check EXIT=0; 10/10\nconsecutive scoped runs with zero unhandled rejections, exit 0 each.\n\n* mcp: generic discovery surface, drop linear/notion wrappers (ENG-6108)\n\nAdd a bounded discovery surface to the kernel MCP module:\nlist_plugins, search_plugins, list_connections, search_tools and\ndescribe_tool, backed by host-owned catalog/connection handlers,\nwith cursor-safe tools/list pagination, explicit search scopes and\ndefensive secret scrubbing of inventory metadata only.\n\nReplace the bespoke Linear/Notion Python wrapper packages with one\ngeneric bundled mcp skill; remove the McpIntegration base class after\nauditing consumers, moving its shared helpers into rlm.mcp. Connecting\na service is a user action (/plugins or /mcp login), never an install\nor a per-service Python module.\n\n* mcp: fail-closed tool discovery, isolated schemas, redacted inventory errors (ENG-6108)\n\nFollow-up to 6514cbe6f per review:\n\n- discover() now publishes a tool map only when tools/list pagination\n  completes; a repeated or malformed continuation cursor, or exceeding\n  the page cap, raises McpDiscoveryError instead of a silent partial\n  inventory. Malformed cursors are rejected rather than read as done.\n- list_tools/describe_tool return deep copies, so caller mutations can\n  never reach the cached canonical schemas.\n- Per-connection search failures report a fixed exception type + hint\n  (McpCredentialsUnavailable and friends) instead of raw exception text;\n  host_request error text echoed by inventory calls is scrubbed of\n  credential-bearing URLs, query strings and auth headers and bounded.\n\n* mcp: never chain raw host errors in inventory wrappers (ENG-6108)\n\nFollow-up to ff738187e per review. _host_inventory raises a fixed\n\"MCP <request-type> request failed/timed out\" wrapper outside the\nexception handler, so arbitrary host/bridge error text (which can\nembed credential-bearing URLs, query strings, headers and HTTP\nbodies) is never echoed and cannot be reached through __cause__ or\n__context__ either; format_exception prints stay secret-free. The\nnow-unused redaction regex helper and bound constant are removed.\n\nRegression uses traceback.format_exception, not only str(exc), to\nassert the original exception is fully absent. Skill updated for the\nhost status vocabulary (pending, verified handshake) and PluginView\nfields (setupHint, unverified, verifiedAt/toolCount, connectionIds).\n\n* fix(coding-agent): bound MCP probe lifetime and connection-store races (ENG-6108)\n\nRoot review fixes on the lifecycle lane:\n\n- probeMcpEndpoint: the SDK passes its own controller's signal to every\n  fetch (including the cleanup DELETE and its body cancel), and the SDK\n  request timeouts only race the JSON-RPC promise, so an unresponsive\n  DELETE could hang the probe forever. One lifecycle AbortController now\n  bounds the probe: a fetch wrapper merges its signal into every\n  transport fetch, terminateSession/close are each raced against a\n  cleanup grace deadline whose expiry aborts the signal, an absolute\n  deadline timer plus a final abort end lingering body reads, and every\n  timer is cleared. Failure categories stay fixed and safe.\n- McpConnectionStore: the pre-lock exists-then-write-empty create could\n  rename an empty file over records another process just wrote; the file\n  is now created exclusively (wx, never truncating) before the canonical\n  realpath lock, with mode 0600. A failed atomic write no longer drops\n  queued mutations: the batch is unshifted back to the front of the\n  queue and retried by the next flush (ops are idempotent; verify\n  guards re-evaluate under the lock).\n- MCP_PROBE_ERRORS gains UNBOUND_CREDENTIAL (\"credential-unbound\") for\n  grants not bound to the endpoint, consumed by the service catalog.\n\nOffline regressions: never-returning cleanup DELETE, hanging response\nbody, exclusive first-create race with mode 0600, injected atomic-write\nfailure with in-order retry and stale-guard discard, plus the existing\nsuites. All fetch stubs; no live credentials or provider calls.\n\n* test(coding-agent): multi-PID first-create regression for MCP connection store (ENG-6108)\n\nRoot review follow-up: in-process instances cannot reproduce the\nfirst-create exists/write race because their pre-await work is\nserialized on one event loop. The store test file now also spawns four\nreal first-writer processes (temporary .mts worker imported through the\nproject tsx loader, no production entry point), aligned by ready\nmarkers + a file barrier, racing the first create and the locked flush\non the shared store path. Asserts distinct PIDs, all children exit\ncleanly, every record survives, and the file keeps mode 0600; children\nare terminated in a finally on every path.\n\nTest-only: no production files touched.\n\n* test(coding-agent): Windows-portable multi-PID store regression (ENG-6108)\n\nTest-only portability follow-up: the generated first-create worker\nimported the store module by resolved absolute OS path, which is not a\nvalid ESM specifier on Windows; it now imports by file URL, and the\nexact 0600 mode assertions are POSIX-only (Windows mode bits do not\nmap meaningfully). No production changes.\n\n* test(coding-agent): add service-safety adversarial regressions for MCP credentials and providers (ENG-6108)\n\nAdversarial regression suite for the ENG-6108 service-catalog safety\ncontract, red on the 4bd8abc12 baseline and green on the wave-2 fixes:\n\n- Credential binding before probe/token access: a stored credential bound\n  to a different endpoint, or unbound, is rejected before any probe call\n  and before authStorage.getApiKey - for user-declared servers and\n  catalog services, through direct verifyConnection and the demand-driven\n  mcp.list_plugins background verification; never a connected record.\n- Cross-client stale probes: two AuthStorage instances share one\n  auth.json; a probe finishing after a second client logs the grant out\n  or replaces it mid-flight must not persist a connected record or\n  verifiedAt for the current grant.\n- OAuth provider lifecycle: a full OAuth registry reset (through the\n  real createAgentSessionServices + modelRegistry.refresh seam)\n  preserves non-bundled catalog providers, and removing a user override\n  restores the catalog provider after one refresh.\n\nOffline-only: injected probes, denied fetch, per-test temp credential\nand connection stores, no live endpoints or real credentials.\n\n* fix(coding-agent): durable account reservations, per-account views, honest actions (ENG-6108)\n\nFinal-review wave 4:\n\n- Account allocation is a durable reservation under the connection-store file\n  lock: reserveConnectionId applies atomically on disk (exactly one winner in\n  a cross-process race; the loser allocates the next id), pending markers are\n  visible to every client, and removeReservation is ownership-validated (id +\n  still-pending + same createdAt) so a late callback never removes or resurrects\n  another client's account. Allocation consults store records, credentials,\n  configured user servers, and catalog ids; configured names are never taken.\n- Views aggregate every account of a service: connectionIds lists all accounts,\n  each account's status reflects its own bound credential, the service card\n  survives on a remaining account after the default disconnects, and the\n  inventory emits one row per account (no phantom primary row). Alias account\n  ids are searchable (search_plugins alias contract). Connections whose local\n  catalog source vanished keep a pinned descriptor at the recorded endpoint —\n  credentials are never retargeted.\n- Explicit state actions: pending accounts retry verification without a\n  relogin (the \"retry from /plugins\" path works), error accounts keep\n  Reconnect (catalog and user rows), each account gets an explicit Remove\n  row, and a verification result that could not be saved reports pending —\n  never a false Connected.\n- resolveMcpServiceCatalog isolates local-source failures per source: one\n  unreadable or invalid file becomes a bounded visible diagnostic while the\n  built-in catalog and every other source keep resolving.\n\nTests: two-client simultaneous reservation race with barrier, ownership\nvalidation, full add-second -> reload -> inventory -> disconnect-default ->\nsecond-still-manageable regression, per-account view aggregation, vanished-\nsource pinning, per-source failure isolation, state-based action tests, and\nallocation that skips configured ids.\n\nOwnership: bootstrap.ts untouched (delegated lane).\n\n* fix(coding-agent): require MCP discovery methods in the kernel ready check (ENG-6108)\n\nThe runtime ready check only asserted mcp.list_tools/mcp.call_tool; the\nfive new discovery methods were validated once by the bootstrap import\nscan, so a cached kernel venv with an old prime-agent-runtime could\npass readiness. The check now requires callables for list_plugins,\nsearch_plugins, list_connections, search_tools and describe_tool, and\nfails with an actionable message so the venv is rebuilt instead of\nsilently reused.\n\nRUNTIME_READY_CHECK is exported so the new regression executes the\nexact shipped check against a real project runtime: it accepts the\ncurrent runtime, and rejects a runtime simulated as old by deleting\neach discovery method in-process (not a text-grep test). No provider\ncalls, credentials, or real daemon involved.\n\n* fix(coding-agent): guarded account credential commits and computed account status (ENG-6108)\n\nFinal-review wave 5:\n\n- Reservations resolve only after the durable record write COMMITS: the\n  store defers reserve/remove/finalize callbacks past writeFileAtomicSync,\n  resolves them false on write failure, and drops the one-shot ops instead\n  of requeueing them — a failed write can never produce a ghost reservation\n  a login could start on (injected-write-failure regression: no marker, no\n  requeue surprise, retry works)\n- Ownership is an opaque random attempt nonce (not createdAt): cancel and\n  the NEW successful-commit guard both validate it under the same store\n  lock. Add-account logins stage the OAuth credential under\n  mcp:<id>--<attempt> and move it to the real account key only inside a\n  guarded finalizeAttempt commit — a late login success after remove or\n  replacement discards the staged credential and never touches the\n  account (regressions: late-success-after-remove and same-id-new-owner,\n  both assert the final credentials)\n- Per-account status is one computed helper (accountStateFor): credential\n  binding, expiry, and the record combine through httpConnectionStatus, and\n  the plugin aggregate, connection inventory, and account picker all use\n  it — previously-connected records with unbound, retargeted, or\n  expired-no-refresh credentials report Reconnect everywhere (6\n  regressions across default and alias accounts)\n- Catalog metadata aliases ride the view DTO and are searchable again\n  (regression: an alias absent from label/id/description matches)\n- Vanished-source pins are their own trust path (never localSource trust;\n  never one-click connectable)\n\nTests: 147/147 across 10 files; npm run check EXIT=0; 10/10 consecutive\nscoped runs with zero unhandled rejections, exit 0 each.\n\n* fix(coding-agent): exactly-once account transactions and locked disconnects (ENG-6108)\n\nFinal-review wave 6 (transaction issues):\n\n- Every one-shot store callback (reserve/removeReservation/finalizeAttempt/\n  removeAccount) settles EXACTLY once: deferred callbacks resolve with the\n  commit outcome (not `didCommit && resolve(true)`), losing and throwing\n  branches resolve false inline, one-shot ops are dropped on write failure,\n  and trailing ops in a failed batch can never hang — batched-two-reserves\n  write-failure regression included\n- Account removal runs credential deletion AND record removal under the SAME\n  store lock (new store.removeAccount; disconnect, remove-action, and\n  /mcp logout all use it): a concurrent finalize can never re-add an orphan\n  credential after a disconnect — interleaving regression on real stores\n  covers both orders (remove-then-finalize loses ownership; finalize-then-\n  remove clears record AND credential)\n- finalizeAttempt compensates: if the RECORD write fails after the credential\n  move, the compensate callback runs under the same lock and restores the\n  staged credential (the real key was empty before the attempt), so a failed\n  finalize is all-or-nothing; the flow then releases the reservation and\n  reports honestly — UI regression asserts the real key untouched, staged\n  restored+discarded, reservation released, and the honest message\n\nTests: 151/151 across 10 files; npm run check EXIT=0; 10/10 consecutive\nscoped runs with zero unhandled rejections, exit 0 each.\n\n* fix: honest MCP account recovery edges (ENG-6108)\n\n- removeAccount logs a credential-only integration out even when no\n  connection record exists; outcomes are typed (removed, credential-only,\n  missing, failed) and every UI route maps them honestly.\n- finalizeAttempt registers its rollback BEFORE any side effect: a\n  throwing or partial commit is compensated under the same lock, and a\n  FAILED rollback surfaces an explicit recovery-required state with the\n  credential retained instead of a silent false.\n- the guarded commit refuses to clobber a credential an ordinary login\n  wrote at the account key mid-flight, and the rollback only ever undoes\n  its own write; a bystander credential survives byte-for-byte.\n- one-shot store operations settle cleanly when the file lock itself\n  cannot be acquired; durable operations requeue (pre-splice).\n\n* fix: atomic MCP credential moves and honest partial logouts (ENG-6108)\n\n- staged logins move their credential to the account key with a new\n  disk-authoritative compare-and-set under the auth backend's own file\n  lock: moveStagedCredential (set-if-absent, returns the exact moved\n  credential), restoreCredentialIfAbsent, and removeIfCredentialMatches\n  (exact full-object own check, not access-token equality). A bystander\n  credential written by another process can no longer be clobbered by a\n  get/set race across AuthStorage instances.\n- the finalize compensation restores ours only into an empty staged slot\n  and deletes only its own exact credential from the account key.\n- removeAccount now reports \"logged-out\" when the credential logout\n  committed but the record save failed: the logout is preserved, the UI\n  wording says so and never claims the account is still connected; plain\n  \"failed\" wording is state-neutral.\n- two-real-storage-instance regressions: a bystander login written after\n  staging survives byte-for-byte; a generic /logout in another client\n  before/after the finalize races atomically (last-writer-wins under the\n  backend lock, record shows an honest unbound state); an injected\n  record-write failure after the logout reports the honest partial state.\n\n* fix: disk-verified MCP logouts and logout-cancelled login attempts (ENG-6108)\n\n- the three removeAccount authCleanup paths now use removeVerified\n  (extended to return whether a credential was actually removed from\n  disk): a failed auth-file write can no longer report Removed/\n  Disconnected while the credential persists; the honest \"failed\"\n  wording is state-neutral.\n- a real generic /logout of an MCP account now cancels that account's\n  pending login attempts: runLogout calls the new\n  ProviderAuthFlowsHost.onMcpCredentialRemoved hook, and the host\n  invalidates the pending reservation under the connection store's lock\n  (new invalidatePendingAttempts), so a stale in-flight OAuth attempt\n  resolves denied and can never re-activate the logged-out account.\n  Non-MCP logouts are unchanged.\n- regressions: auth-file write failure with a fresh disk reader (the\n  credential survives, nothing claims success), a route-exact\n  cross-client pending-finalize vs real /logout test driven through the\n  selector, store-level invalidation semantics, and stale\n  interactive-mode-status fixtures repaired to the current seams.\n\n* fix: one shared store-locked MCP logout op for the generic /logout route (ENG-6108)\n\n- the route delegates the ENTIRE MCP logout before touching auth: the new\n  exported logoutMcpAccount(providerId, store, authStorage) performs\n  verified credential deletion (removeVerified) AND pending-attempt\n  cancellation in one store-locked removeAccount with the new\n  preserveCompletedRecord semantics (pending attempts cancelled,\n  completed records kept for the honest unbound/Reconnect state).\n- removeAccount now runs the verified cleanup BEFORE mutating the\n  working records map: a failed auth-file write resolves \"failed\" with\n  the record intact in memory AND on disk (no half-applied deletion),\n  and a partially-saved logout still reports the honest \"logged-out\"\n  state.\n- the id resolution is exported as resolveMcpAccountLogoutTarget:\n  exact ids win (service ids may contain \"--\"), and staged keys map\n  back only through their actually recorded attempt nonce.\n- regressions: a barrier test fires the REAL generic route inside the\n  finalize's locked commit (verified deterministically red against the\n  old logout-first ordering); store-level half-applied-deletion and\n  preserve-semantics tests; route delegation/wording tests; handler\n  tests for double-hyphen ids, staged-key mapping, and preservation.\n\n* fix: fail-closed refusal for stale staged-key MCP logouts (ENG-6108)\n\n- a staged-key logout that races a completing finalize now refuses\n  fail-closed instead of orphaning the moved credential: the shared\n  handler resolves the account from CURRENT records and CURRENT on-disk\n  auth state under the store lock (never a pre-lock cache snapshot), and\n  when the staged credential already moved onto the account key it\n  returns \"refused\" — the record and the newer credential both survive,\n  and the route reports the completed login explicitly instead of\n  claiming Logged out.\n- new removeAccountForProvider store op (one critical section: resolve\n  under lock -> disk-verified refusal checks -> verified cleanup ->\n  cancel pending / preserve completed); resolveMcpAccountLogoutTarget\n  now returns a stale variant for nonce-matched non-pending records.\n- new disk-authoritative AuthStorage.hasVerified existence check used\n  for the current-state refusal decisions.\n- regressions: the staged-key race queued behind a finalize-first move\n  (refused, record + credential survive), resolver stale semantics, and\n  the route-level refused wording.\n\n* fix: staged-key MCP logouts cancel the attempt and preserve the account shell (ENG-6108)\n\n- removeAccountForProvider no longer gates record deletion on an auth\n  existence snapshot (not atomic with another client's ordinary login):\n  a staged-key logout removes only the staged credential, INVALIDATES the\n  attempt nonce on the pending record (so the in-flight login's denied\n  path can neither finalize nor removeReservation-delete it), and\n  PRESERVES the account record — deletion stays the explicit Remove\n  action's job; a bystander credential on the real key can never be\n  orphaned.\n- the \"refused\" outcome is now state-neutral (\"This login attempt is no\n  longer current; manage the account from /plugins\") — no Logged out or\n  Connected claim from token presence; failed verified auth deletion\n  still changes no record.\n- the interim AuthStorage.hasVerified helper is removed (no auth-state\n  snapshot decisions remain); regressions pin the both-exist contract\n  (staged removed, bystander byte-for-byte, record + nonce-invalidated\n  shell preserved, old-nonce finalize denied, removeReservation no-op)\n  and the finalize-first race with the same invariants.\n\n* feat: one guarded connect operation for every MCP OAuth login route (ENG-6108)\n\n- new one-shot store ops claimConnectionId/releaseClaim: a guarded login\n  claims an EXISTING account record (any status) under the store lock and\n  cancel releases it — the record, its status, and any credential survive\n  untouched; finalizeAttempt ownership is now the EXPLICIT nonce on any\n  record status.\n- every user-facing MCP OAuth login (initial connect, error-state\n  reconnect, add account, /mcp login, generic /login service options,\n  config menu) routes through the guarded flow: claim/reserve, staged\n  OAuth, guarded finalize. The raw dialog remains internal.\n- the finalize commit is a full-identity compare-and-swap on the auth\n  backend lock: set-if-absent for fresh accounts, replace-only-if-matching\n  for intentional replacements (reconnects and credential-only legacy\n  grants); it consumes the nonce and marks the record pending-verification\n  so an old Connected status never carries onto a replaced grant; the\n  compensate RESTORES the previous credential (never delete-only, never\n  clobbering a newer writer).\n- every preserving logout clears the ACTIVE claim nonce regardless of\n  record status, so a logout cancels an in-flight reconnect too; a nonce\n  match in the resolver is always a LIVE attempt (finalizes consume\n  nonces, so the stale variant is gone).\n- new AuthStorage primitives: getVerified (disk-authoritative identity\n  capture) and replaceStagedCredential / replaceCredentialIfMatches\n  (full-identity CAS move and restore).\n- regressions: error-state reconnect (CAS, pending-verification, nonce\n  consumed, old verification state cleared), cancelled reconnect\n  preservation, late-reconnect-after-logout discard, claim/release one-shot\n  settlement on failed batch writes, rollback-restores-previous via CAS,\n  and the generic /login + config-menu delegation to the guarded hook.\n\n* fix: preserve MCP login intent and cancelled account settings (ENG-6108)\n\n* test: cover MCP account lifecycle commit safety (ENG-6108)\n\n* fix: merge-main regressions and secret-free grant binding (ENG-6108)\n\n* fix: fail closed on unproven MCP catalog entries and expired grants (ENG-6108)\n\n* fix: keep built-ins in the catalog cap and harden grant-type regressions (ENG-6108)\n\n* fix: match MCP connectors to the inline configuration pickers (ENG-6108)\n\n* fix: make MCP picker actions match settings-backed targets (ENG-6108)\n\n* feat(ai): complete the generic MCP OAuth engine (ENG-6108)\n\nThe MCP OAuth engine only handled public-client dynamic registration and\nexact endpoint/protected-resource matches: it discarded all registration\nresponse fields beyond client_id, requested every AS-advertised scope,\nissued unbounded uncancellable requests, and rejected the official\nNotion/Slack metadata shape (pathful endpoint, origin-level PRM resource)\nat discovery, so those servers could not log in or refresh at all.\n\nThe engine now follows the SDK 1.30 auth standards via pure helper/schema\nimports from @modelcontextprotocol/sdk (never the auth() orchestrator,\nwhose redirect model does not fit the staged consent UI):\n\n- Client auth-method negotiation (client_secret_basic > post > none,\n  DCR hint honored, RFC 8414 defaults) applied to exchange and refresh,\n  with a compatibility gate: a secret-only server never receives a doomed\n  no-auth request; it fails early with typed setup guidance.\n- Full RFC 7591 registration responses: persisted DCR client identity,\n  issued secret and expiry (respected on refresh), and registration-mode\n  binding. Config-supplied secrets are never persisted or embedded.\n- CIMD/SEP-991: a configured Prime-controlled client-metadata URL becomes\n  the client id when the server advertises\n  client_id_metadata_document_supported; no URL is invented or deployed.\n- SEP-835 scope precedence: configured > protected-resource > omitted;\n  authorization-server-wide scope lists are never blindly joined.\n- Narrow audience policy: the PRM resource must equal the canonical\n  endpoint or its exact HTTPS origin (URL-component compared); refresh\n  pins both values and the audience mode, fail-closed on any change, and\n  legacy exact grants never refresh against origin audiences.\n- Every request is bounded (10/15s deadlines, 256KiB bodies) and login\n  honors the host abort signal, including callback-server cleanup.\n- Token errors are typed and sanitized: whitelisted RFC error codes only,\n  fixed guidance, never raw server-controlled descriptions.\n\nAll flows run against offline fake OAuth/MCP servers in\npackages/ai/test/mcp-oauth.test.ts (39 tests: official Notion/Linear\nfixtures, Slack post-only negotiation, CIMD, refresh binding and\nrotation, abort/cancellation); no live endpoints or credentials.\n\n* feat(ai): read-only catalog metadata audit with readiness evidence (ENG-6108)\n\nAdd a reproducible read-only public metadata audit of all 103 remote catalog endpoints (public unauthenticated GETs only, bounded, DNS-pinned per request through an undici dispatcher lookup) and merge the committed evidence into the catalog offline. New additive, optional interface: setup.readiness (informational, never a Connect gate), setup.requirement, setup.fields[].kind, auth.alternatives[] per-path alternatives, and the observational auth.metadata evidence block. Placeholder-only OAuth blockers are cleared with evidence (Airtable, Shopify stay Connect-attemptable); genuine documented requirements stay hard (API keys, bearer tokens, tenant config, registered clients, transport and local-runtime limits). CIMD alone is never oauth-ready, audience-mismatched PRM documents stay unknown with notes until the approved engine audience policy lands, and local sources cannot self-assert readiness, alternatives or evidence.\n\n* docs(ai): correct stale oauth-marker consumer comment (ENG-6108)\n\nThe host keys OAuth support off authStrategy, not entry.oauth?.kind; the comment now points consumers at auth.strategy. Comment-only change.\n\n* fix(coding-agent): guard mcp account ownership and capability policy (ENG-6108)\n\n* fix(ai): adopt engine component comparison for readiness re-derivation (ENG-6108)\n\nThe importer audience rule now uses the engine component comparison: a protected-resource document must match the exact canonical endpoint or the exact origin (root-slash normalized). notion plus the 9 DCR-capable origin-mismatched entries (airtable, amplitude, appwrite, lovable, miro, rootly, vercel, windsor-ai, zoominfo) re-derive to oauth-ready and their stale not-yet-landed notes are gone; logrocket stays unknown (its resource drops the ?toolsets=all query, failing closed under the component rule); slack and hubspot stay unflipped (no dynamic client registration). Counts re-derive to 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown. Catalog oauth validation now rejects client secrets explicitly instead of silently dropping them, symmetric with the client-id rejection.\n\n* feat(coding-agent): wire oauth client identity through shared mcp provider factory (ENG-6108)\n\n* fix(ai): mirror engine PRM selection in the metadata audit (ENG-6108)\n\nBugbot PRRT_kwDOSXZbXs6hvVZP + PRRT_kwDOSXZbXs6hvVZS: auditEndpoint now mirrors oauth.ts exactly - a WWW-Authenticate resource_metadata pointer is followed alone and any failure fails closed with no well-known fall-through; absent a pointer the pathful well-known is tried then the origin-level root location (SDK parity, 4xx continues); a candidate is selectable only when its document passes the engine audience component comparison and carries authorization servers. protectedResourceUrl is used at the call site instead of an inline construction. The bounded read-only audit was re-run (public GETs only, DNS-pinned, all bounds unchanged) and readiness re-derived: the reviewer obligation flips stay intact; codspeed and resend flip to oauth-ready via the SDK-parity origin-level fallback (valid documents, DCR, coherent AS); confidence-docs/-flags stay unknown with fail-closed notes (served-but-invalid documents); logrocket stays unknown with the precise fail-closed reason; slack/hubspot stay unflipped (DCR-less); shopify metadata is now available but DCR-less. Counts: 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown; metadata 97 available / 6 unavailable.\n\n* fix(ai): require the exact engine fallback condition for oauth-ready (ENG-6108)\n\nBugbot PRRT_kwDOSXZbXs6hva2k: evidenceSupportsStandardOauth granted oauth-ready via origin-AS evidence for ANY no-served-JSON state, but the engine reaches its origin-level AS fallback ONLY when no resource_metadata pointer was followed and every tried well-known candidate returned exactly a 4xx (5xx, fetch errors, 2xx/3xx non-JSON bodies and served-but-invalid documents all throw with no fallback). A precise engineFallsBackToOriginAs predicate is now derived from the recorded attempts (followed or rejected pointer, served document, and per-attempt httpStatus), so fail-closed discovery stays honestly unknown. The audit script selectionNote now fires only for true fail-closed states; the all-4xx state is the engine honest fallback and records no note. The bounded read-only audit was re-run to match the corrected note semantics (aggregates stable: 103 audited, AS 97/6, DCR 78, CIMD 25, PKCE 97). Zero readiness flips - pure hardening; 7 all-4xx entries lose stale generic notes; new regression assertions pin intercom (oauth-ready via the legitimate origin-AS fallback, no note) and adobe-for-creativity (unknown, unavailable AS, no note). Counts unchanged: 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown.\n\n* fix(ai): classify figma as registered-client after live DCR 403 evidence (ENG-6108)\n\nDogfooding PR #2256 head 8e77f0cc1 surfaced what the read-only audit could\nnot observe: Figma's advertised dynamic-client-registration endpoint returned\nHTTP 403 to the engine's anonymous registration POST during a real\n/mcp login figma attempt (2026-09-13), while its AS metadata still advertises\nthe endpoint with confidential-only client auth. A public metadata-only GET\nof the register endpoint returns 404, and public reports corroborate the 403\nfor anonymous DCR requests; whether self-registered Figma apps can obtain\nmcp:connect is publicly unresolved.\n\n- Audit store: the live attempt is recorded as an authorizationServer\n  registrationAttempt block with explicit provenance (the audit script never\n  POSTs registration endpoints); the script now preserves these blocks\n  verbatim on re-runs, and the $comment sanctions exactly this supplement.\n- Importer: an advertised registration endpoint whose live anonymous\n  registration was rejected (401/403) is gated evidence —\n  auth.metadata.dynamicClientRegistration flips to an explicit false (gated,\n  distinguishable from omitted \"not advertised\"), the gated finding becomes\n  the default metadata note, and the entry can never be oauth-ready\n  (fail-closed, the same honest class as DCR-less Slack/HubSpot).\n- overrides.json: figma mirrors the Slack precedent — pre-registered client,\n  registered-client requirement, prime-restricted readiness, requires-setup\n  with the 403-documented reason and FIGMA_MCP_CLIENT_ID / FIGMA_MCP_CLIENT_SECRET\n  setup fields.\n- Regenerated catalog.json + catalog.data.generated.ts via the importer;\n  counts: ready 82 -> 81, requires-setup 58 -> 59, oauth-ready 72 -> 71,\n  prime-restricted 5 -> 6 (user-setup 53, unknown 10 unchanged; sum 140).\n\nOffline verification: catalog suite 25/25, coding-agent catalog eligibility\n12/12, tsgo --noEmit clean, and both catalog scripts typechecked under the\nrepo base config.\n\n* drop the revert changelog fragments\n\nthe reland makes the \"removed\" entries moot before any release cut them;\nthe release notes should only describe the additions.\n\n* feat(ai): cut the service catalog to zero-app self-serve only (ENG-6108)\n\n2026-09-14 product decision: Prime maintains ZERO provider OAuth apps, so\nthe catalog advertises only what works self-serve — dynamic client\nregistration (readiness \"oauth-ready\") or user-supplied tokens/keys\n(\"user-setup\"). Every entry classified prime-restricted (needs a\nprovider-registered client) or unknown (no verified self-serve path) is cut\nfrom the shipped catalog; audit/engine parity, the readiness vocabulary and\nthe fail-closed classification machinery are unchanged.\n\n- overrides.json: the 16 cut providers (figma, gmail, google-calendar,\n  google-drive, mongodb-atlas, slack, adobe-for-creativity,\n  confidence-docs, confidence-flags, hubspot, logrocket, mapbox-docs,\n  shopify, sumup, synthflow, synthflow-docs) are excluded via the documented\n  excludedServers list — one entry per upstream record (18 keys: figma and\n  slack are merged from both upstreams, so both sides are cut and no ghost\n  entry can re-enter), each with a per-entry reason citing the decision and\n  the specific audit evidence. The now-dead servers overrides for excluded\n  identities were removed; their honesty content lives on in the exclusion\n  reasons.\n- Importer: the cut is enforced structurally — buildCatalog refuses to emit\n  an entry whose readiness classifies prime-restricted or unknown and fails\n  with a curation prompt (exclude with a documented reason, or curate\n  readiness with evidence), so an unverified provider can never ship\n  silently again. The gated-DCR honesty machinery (advertisedRegistrationGated,\n  explicit-false dynamicClientRegistration semantics) is kept and now\n  exported for direct unit tests, since the live case (figma) is excluded\n  rather than classified; the predicate still guards future entries.\n- Audit store: untouched — the pinned source snapshots and metadata-audit\n  results for the excluded endpoints stay committed as evidence (including\n  figma's live 403 registrationAttempt). The audit script now also retires,\n  never drops, registration-attempt evidence for servers that leave the\n  audit target set via the new top-level retiredRegistrationAttempts array,\n  so a re-run can never silently delete the figma evidence.\n- Regenerated catalog.json + catalog.data.generated.ts via the importer;\n  counts: total 140 -> 124 (http 102 -> 86; stdio 32, templated 5, sse 1\n  unchanged), ready 81 -> 71, requires-setup 59 -> 53, oauth-ready 71,\n  user-setup 53, prime-restricted 6 -> 0, unknown 10 -> 0 (sum exact).\n- Tests: mcp-catalog.test.ts now asserts the cut (all 16 ids absent, both\n  upstream sides of merged providers excluded, all 18 keys documented in the\n  import report with zero-app reasons, source snapshots and audit evidence\n  kept incl. figma's 403 attempt), pins the gated-DCR machinery directly\n  with synthetic evidence, updates the count assertions (124/71/53/0/0) and\n  keeps the byte-for-byte regeneration pin; the figma assertions now assert\n  exclusion instead of prime-restricted-in-catalog.\n\nOffline verification: catalog suite 27/27, coding-agent catalog eligibility\n12/12 (plus all 13 coding-agent mcp test files: 281 passed, 1 skipped),\ntsgo --noEmit clean at the repo root, both catalog scripts typechecked\nclean under the repo base config, biome clean on the changed files.\n\n* test(coding-agent): adapt activation-queue route host to the inline auth panel host surface\n\n* test(coding-agent): drive logout route assertions through the inline auth panel surface\n\n* fix(ai): demote confidential-only AS providers to the user-setup OAuth path (ENG-6108)\n\nLive gap found in dogfooding: Hugging Face /mcp login failed at connect with\n\"no compatible client authentication method (advertised: client_secret_basic,\nclient_secret_post)\" because the catalog classified the entry oauth-ready\nwithout ever checking token_endpoint_auth_methods_supported; the engine checks\nit at runtime and fails closed.\n\n- Extract the engine's fail-closed client-auth decision from\n  negotiateAuthMethod into the exported decideClientAuthMethod and add the\n  catalog predicates tokenAuthMethodsSupportPublicClient /\n  tokenAuthMethodsSupportConfiguredClient in packages/ai/src/mcp/oauth.ts —\n  the importer runs the SAME decision, so classification and the connect-time\n  gate share one source of truth.\n- Wire the gate into importer readiness: coherent DCR evidence with\n  confidential-only advertised methods now demotes honestly to the user-setup\n  OAuth path (requires your own OAuth app reason, registered-client\n  requirement, client-id/client-secret setup fields) instead of oauth-ready —\n  the user's own registered app, zero-app compliant, never an exclusion.\n  Advertised methods that serve not even a configured secret-bearing client\n  (mTLS-only) keep failing closed as today; omitted lists stay oauth-ready\n  per the engine's public-client spec default.\n- Regenerate catalog.json, catalog.data.generated.ts and import-report.json:\n  14 entries demote (airwallex, airwallex-sandbox, atlan, gitlab,\n  hugging-face, legalzoom, lusha, miro, monday-com, planetscale, supabase,\n  vercel, windsor-ai, zoominfo) — readiness counts move 71->57 oauth-ready and\n  53->67 user-setup; total 124 and zero prime-restricted/unknown invariants\n  hold, each entry carrying its confidential-only evidence and note.\n- Document tokenAuthMethods as required engine-compatibility capture in the\n  audit script and catalog README so future audits keep the check.\n- Tests: pin the hugging-face demotion with its confidential-only evidence and\n  the full demoted set, add the synthetic classification matrix\n  (confidential-only demotes, none/omitted stay one-click, mTLS-only stays\n  unknown) and direct predicate tests; update readiness count pins. The\n  byte-for-byte regeneration pin and the coding-agent eligibility thresholds\n  pass unchanged.\n\n* test(coding-agent): pin the MCP auth routes to the inline auth panel surface\n\nthe guarded-credential race test kept an unobserved showOverlay stub on the\nfake route TUI; it now asserts the generic /logout service selector never\nmounts an overlay popup, so MCP auth can only render through showAuthPanel\nlike #2331 provider logins. adds the changelog fragment documenting that\nevery MCP auth surface (guarded staged OAuth dialog, /login and /logout\nservice selectors, mcp-connections tab, /mcp login) mounts inline under\nthe chat with stacked closers, focus restore, and rows-aware sizing.\n\n* feat(ai): cut the catalog to one-click DCR or user token/key only (ENG-6108)\n\n2026-09-15 product decision (\"remove everything that's not one-click auth\nor api key\"): the shipped catalog advertises only one-click dynamic client\nregistration (readiness \"oauth-ready\") and user token/key entries; the\nclassification machinery and audit/engine parity are unchanged.\n\n- overrides.json: the 49 non-token/key entries — the 14 registered-client\n  entries whose authorization servers accept only secret-bearing client auth\n  (airwallex, airwallex-sandbox, atlan, gitlab, huggingface-skills,\n  legalzoom, lusha, miro, monday-com, planetscale, supabase, vercel,\n  windsor-ai, zoominfo), the 32 local-runtime stdio adapters and the 3\n  url-only tenant templates (activecampaign, jfrog, pigment) — are excluded\n  via the documented excludedServers list: one entry per upstream record\n  (64 keys: monday-com/supabase/vercel are merged from both upstreams, so\n  both sides are cut; every stdio server of the multi-server adapter plugins\n  is excluded), each with a per-entry reason citing the decision and the\n  specific evidence. The now-dead servers overrides for excluded identities\n  were removed; their honesty content lives on in the exclusion reasons.\n- Importer: the cut is enforced structurally — buildCatalog refuses to emit\n  a user-setup entry whose requirement is not token/key-shaped\n  (bearer-token/api-key credentials, a tenant config with a genuine non-url\n  field, or a legacy-transport entry that still collects a token/key) and\n  fails with a curation prompt, so a registered-client demotion, a\n  local-runtime adapter or a url-only template can never silently re-derive.\n  The auth-methods honesty machinery (decideClientAuthMethod parity,\n  confidential-only demotion, tokenAuthMethods capture) is unchanged and\n  stays active for the survivors.\n- Audit store and source snapshots: untouched — evidence for the excluded\n  endpoints stays committed as history.\n- Regenerated catalog.json + catalog.data.generated.ts + import-report.json\n  via the importer; counts: total 124 -> 75 (http 86 -> 72, templated 5 -> 2,\n  sse 1 unchanged, stdio 32 -> 0), ready 57 unchanged, requires-setup 67 ->\n  18, oauth-ready 57, user-setup 18, prime-restricted 0, unknown 0 (sum\n  exact); api-key strategy 32 -> 16.\n- Tests: mcp-catalog.test.ts pins the cut (all 49 ids absent, both upstream\n  sides of merged providers excluded, all 64 keys documented in the import\n  report with 2026-09-15 reasons, source snapshots and audit evidence kept,\n  the shipped user-setup set is exactly the 18 token/key entries), keeps the\n  confidential-only machinery matrix (now pinned on the committed\n  huggingface-skills audit evidence plus the synthetic matrix), adds the\n  structural invariant regression (lifting the gitlab exclusion fails the\n  import with the curation prompt), updates the count assertions (75/57/18/\n  0/0) and keeps the byte-for-byte regeneration pin; coding-agent\n  mcp-service-catalog count comment + eligibility sweep thresholds updated\n  for the 75-entry catalog (api_key >= 10 still holds at 16; unknown 53).\n\nOffline verification: ai catalog suite 29/29, ai mcp-oauth 40/40, all 13\ncoding-agent mcp test files 276 passed 1 skipped (catalog eligibility 12/12,\nservice catalog 63/63), tsgo --noEmit clean at the repo root, biome clean on\nthe changed files.\n\n* fix(tui): separate the oauth url from the browser-step text with a blank line\n\n* fix(tui): keep the service-catalog picker at one description line with stable frames\n\n* feat(tui): persist MCP connect outcomes as refinement-style chat entries (ENG-6108)\n\nConnect outcomes (\"Connected Linear (12 tools verified)\" and its\nsaved-but-unverified variants) were transient status lines that vanished;\nthey now persist in the chat transcript like harness refinement notices.\n\n- Add the mcp_connection_outcome custom message with structured details\n  (label, login/retry source, connected/unverified/unsaved verification\n  state, tool count, account id, activation) and the exact legacy wording\n  as its content; keep it out of LLM context like refinement outcomes.\n- Render it with a purple refinementHeader \"◆ Connected <service> · N\n  tools verified\" header over a refinementSummary body via the\n  ExpandableEventMessage base; register live rendering and transcript\n  replay (malformed entries included) and gate both on display.\n- Route both emit sites (pending-account retry verification and the\n  guarded login completion) and their failure/partial variants through\n  completeMcpConnectionOutcome: reload, then append the durable entry via\n  the new AgentConnection.appendCustomMessage (in-process sendCustomMessage,\n  daemon legacy append_custom_message RPC). Mid-turn connects keep the\n  transient \"will activate automatically\" line and record the durable\n  entry at the next safe boundary; a failed reload marks the entry\n  \"not active in this session\". Pre-outcome login failures (eligibility,\n  claim, finalize, incomplete login) remain transient warnings.\n- Focused tests: component rendering/replay, formatter wording parity,\n  and both emit sites including queued-boundary, inactive, and\n  append-failure fallback paths.\n\n* fix(tui): flatten multi-line catalog copy before it becomes a picker line\n\n* fix(tui): repair /mcp picker chrome nits and search ranking (ENG-6108)\n\nFive chrome nits from Kevin's live testing plus the picker search:\n\n- The scroll counter aligns with the row indent (rows render their label\n  at column 2; the counter and the empty-state message now do too).\n- Enter on an accounts-picker row 1 (the account name) re-verifies the\n  account instead of disconnecting it; only the explicit Remove row\n  removes. connectServiceFromPicker's connected branch now re-verifies\n  exactly like the pending branch.\n- One blank line between the last row and the description line in both\n  catalog and accounts mode, budgeted in updateLayout so frames stay\n  height-stable.\n- Accounts search matches identity only (account label + connection\n  id): every account row shares the same description/setup hint, so\n  matching that text could never filter anything.\n- Every inline MenuPanel opens with exactly one separator rule between\n  the chat view and the picker: a titled panel draws the rule above its\n  title; a headerless panel keeps the bordered search's top border as\n  that rule, never both. Model/provider/oauth/extension/prime-team\n  pickers budget the rule through the shared inlineMenuPanelTopRuleRows\n  helper.\n- Search ranking rewritten: exact/prefix/word-start/substring matches on\n  label, service id, and aliases rank far above description/setup-hint\n  text; the identity-only subsequence fallback requires a consecutive\n  run of half the query (minimum two); descriptions match only as\n  word-start/substring. Searching vercel against a catalog without\n  Vercel now yields the No-matching-services empty state instead of\n  eight unrelated rows matched through setup-hint boilerplate.\n\n* fix(mcp): cut non-token catalog survivors and say what to paste\n\n2026-09-16 product decision, from live picker testing: the catalog ships\none-click DCR connectors and simple paste-an-API-key/token services only.\n\nCut 5 survivors with documented per-entry reasons in overrides.json:\n- cockroachdb (cockroach-labs): tenant config, only input is the\n  per-cluster `mcp-cluster-id` header, no key/token field\n- dynatrace, sourcegraph: tenant instance URL next to the token\n- paypal-sandbox: legacy SSE, the runtime cannot connect to it at all\n- render: api-key requirement with zero setup fields, nothing to paste\n\nThe importer now enforces the narrower rule structurally: a user-setup\nentry ships only when its requirement is bearer-token or api-key AND it\ncollects at least one bearer-token/api-key field. An entry the readiness\npass never classified also fails closed instead of slipping past every\nshipping guard.\n\nAll 13 surviving setup reasons are now picker copy for a human: one line,\nstarting with \"paste\", naming the entry's real field. \"requires provider\ncredentials supplied as headers\" and \"requires an auth token supplied via\nenvironment variable\" are gone; github no longer stutters the same clause\ntwice; zoom-meetings drops the upstream placeholder note that never\nchanged what the user does. A test pins the shape.\n\nCatalog: 75 -> 70 entries (57 oauth-ready, 13 user-setup), all plain\nstreamable-http. Evidence, source snapshots and audit store unchanged.\n\nENG-6108\n\n* fix(tui): drop the restated MCP connect body and add disconnect feedback\n\nKevin saw the durable connect entry print the same sentence twice: the\nheader and the body both said \"Connected Granola (6 tools verified)\".\nThe header is the outcome line, so the body now carries ONLY what the\nheader omits - added account, verification issue plus next step, deferred\nactivation - and a plain success renders as the header alone. The\npersisted `content` keeps the full legacy sentence, because the transient\nfallback and status lines still need a whole sentence.\n\nDisconnects had no durable feedback at all. A successful disconnect from\n/plugins, `/mcp logout <name>`, or the generic `/logout` route now leaves\nthe same kind of entry, in the muted theme key: not the connect purple (a\ndisconnect is no refinement) and not the error red (it succeeded) - the\ngrey /plugins already uses for \"Not connected\". Only outcomes that really\nremoved the credential (removed, credential-only, preserved) get an\nentry; \"logged-out\" (partial save failure), \"failed\", \"missing\", and the\nstate-neutral \"refused\" keep their honest warnings and record nothing, so\nno entry can claim a disconnect that did not finish.\n\nThe generic /logout route still runs ONE store op and ONE reload: the\nhost records the outcome under its existing delegation and the selector\nappends it after the reload it already did.\n\nENG-6108\n\n* fix(tui): record the picker disconnect entry on the remove row\n\n* fix(tui): rebuild the /mcp accounts menu as a choice list (ENG-6108)\n\nKevin's live-testing redesign: the accounts menu drops its no-op search box\nand account-name row, renders '<service> MCP' with the muted description\n(wrapped, capped at three lines) above the options, and lists Reconnect /\nDisconnect <id> / Add another account in the PR #2340 selection language\n(mirrored locally until #2340 lands). Reconnect keeps the existing re-verify\npath and never disconnects; Disconnect keeps the store-locked removal and\nits durable disconnected entry.\n\nCatalog picker nits: the Connect trailing status reads in the text colour\ninstead of the accent purple, and the empty state gains one blank row above\nthe shortcuts line, aligned with the row labels (pinned at width 120).\n\n* fix(tui): stop inline pickers doubling the separator rule\n\n* feat(mcp): connect paste-a-key catalog services through an inline masked paste panel (ENG-6108)\n\n* fix(mcp): collapse the paste flow to ONE credential per service, cut named-header pairs (ENG-6108)\n\nTwo Bugbot findings, one root cause: the generic MCP runtime sends exactly\none Authorization: Bearer per connection, but the paste flow treated every\nrequired credential field as a separate mandatory prompt, and GitHub's two\nsetup fields (GITHUB_PAT_TOKEN / GITHUB_PERSONAL_ACCESS_TOKEN) were presented\nas two required tokens when they are alternative names for one PAT.\n\n- Curate GitHub's fields as alternatives via a shared field-level\n  credentialSet (\"github-pat\") in mcp-catalog/overrides.json; the paste flow\n  now prompts ONCE, labels honestly (\"GitHub personal access token\") and\n  stores the value under the first alternative's id.\n- Cut datadog and cloudinary-mediaflows from the catalog (documented\n  excludedServers reasons citing the named-header evidence: DD_API_KEY +\n  DD_APPLICATION_KEY, cld-api-key + cld-secret - one bearer can never\n  authenticate them). Catalog: 68 entries = 57 one-click DCR + 11 paste.\n- The importer now throws when a shipped requires-setup entry collects more\n  than one distinct required credential, so an unmarked multi-credential\n  entry can never silently re-derive; tests pin the guard by lifting the\n  datadog and cloudinary exclusions.\n- Simplify the host flow to one prompt/one value (no multi-field loop, no\n  per-field checkmark rows); masking, Esc-cancels-nothing-stored, the\n  empty-value guard, verification and the durable Connected outcome are\n  kept; services with genuinely distinct credentials stay honest\n  setup_required and are not pasteable.\n\n* fix(mcp): drop the dead paste-credential branch and trim the importer comment\n\n* fix(tui): render paste outcomes honestly and polish the accounts menu\n\n* fix(tui): budget the accounts frame for the trailing blank row\n\n* fix(tui): keep the /mcp picker chain open after connect, disconnect, and paste actions\n\nSelecting a row no longer drops the user back to the prompt after the action: the picker chain re-enters the right surface, rebuilt from the live catalog and connection store. Disconnecting one account reopens that service accounts menu without the removed row; disconnecting the last account, or a cancel that stored nothing, reopens the catalog; reconnect/re-verify, add-account, and paste re-enter the accounts menu with refreshed state. Esc closes the whole chain, and actions blocked before they start (login in progress, guidance, target drift) end the chain with their status line instead of re-opening, so there is no re-entry loop.\n\n* fix(tui): drop the accounts description instead of overflowing tight viewports\n\n* fix(tui): one reconnect/disconnect row per service with an account sub-picker, and left-arrow back to the catalog\n\nA service's accounts menu is now exactly three rows — Reconnect, Disconnect, Add another account — instead of a reconnect/disconnect pair per connection id. With one account, Enter acts on it directly with the existing re-verify and remove semantics. With several accounts, Enter on Reconnect or Disconnect opens a second inline picker in the same choice-list shape that lists the account ids; picking one runs the action on that connection id only, and Esc or left there returns to the accounts menu without acting. The sub-picker never nests deeper, and after an action the existing re-entry table decides the next surface (the accounts menu while an account survives, the catalog otherwise).\n\nLeft arrow from the accounts page now navigates back to the /mcp catalog — the picker chain's parent surface — remounted fresh, using the same app.modal.back binding the dialogs share; Esc still closes the whole chain, and left in the catalog stays inert. The accounts frame budget is unchanged (the option count is the only thing that grows), the budget test now pins the three-row count, and the multi-account re-entry tests drive the sub-picker end to end.\n\n* fix(tui): colour mcp outcome entries by outcome, warning for non-success\n\n* fix(mcp): keep alias OAuth providers behind the parent service catalog classification (ENG-6108)\n\n* fix(mcp): probe the origin-level oauth-protected-resource document without the endpoint query\n\n* test: bring ENG-6108 suites into the main-branch testing policy (#2336)\n\nShrink the branch's test additions from a net 16,514 to 16,610? -> net 11,610\ntest lines (the same as the branch's source additions), clear all 46 new\ntest-policy pattern violations, and consolidate per the policy's \"one file\nper module, regressions live in the owning suite\" rules. No test survives\non a timer, poll, sleep, skip, or env gate; every wait resolves on a\nconcrete deferred signal (mount hooks, probe gates, store flushes).\n\nFolded per-issue regression files into the owning module suites:\n- suite/regressions/eng-6108-inline-picker.test.ts -> the picker-chain\n  describe in test/service-catalog-picker.test.ts (mount/stale/replacement\n  settling, action routing, re-entry, settings-actions freeze, paste flow,\n  blocked actions) with vi.waitFor replaced by ui.setFocus-mount and\n  action-start deferred signals; the pure row-shape/menu layout pins\n  already covered by the component tests were deleted.\n- suite/regressions/eng-6108-service-catalog-activation.test.ts -> the\n  connect-then-activate end-to-end test in test/agent-session-services\n  .test.ts; the stored-token-pending duplicate died (already pinned in\n  mcp-service-catalog).\n\nDissolved test/mcp-account-commit-safety.test.ts; its unique invariants\nmoved to the owning suites and the rest were duplicates:\n- store->auth gap interleave + finalize nonce ownership + no-resurrection\n  -> test/mcp-connection-store.test.ts\n- CAS-absence replaceStagedCredential -> test/auth-storage.test.ts\n- /mcp login on a PENDING account, vanished-source repair (record+grant\n  evidence; bare shell refuses), and the paste-flow seam (single-credential\n  static token, cancelled/empty value, login-in-progress and target-changed\n  refusals) -> test/mcp-activation-queue.test.ts.\n\nConsolidated near-identical seams (surviving test -> invariant it owns):\n- grant-state matrix pinned ONCE in mcp-catalog-eligibility (predicate +\n  prompt + dispatch + view parity); manager's copy deleted.\n- reserved-name ownership pinned at dispatch level in mcp-manager; the\n  view-level copy and mcp-service-safety's provider-lifecycle duplicate\n  deleted.\n- cap protection pinned in mcp-service-catalog (resolver's own module);\n  mcp-catalog-eligibility's copy deleted.\n- remove/logout-vs-finalize races pinned once at the REAL route seam in\n  mcp-activation-queue; the store-level interleave duplicate deleted.\n- exact rendered copy kept only where it is a durable protocol contract\n  (outcome notice wording); component render pins made structural.\n- oauth client-auth negotiation + PRM-mismatch refusals + python discover\n  cursor/table families -> it.each/subTest tables.\n\nViolation conversions (all 46 cleared):\n- wall-clock-timer/poll/sleep: setFocus-mount signals, action-start\n  deferreds, queueVerifyResult+flush chains, an asyncio.Event hang, and\n  fs.watch for the multi-process ready barrier.\n- environment-gated-path: the 11 false positives in mcp-oauth (mock route\n  conditions carrying token/credential substrings) renamed via aliases;\n  the rest made unconditional.\n- explicit-test-timeout: allowed with policy comments only where the\n  probe's own timeout bound IS the behavior under test (probe hang tests,\n  real multi-process spawn).\n- conditional-or-disabled-test: kernel-bootstrap made unconditional\n  (file-scoped venv resolution, no cwd dependence; merge of main's #2336\n  had dropped the branch's theme bootstrap in menu-panel too - restored).\n\nVerified: every modified suite passes standalone and under 6 shuffle\nseeds; npm run check (biome + check:test-policy + tsgo + installer +\nbrowser-smoke) is green; spot-reverts of the chain re-entry rule and the\nstore finalize-ownership guard both fail the consolidated tests.\n\n* fix(mcp): mirror the engine audience rule and first-issuer selection in the audit\n\n* fix(mcp): fail closed on a malformed advertised issuer and fix the notion URL substring check"},{"name":"prompts","kind":"directory","size":0,"lastCommitHash":"e5f052c63af15817e86a4862789d0e08982d4878","lastCommitWhen":"2026-09-17T12:13:45+03:00","lastCommitMessage":"refactor(coding-agent,tui): call the feature a pasted file, one line and no hash\n"},{"name":"refinement","kind":"directory","size":0,"lastCommitHash":"348df40d4f355e1b1774dcb5c64c6eb05c8040ec","lastCommitWhen":"2026-09-17T13:19:59+03:00","lastCommitMessage":"feat(coding-agent): curate restored state, frame heartbeats, and add violation counters\n"},{"name":"tools","kind":"directory","size":0,"lastCommitHash":"6b8fbd8b0831e14a085634ea8a395b60d8041c3b","lastCommitWhen":"2026-09-17T20:40:32+03:00","lastCommitMessage":"fix(coding-agent): harden kernel bootstrap lock, staging checks, import isolation and postinstall\n"},{"name":"agent-messages.ts","kind":"file","size":21342,"lastCommitHash":"2de5e72f0ad04bbdbde470ea9eb57907ec80d14d","lastCommitWhen":"2026-09-17T07:03:07+03:00","lastCommitMessage":"fix(coding-agent): pin the child cwd, harvest silent children, backpressure fan-in (R4, R11, R10, R9)\n\nR4 - children defaulted to whatever the host happened to pass, so recursive\nsearches walked multi-TB caches and froze kernels for 21 and 92 minutes\n(01a09d7f, 01a09bf6, 01a09351). `CreateRlmSubagentRuntimeOptions` now carries\nan explicit `cwd`, the parent always sets it to its own session directory, and\nboth runtime hosts and the inline path use it instead of reaching into the\nparent session. Proof: test/suite/subagent-cwd-propagation.test.ts.\n\nR11 - 11 consecutive children exited without replying (01a09782) while parents\nwaited on fan-in that never came. A child that finishes with zero\n`agent_message.send` calls now hands its last assistant text to the parent as\n`[auto-harvested fallback from <name>]`, tagged as unreviewed, with an empty\nchild still getting the plain no-reply notice. The reply obligation also moved\ninto the task envelope and the child doctrine, where a child cannot miss it.\nProof: test/suite/subagent-reply-harvesting.test.ts.\n\nR10 - fan-in hit a hard 20-pending ceiling and threw at the exact moment\nresults arrived (01a09d35). The ceiling is now soft (200) and admission never\nfails on it: the message buffers in memory, and the daemon yields up to 30s for\na saturated recipient to drain before delivering anyway. The throwing\n`assertAgentMessageQueueCapacity` helper is gone; the two tests that asserted\nthe old fatal cap now assert the resilient behaviour. Proof:\ntest/suite/agent-message-backpressure.test.ts (35 concurrent senders, zero\nrejections).\n\nR9 (host half) - the worker forwarded PATH alone to a session it created, so\n`cargo`/`nix` were missing under a GUI- or launchd-started daemon (01a09746\nexit 127). The worker now forwards the launching shell's environment, which the\nsupervisor already seeded it with.\n"},{"name":"agent-observe.ts","kind":"file","size":6585,"lastCommitHash":"4f4d51c5b5e1d29a95ac0391556898910e1e01c7","lastCommitWhen":"2026-09-10T19:15:36+02:00","lastCommitMessage":"fold the twin agent rosters into one (#2153)\n\n* fold the twin agent rosters into one\n\nFamily discovery had two entry points: agent_message.list_agents listed the\nnuclear family including members that were only on disk, while\nagent_observe.list_agents listed live sessions plus passive subagents. Neither\nwas a superset, so an agent had to call both to know who it could reach.\n\nagent_observe.list_agents is now the single roster. It is built from the family\ncatalog that send() already uses to resolve receiver_role and receiver_name, so\nmembership has one definition. Entries carry the distinction as data: a member\nwith no live session here has no activeSessionId, keeps status \"inactive\", and\nreports only persisted facts, while live members keep their runtime detail.\nEvery entry carries its relationship, so a roster row maps directly onto a send.\n\nagent_message.list_agents is gone from the skill module and the docs; its host\nrequest now fails with a message naming agent_observe.list_agents, so an old\nkernel or a copied old transcript self-corrects.\n\nFixes RES-1335\n\n* correct the observe read scope and order the roster snapshot\n\nThe observe skill doc claimed transcript reads never work on inactive members;\nthe daemon hydrates a passive child on demand, so only root siblings in another\nworker are unreadable.\n\nBuild the resident-session map after the family catalog resolves, so a session\nthat becomes resident during the catalog's disk and supervisor IO is still\nreported with its live fields.\n\n* bound roster previews and keep peer rows honest\n\nA saved root's first user message could be any size, so copying it onto every\nsibling row made one roster reply carry the opening prompts of every saved\nsession. Saved roots no longer carry a first message at all, and the previews a\nrow can carry share one cap with the live latest-message preview.\n\nA peer working in another worker is live, so its row now keeps the active\nsession id the peer summary reports instead of claiming an active session with\nno id.\n\n* say which rows carry a first-message preview"},{"name":"agent-session-config.ts","kind":"file","size":6165,"lastCommitHash":"21cdadfc1e70a98a89006fa2b4b53d65e2b2be98","lastCommitWhen":"2026-09-17T06:02:59+03:00","lastCommitMessage":"feat(coding-agent): add remote python host support and ui indicators\n"},{"name":"agent-session-runtime.ts","kind":"file","size":24723,"lastCommitHash":"edbebbe932b1fcf286cd0f11fb283ea1eb37b117","lastCommitWhen":"2026-09-17T07:04:26+03:00","lastCommitMessage":"feat(coding-agent): wire spawn cwd, isolated workspaces and push authorization (R4, R12, R6)\n\n- `rlm.spawn(..., cwd=...)` and the runtime-created isolated checkout now reach\n  the child through `CreateRlmSubagentRuntimeOptions.cwd`, so an isolated child\n  really starts in `<repo_root>/.worktrees/<name>` instead of the parent's cwd\n  (the R4 default still applies when no cwd is given)\n- `rlm.spawn(..., allow_push=True)` reaches the child as `RLM_ALLOW_PUSH=1`,\n  which is the only thing that lifts the git/jj publish guard for a child; the\n  kwarg and the workspace value are validated before any allocation\n- the prompt now states the two corrections a model needs when a guard fires:\n  `line_hint=` for a non-unique `old_str`, and `RLM_ALLOW_PUBLIC_LISTEN=1` when a\n  public bind really is wanted\n"},{"name":"agent-session-services.ts","kind":"file","size":13338,"lastCommitHash":"988e4f41dd25a6f3df9cfc66f45496d630be1969","lastCommitWhen":"2026-09-17T08:25:36+03:00","lastCommitMessage":"fix: reconcile the rebased fork with upstream's refactors\n\nSecond pass over the residue the rebase left behind: the tree now\ntypechecks and lints clean, and the touched suites pass.\n\n- finish the credential reconciliation (firstCredential readers, MCP\n  static tokens, prime-cli config read/write helpers and the private\n  prime-cli accessors the fork's call sites need)\n- restore dropped wiring: the bash.consumed host request, the MCP\n  discovery assertions in the kernel ready check, and the snapshot\n  extras (activity, tool use, previews, labels, staleness) on kernel\n  roster entries next to the fork's turn/token accounting\n- rebuild the interactive-mode class fields and the /reload + /usage +\n  /context dispatch, and restore the async-bash header snippet\n- re-merge the agents view on upstream's newer file instead of the\n  per-commit resolutions, so the fork's view model survives: the\n  actions pane and its renderSessionRows early return, compactSessionRows\n  over the raw allRows, the pinned/expanded row markers and the\n  completed/needs-input icons, the running-subagent rows, and the\n  model-plus-host row label. upstream's timer-batched catalog reconcile\n  and its rebuild-free tick loop are kept, with a live cache ttl counted\n  as work so the ttl keeps counting down; the tray label providers dropped\n  upstream's redundant inline-picker guard\n- skip the quota wait when an unblocked sibling credential exists, so\n  the fork's quick account rotation still wins over a long Retry-After\n- restore real timers in the compaction regression suite, which the\n  preceding fake-timer test left mocked, and hold the fork's contracts in\n  the queue suite (200-message ceiling, batched steering) and the 4649\n  name-reservation test\n- drop upstream's subagentDefaultModel suite and its inherit-parent case:\n  this fork keeps an explicit model= on every spawn\n- move the deferred-session-event tests back to top level and wait on\n  the connection's own status sequence instead of a wall-clock poll\n- keep the fork's lazy session-open and sqlite catalog paths as the\n  session-loading fast path\n"},{"name":"agent-session.ts","kind":"file","size":536189,"lastCommitHash":"a94490eda202a79bb524e9822bb6c8bf6f3f04ea","lastCommitWhen":"2026-09-18T00:07:24+03:00","lastCommitMessage":"coding-agent: answer the tool call a replaced session left unresolved\n"},{"name":"agent-sessions.ts","kind":"file","size":7184,"lastCommitHash":"03c3ca484fbaa7f610a185df65fd73b05599651a","lastCommitWhen":"2026-09-17T05:52:15+03:00","lastCommitMessage":"feat(coding-agent,runtime): rebase minimal runtime extensions on upstream 0.9.3\n"},{"name":"agent-traces.ts","kind":"file","size":40407,"lastCommitHash":"cf07c5a3f5eca98e7744f2df83050044c920252a","lastCommitWhen":"2026-09-16T16:28:13-04:00","lastCommitMessage":"delete dead tests and fix the races the flaky ones were hiding (#2336)\n\n* add an objective testing policy to AGENTS.md\n\n* fix flaky daemon supervisor monitor test\n\nThe supervisor availability check is a real async chain (registry stat,\nsocket probe, replacement launch) started from a timer callback, so the\ntest drove a bounded fake-timer pump and asserted on a probe counter.\nUnder a loaded CI shard the chain did not finish inside the iteration\nbudget, and the variant mixing fake timers with a real probe promise\ncould deadlock for the full 30s test timeout.\n\nExpose a settled promise per armed availability check and await it in\nthe tests, so each assertion runs after the check finished instead of\nafter an arbitrary number of clock advances.\n\n* remove vitest retry masking from ai and attach-image tests\n\nDeleted all 548 `retry:` options in packages/ai/test and the 2 in\nkernel-attach-image-skill.test.ts. Retries hid non-determinism instead of\nfixing it, so a broken code path could still go green.\n\n- Deleted 17 live-only cross-provider E2E matrices whose every case sits behind\n  skipIf(!API_KEY) and never runs in CI; stream.test.ts stays as the survivor\n  that owns the provider table.\n- Stripped the retry option from the 198 stream.test.ts cases and dropped the\n  live E2E describe (plus its now-unused helpers) from\n  anthropic-thinking-disable.test.ts, keeping its mocked payload contract.\n- Removed retry: 1 from the two attach-image kernel cases; they pass without it.\n\nMocked wire/SSE contract tests are untouched. Tests only, no product code.\n\n* make agent trace upload tests deterministic\n\nThe suite pumped a synthetic clock with advanceTimersUntil() and hoped real\nfs and promise work settled inside a 200-step budget, asserted schedule\ndelays through a global setTimeout spy whose fake clock had drifted, and\nremoved its temp dir while catch-up and cursor writers were still running.\nUnder a loaded CI shard that produced \"Timed out advancing fake timers\",\n\"expected 1000 to be 60000\" and \"ENOTEMPTY rmdir /tmp/agent-traces-test-*\".\n\nThe upload scheduler now reports the delay it arms and the outcome of each\ncycle, the upload reports every wait it arms before the next request, and\ninstallAgentTraceUpload returns a handle that resolves when the startup\ncatch-up and any in-flight upload have finished writing. Tests await those\nsignals and advance the fake clock by the exact reported delay, and teardown\nwaits for in-flight writers before removing the temp dir.\n\nThe ~15 retry, backoff and Retry-After variants collapse into one\ntable-driven it.each, per the MERGE verdict: 1569 -> 1141 lines, 44 -> 27\ntest blocks, with no lost coverage.\n\n* make the compiled artifact and installer probe tests deterministic\n\nThe compiled-artifact afterEach polled for supervisor exit with the same\n10s budget as vitest's hook timeout, so the poll could never report on the\nslower standalone runners. The teardown now escalates to SIGKILL and every\ninner deadline stays below the surrounding hook and test budgets.\n\nnative-probe-timeout decided pass/fail from wall-clock deadlines around a\nreal 10s installer probe. The installer probe deadline is now injectable\nthrough PRIME_AGENT_PROBE_TIMEOUT_SECONDS, the blocked probe records the\ninstall lock itself, and the spawn deadlines are gone.\n\n* fix daemon shutdown admission loss during slow scans\n\nshutdown --force holds a 5s admission lease refreshed by a 1s timer, but it\nblocks its own event loop in synchronous ps/lsof/ss scans. On a loaded runner a\nscan outlasts the lease, the elapsed record is treated as abandoned, and the\nholder's next assertOrRenew throws \"Daemon shutdown admission was lost\".\n\n- A late renew re-arms a record that is still ours; only a missing or foreign\n  record ends the admission.\n- A renew that could not read the registry no longer retires the lease.\n- isDaemonShutdownAdmissionActive is read-only, so a bystander probe cannot\n  delete a live holder's record.\n- stopHiddenSupervisors renews before the blocking scan.\n\nThe 4603 regression drops its 11s sleep for a post-shutdown listener assertion\nand uses mkdtemp for the child TMPDIR.\n\n* delete 148 dead test files\n\nRemoves test files judged CUT by a full 480-file audit: duplicates of a named survivor, mock-asserting tests, rendered-copy assertions, private-internals casts, and live-API matrices behind skipIf(!API_KEY) that never ran in CI.\n\n* merge interactive-mode and agents-view test suites\n\n* merge tui render, overlay and helper test suites\n\n* test: slim daemon-mode and agent-connection-daemon suites\n\ndaemon-mode: keep passive hydration/passivation, delete_subagent durability, agent-message concurrency and rate limits, attach-snapshot backpressure; drop per-race internal regressions already covered process-level by daemon-supervisor-process.\nagent-connection-daemon: keep reconnect, update-restart, chunked-snapshot assembly and disposal races; drop tautological daemon-protocol pass-through cases.\n\n* merge tui editor, markdown and autocomplete test suites\n\n* test: merge audited session-core test bloat\n\nExecute MERGE verdicts from the 480-file test audit for the agent-session\ncore suites: collapse near-identical blocks into it.each tables, drop\nmock-return/rendered-copy assertions and private-cast white-box cases,\nand fold one-off files into the owning suite.\n\nDeleted (folded into their owning suite):\n- agent-session-concurrent.test.ts, suite/agent-session-action-races.test.ts,\n  suite/agent-session-action-contracts.test.ts -> suite/agent-session-queue.test.ts\n- suite/agent-session-compaction-continuation.test.ts,\n  suite/agent-session-compact-skill.test.ts -> suite/agent-session-compaction.test.ts\n- agent-session-runtime-events.test.ts -> suite/agent-session-runtime.test.ts\n\nPreserved: process boundaries (daemon RPC, ACP), on-disk formats,\nconcurrency/ordering, crash/restart/resume and load coverage.\n\n* address review: octal probe timeout, truncated deadline, dead schedule field\n\n* test: merge redundant coding-agent test cases into case tables\n\nExecutes the MERGE verdicts from the 480-file test-bloat audit for the\nmisc lanes. Repeated near-identical blocks collapse into single it.each\ncase tables, and ticket-numbered one-off files fold into the owning\nmodule suite.\n\nRemoved throughout the touched files: assertions on mock return values,\nassertions on rendered text/copy, `as unknown as` casts into privates,\nand suites gated behind skipIf(!API_KEY) (which never ran in CI).\n\nPreserved: process boundaries (daemon RPC, ACP), on-disk formats,\nconcurrency and ordering, crash/restart/resume, and load.\n\nDeleted files, folded into their module suite:\n- compaction-extensions -> deleted outright (whole file behind skipIf(!API_KEY))\n- compaction-serialization -> compaction\n- heartbeat-catalog -> daemon-client\n- child-process -> exec\n- edit-tool-legacy-input -> tools\n- kernel-goal-skill, kernel-rlm-heartbeat-skill -> kernel-agent-message-skill\n- kernel-agent-observe-skill -> kernel-attach-image-skill\n- kernel-windows-process -> kernel-bootstrap-windows\n- extensions-input-event -> extensions-runner\n- sdk-skills -> sdk-session-manager\n- session-manager/{agent-status,has-user-content} -> session-manager/session-state\n- session-manager/migration -> session-manager/file-operations\n- session-manager/custom-session-id -> session-manager/tree-traversal\n\n* slim ai + regression tests (lanes A/B/D/E)\n\nExecute MERGE verdicts from the test audit for packages/ai and the\nupdate-restart / snapshot / session-view regression files.\n\n- fold ticket-numbered regression cases into the owning suites\n- collapse near-identical blocks into it.each tables\n- drop mock-return, rendered-copy and live-API-gated assertions\n\n* test: collapse package-manager tables and fold small daemon selector suites\n\npackage-manager: git-URL parsing, top-level/manifest/package glob filters and npm install-argv cases are now table-driven.\ndaemon-session-id: absorbs daemon-catalog-process selector case, drops display-id formatting trivia.\ndaemon-worker-windows-timeouts: absorbs the connection-deadline budget cases from daemon-worker-connect.\ndaemon-catalog-startup: drops the src-directory one-off.\n\n* test: collapse refinement, settings and config suites into case tables\n\nFinal misc lane of the test-bloat audit.\n\n- refinement: per-kind create/update/delete becomes one it.each lifecycle;\n  8 rejection suites become one 18-row invalid-edit table that also asserts\n  state and the refinement log stay untouched; truncation/parse errors,\n  scope permutations, ranking and the tokenizer each become one table.\n  System-prompt and user-prompt copy assertions removed.\n- settings-manager: per-setting default getters removed; unknown-key\n  preservation, invalid-file guards and project-vs-global precedence kept.\n- config: install-method detection becomes one table; session-dir env\n  permutations collapse into one precedence test.\n- builtin-skills, repl-kernel-abort, session-cwd, truncate: repeated blocks\n  collapsed; one ReplInternals reach-in dropped.\n- child-process folds into exec as one process lifecycle suite.\n\n* slim regression tests (lane C)\n\nFold the remaining ticket-numbered regression files into the owning\nmodule suites and collapse duplicate cases into it.each tables.\n\n- 19 regression files deleted after their kept cases moved into\n  agent-session-queue, auth-storage, acp-features, resource-loader,\n  agent-session-runtime/compaction/retry-events/recursion,\n  model-registry, slash-commands, daemon-supervisor-process\n- 3 files slimmed in place where the named target no longer exists\n- drop rendered-copy, mock-return and private-cast assertions\n\n* test: collapse daemon protocol, command, list, ps and package-command suites\n\ndaemon-protocol: two gating tables replace 16 near-identical capability/schema cases.\ndaemon-command: table-driven argv parsing plus the --goal leak guards; drops help/usage copy assertions.\ndaemon-session-list: activity, recap and model-fallback projections are table-driven.\ndaemon-ps: keeps planReap/planShutdownAll safety rules, drops ss/lsof parsers, sorting and uptime trivia.\ndaemon-stop-confirm: one busy-guard table, no prompt copy.\npackage-command-paths: one shared self-update fixture for the install-spec cases; drops help and removed-flag copy.\nacp-events: keeps only the cases the ACP suite does not cover end to end.\ndaemon-session-summarizer: one recap/status parse table.\ndaemon-extension-binding: keeps the duplicated-partial-message strip.\n\n* test: tighten the daemon stop-confirm busy-guard table\n\n* fix ci: biome forEach body, vacuous autocomplete case, missing prompt before second compaction\n\n* fix ci: restore escaped template literals in prompt-template cases\n\n* fix codeql: single-pass path escaping in test helpers\n\n* address review: flush debounced trace uploads, restore probe timeout guards, drop dead test scaffolding\n\n* respect retry-after and throttle window when flushing trace uploads\n\n* await in-flight trace uploads before a drain returns\n\n* extend deterministic test policy to python\n\n* harden deterministic test policy checks\n\n* close test policy edge cases\n\n* finish deterministic policy edge coverage\n\n* fix policy lexer and macos signature setup\n\n* mask regex literals in test policy checks\n\n* distinguish postfix division in policy lexer\n\n* close native migration signal race\n\n* keep native migration force timer owned\n\n---------\n\nCo-authored-by: prime-agent <agent@local>"},{"name":"auth-guidance.ts","kind":"file","size":2241,"lastCommitHash":"f3130cc518dada33e4933e2c14d9ebbb940009d5","lastCommitWhen":"2026-07-08T11:50:59-07:00","lastCommitMessage":"mark stale provider auth after repeated failures (#335)\n\n* fix stale provider auth after repeated failures\n\n* fix stale auth source fallbacks\n\n* fix stale auth review edge cases\n\n* fix stale auth login display\n\n* fix stale auth retry edge cases\n\n* fix stale auth source fingerprints\n\n* fix stale auth source tracking\n\n* fix stale models json key rotation\n\n* fix stale auth final guidance\n\n* fix auth guidance regression test\n\n* fix stale auth login ordering\n\n* fix auth stale retry cancellation"},{"name":"auth-storage.ts","kind":"file","size":66659,"lastCommitHash":"61731ee9489fecade294cac26a725d4648b5afb5","lastCommitWhen":"2026-09-17T09:50:34+03:00","lastCommitMessage":"fix(coding-agent): fail closed only for live stored credentials\n\nA credential that a failure or the user already marked stale exists\nprecisely so resolution can fall through to another source, so the\nfail-closed rule now covers only live stored credentials that could not\nsupply a key. That keeps ENG-6059 (no silent environment charge after a\nfailed refresh) while restoring stale-account fallback and stale-fallback\nmodel routing.\n"},{"name":"autonomous.ts","kind":"file","size":24503,"lastCommitHash":"f781e33779d4d57203f21db2d19746fa5b23a3c6","lastCommitWhen":"2026-09-17T07:04:08+03:00","lastCommitMessage":"feat(coding-agent): context is the harness's job, not a budget the model watches (P1, I3, P2)\n\nP1 - a context-budget panic stopped work at 11% usage (01a0920d) because the\nmodel read a compaction counter as an external budget; the corpus also shows\nmodels shortening answers, refusing to continue, and treating `percent` as a\nthreshold. Nine false-budget signals reached a model or a parent. They are gone:\n\n- the compact skill's description no longer says \"context is filling up\" and no\n  longer tells the model to compact while work remains; its rules now say\n  context size is not a budget the model manages and is never a reason to stop,\n  shorten, drop a step, or return early, and `status()` is named as a\n  measurement rather than a limit\n- the system prompt's REPL paragraph drops \"context management\" and the\n  variable-size compaction sentence, and the long-running-work block gains the\n  rule outright: context is never a blocker\n- the context-overflow and compaction-failure messages ask for the last real\n  blocker instead of suggesting a smaller context or a larger-context model\n- goal `remaining_tokens` is labelled a lifetime goal budget on both goal skill\n  surfaces and in the goal context messages, not context headroom\n- the autonomous continuation prompt points at the host that stops the run\n  instead of an unquantified budget\n- the compaction-summary suffix states once that a mid-task compaction is\n  routine: continue without an apology, without restating the plan, and without\n  trimming the work\n- session-local continual harness entries now win the digest's detail budget, so\n  a large global harness can no longer push this session's own memories into the\n  listing-only tail at compaction (this also fixes a failing suite test)\n\nThe harness still compacts automatically at a turn boundary and resumes the\nmodel with the summary; a checkpoint is for summary quality only (the user\nasked, or a large milestone closed). No field, threshold, or reserve is\npublished to the model: the user and the UI keep the numbers.\n\nI3 - a reply that drifts out of the conversation's script (01a0924e, 01a09b11)\nnow gets one advisory `[language-drift]` notice, at most three per session and\nnever twice within twenty assistant turns. It is advisory only: short or\ncode-heavy replies, and a user who writes that script, are ignored.\n\nP2 - the child-lifetime policy, as policy only: the system prompt states one\nchild per coherent deliverable, reuse only for live state, never tell a child to\ncompact or to stay short, and no turn/token/lifetime caps. The parent-side\nfooter now reports `compactionCount` from `ContextUsage` -- the lifetime signal\na parent should read -- and labels the token numbers as measured, not a limit.\n"},{"name":"bash-executor.ts","kind":"file","size":3473,"lastCommitHash":"844e85545af6858dcb3d6cfe42bbfcf2ca0be4e5","lastCommitWhen":"2026-09-06T21:56:32-04:00","lastCommitMessage":"Harden session persistence, worker recovery, and daemon refreshes (#2028)\n\n* refactor(coding-agent): move the semantic-edge ledger onto the event-log substrate\n\nThe recorder's private append/replay/repair IO is deleted; EventLog owns it, the same move #1987 made for the RLM spawn ledger. One durability rule is unified in the substrate rather than dropped: an unterminated final line is an uncommitted append, skipped on read and truncated before the next append — never newline-completed and never surfaced to a consumer whose next append destroys it.\n\n* fix(coding-agent): make the explicit ledger reader's ENOENT contract atomic\n\nreadSemanticEdgeLedger probed with statSync before reading through EventLog, which swallows ENOENT; a ledger deleted between the two returned [] instead of throwing. The missing-file decision now lives at the single open (replaySync missingFileThrows), so no check-then-read window exists.\n\n* docs(coding-agent): state the event-log tail rule once\n\nThe unterminated-tail contract was restated four times (module doc, replaySync doc, two test comments). It now lives once in the module doc; the method doc keeps only its own parse/missing-file semantics and the test comments reference the contract.\n\n* fix(coding-agent): write event-log appends fully and gate appends on tail repair\n\nwriteSync may write short (ENOSPC after a prefix); appendSync now loops until the payload is fully on disk so write-before-action callers never act on a torn record reported as success. A tail-repair failure (e.g. append-only ACL permitting O_APPEND but not r+) now propagates instead of being swallowed: writing through an unrepaired torn tail would weld it to the new record as permanent interior corruption. ENOENT and the concurrent-writer instability path keep their existing semantics.\n\n* fix(coding-agent): reclaim short event-log writes instead of completing them\n\nThe rlm spawn ledger is multi-writer by documented design (supervisor plus each worker over one file), so completing a short O_APPEND write with a second write could interleave with a rival append and weld two records. A short write now truncates its own torn prefix back off (only while this writer still owns the tail) and fails the append; a torn tail is read-tolerated, a weld is permanent corruption. The append fd opens a+ so the ownership check can read the tail.\n\n* fix(coding-agent): leave the torn tail on a short write instead of reclaiming it\n\nThe tail-match reclaim could truncate a rival's committed record whose final bytes coincide with our torn prefix - committed-data loss, strictly worse than the torn tail it prevented. A short write now just fails the append: the torn tail is the one tolerated shape, skipped on read and truncated by any writer's next repair (verified for both topologies: a resumed single-writer recorder repairs on its first append; every rlm-ledger writer repairs before each append).\n\n* refactor(coding-agent): compress event-log comments\n\n* fix(ai): omit the default service tier, reprice cache writes from message_delta, repoint the zai default\n\nIncorporates #2032 at f82c7fa3688b7e25cef80e2663fe77ed153c5cd9.\n\n* fix(tui,coding-agent): survive lone surrogates in table cells and terminate the WebP EXIF scan\n\nIncorporates #2033 at a3d1139ee6e1f77337ab134b0f0c0cede8c942af.\n\n* fix(coding-agent): restart dead kernels on ensure() and read mcp>=2 tool schemas\n\nIncorporates #2034 at 749e216e901304b310ead9f46c3813a032608d7b.\n\n* fix: one crash-safe owner for durable state writes\n\nIncorporates #2035 at f0f02d2fb090ec427307a65b9e9578ae3c8fc783.\n\n* fix(coding-agent): one zombie-aware process-liveness probe\n\nIncorporates #2041 at 92a0eacf47efc831444b0b4e412f35bd17ac3f28.\n\n* fix(coding-agent): snapshot transfer ids from the materialized cursor; mismatches settle the transfer, not the worker channel\n\nIncorporates #2044 at 5af3bbe8090240507d6b0297d0da007159e15305.\n\n* fix(coding-agent): failed workers recover on touch; roster gaps answer a structured recovering error\n\nIncorporates #2047 at 77b747afab402a9e2f5eada227ffe6fed626a634.\n\n* fix(coding-agent): seven session and IO correctness defects\n\nIncorporates #2037 at 41b5d72d7758723f22ba07f8738d217868ed7baf.\n\n* fix(coding-agent): coalesce child-usage attribution and gate agent-status persistence on real changes\n\nIncorporates #2050 at 6b0af5d2679ddff987ef3b4d43235a872fe2b315.\n\n* fix(coding-agent): incremental single-flight session metadata scans\n\nIncorporates #2043 at df032c1192dd2e38d35fcbaca589db7194f26b6c.\n\n* fix(coding-agent): memoize the passive RLM topology derivation\n\nIncorporates #2051 at 0ee114ce77942d9298136ca193ddc2c0b5d27d58.\n\n* fix(coding-agent): preserve accounting and metadata across deferred updates\n\nKeep durable child-usage aggregates separate from pending sibling usage. Retry optional topology metadata after transient reads. Completes #2050 and #2051 integration.\n\n* fix: preserve session accounting and read-only persistence boundaries\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"context-tree.ts","kind":"file","size":10141,"lastCommitHash":"d74a75fea3411136fdd2ba95c7f723ddefdadf05","lastCommitWhen":"2026-09-03T18:08:28-04:00","lastCommitMessage":"feat: token and cost details on agents view rows (#2003)\n\n* fix: count busy descendants in the agents-view subagents indicator\n\nThe \"N subagents running\" indicator only tallied direct children whose\nrow classified as running, so a busy grandchild under an idle\nintermediate child left every ancestor reading \"N subagents\" with a zero\ncount. The tally is now a bottom-up pass over the built rows - the live\nper-descendant truth - replacing the direct-child increment.\n\nIndicator only, per policy: a session is Running when it works itself;\nidle ancestors of busy subtrees stay in Idle. Within Idle they now rank\nabove plain idle rows, and a collapsed group's summary row renders its\nrunning count in the success color instead of dimmed so the busy subtree\nis discoverable without expanding.\n\nDiagnosis credit: Vincent Bailly (VincentBailly/prime-agent#9) traced\nthe stale hasRunningRlmChildren snapshot and the row-walk mechanism;\nthis adopts his walk for the indicator while rejecting the section\npromotion.\n\nRES-1253\n\n* fix: tally busy descendants before heartbeat promotion inflates sections\n\nThe descendant tally read row sections after\npropagateHeartbeatStateToAncestors had promoted idle ancestors to\nrunning, so a heartbeat-active grandchild counted its promoted parent\ntoo. The tally now runs before the promotion pass and counts\nintrinsically busy rows only; once that propagation pass is deleted\n(#1967) the ordering is a no-op.\n\nRES-1253\n\n* fix: make the descendant tally iterative so deep chains cannot overflow\n\nThe recursive tally threw RangeError on a deep child chain just by\nopening the agents view. The nesting loop assigns every row at most one\nparent, so the tree is a forest: a reverse breadth-first pass over one\nwork list computes the same bottom-up counts iteratively, with the\npre-promotion ordering kept.\n\nRES-1253\n\n* fix: classify running from the session's own work, not delegated children\n\nSecond half of the RES-1253 policy, user-approved: Running means the\nsession you enter is doing work now. Delegated child work no longer\nclassifies a session as running - the busy-descendant badge, count, and\nidle ranking from the first half carry the delegation signal.\n\nhasRunningRlmChildren loses its section-classification role in both\nowners: classifySessionRosterStatus composes busy from the session's own\nactivity/isSessionActive, and isActiveSessionBusy (the worker's activity\naxis) no longer holds a settled parent at \"working\" for its children.\nThe \"subagents running\" status label dies with the section it had to\nagree with. The field itself stays on the wire, and isSessionSummaryBusy\nkeeps it on purpose for its residency and shutdown-safety consumers\n(worker eviction snapshots, empty-draft eviction, busy client-owned\nsession counts, daemon stop confirmation).\n\nRES-1253\n\n* chore: note the running-means-the-session policy in the changelog fragment\n\n* fix: split display activity from live-work safety in the busy predicates\n\nisActiveSessionBusy served two meanings after the classification change:\nthe display activity axis (session's own work only, correct) and worker\nrecovery plus draft-discard (where a running RLM child is live work that\ndies with the worker). The recovery journal recorded busy:false for a\nsettled parent with a running child, so a worker death skipped its\ninterruption record and notice.\n\nThe shared predicate is deleted and each meaning gets one named owner:\nactiveActivityForSession reads the session's own isSessionActive\ndirectly, and hasLiveSessionWork (own turn or running RLM child) backs\nrecordWorkerRecoveryState and isDiscardableDraft. No caller can grab the\nwrong meaning blind.\n\nRES-1253\n\n* feat: show token and cost totals on agents view rows\n\nEvery agents view row with usage data now reads\n`<input>/<output> | $<own> ($<recursive>)` in the details cell, replacing\nthe message-count detail. Own numbers are the session's whole-file spend\n(every branch, forks included, attributed child usage subtracted) - the\nmoney answer, deliberately broader than /usage's current-branch context\nanswer, and identical for resident and on-disk rows so nothing shifts at\npassivation or revival. The recursive total rides the same reverse\nbreadth-first traversal as the running-subagent tally, summing each\ndescendant row's own cost exactly once.\n\nProducers: resident summaries compute the total from the already-loaded\nentries, memoized until entries change (0.27 ms measured cold at 10k\nentries); saved rows accumulate it inside the existing mtime/size-cached\ncatalog scan, so old files get costs with no new IO and no new cache.\nEntries over the scan's max line length keep their existing skip, so a\ngiant assistant message can undercount slightly. Schema revision 26\npublishes the new optional summary and saved-row field.\n\nRES-1258\n\n* feat: final row usage format with arrows and conditional recursive cost\n\nDetails cell now reads `↑12k ↓1.2k · $0.42 ($1.10 w/ subagents)`; the\nparenthesized total renders only when descendants added spend visible at\ncent rounding, so leaf rows read `↑500 ↓50 · $0.68`. Arrow glyphs follow\nthe existing TUI vocabulary (keybinding hints, token status) and the\nwidth pipeline already treats them as single cells.\n\nRES-1258\n\n* fix: one own-spend truth across scan, loader, and filters\n\nReview round on the usage feature:\n\n- The catalog scan subtracted attributed child usage from disk values\n  that (in append-only files) still carry the assistant's ORIGINAL\n  model-response usage, double-subtracting and shifting numbers at\n  passivation. Full-file rewrites (migrations, forks) can also persist\n  the already-folded aggregates, so raw summation is wrong for those\n  files instead. The scan now mirrors the loader exactly: fold each\n  attribution's aggregate onto its target, then subtract the child usage\n  - both disk representations cancel to the same own spend the resident\n  computation reports. The equality pin now goes through a real v3\n  flushed-then-attributed fixture (the old fixture had no attribution,\n  which is why it never caught this).\n- Recursive cost was computed over search-filtered rows, so a matching\n  parent showed an incomplete \"w/ subagents\" total. The rollup now comes\n  from the unfiltered record hierarchy (computeRecursiveCosts over the\n  unified index) and filtering can no longer change the number.\n- Zero-spend sessions published 0/0/$0.00 live and nothing once\n  passivated; sessionUsageSummaryFrom now returns undefined for zero\n  totals, shared by both producers, so rows stay age-only until real\n  spend exists.\n\nRES-1258\n\n* fix: gate destructive agent actions on live work, not display section\n\nSince Running means the session's own work, an idle parent of a running\ncrew was branching into the delete path: killSubagent chose stop-vs-\ndelete from the display section and stopAgentForDeletion treated\nactivity==='working' as the only live work. Destructive actions are\nsafety consumers of the display/safety split: one row-level hasLiveWork\n(own section running, busy descendants, or the wire running-children\nflag) now drives the stop-first branch, the deletion flow, and the\nconfirmation verb.\n\nAlso trimmed the tally comment to current behavior.\n\nRES-1253\n\n* fix: stop live descendants when cancelling a settled child run\n\nStopping a subagent row whose own run already settled reported\n'Subagent already finished' while a nested descendant kept running:\ncancelRlmChildRun only cancelled the targeted run itself, and a fully\nreleased child (run removed, session retained) was never matched by id\nat all. Cancellation now descends where the tree lives: a settled target\nstops every running or queued run in its retained session's subtree\n(cancelRunningRlmDescendants, mirroring hasRunningRlmChildren's walk),\nand the returned flag stays truthful so the UI says stopped only when\nsomething stopped.\n\nRES-1253\n\n* feat: render the usage cell unconditionally, zeros included\n\nEvery agents view row now renders the full details cell\n`↑<up> ↓<down> · $<own> ($<total> w/ subagents)` over four defaulted\nnumbers - no presence branching, no thresholds, no conditional paren. A\nsession that never spent reads `↑0 ↓0 · $0.00 ($0.00 w/ subagents)`, and\na zero-usage parent with billed subagents shows its subtree spend\ninstead of hiding it.\n\nRES-1258\n\n* chore: trim comments and fold overlapping pins on the indicator branch\n\nComment pass: multi-line narration cut to one-line invariant guards\n(destructive live-work gate, residency-vs-section busy split, worker-\ndeath live work) and code-readable notes deleted. Test pass: the direct-\nchild indicator pin folded into the grandchild pin (the general case),\nwhich now also carries the idle-label and wire-flag assertions.\n\n* chore: cut the usage feature's comments and collapse its pins\n\nComment pass (>80%): 24 added comment lines down to 4 one-line invariant\nguards (loader-fold cancellation in the scan, passivation-invariance on\nthe resident getter, unfiltered rollup, the revision note). Test pass:\nthe scan-accumulation and resident-equality pins merged onto one forked-\nand-attributed fixture; the descendant-rollup and filtered-total pins\nmerged with a grandchild; the format pin asserts all four row shapes\nfrom one fixture; redundant zero-case and permutation tests deleted.\n\n* fix: cancel and descend at every node of the rlm cancel walk\n\nCancelling a live child run aborts it, and abort cascades into the\nchild's ACTIVE runs - but running work retained under a settled\ndescendant of that child was the end of the line: neither the cascade\nnor the cancel walk visited it. cancelRlmChildRun now descends into the\ntarget's session after cancelling it, and cancelRunningRlmDescendants\ndescends at every node instead of treating running runs as leaves, so\ncancellation is exhaustive over the subtree regardless of each node's\nrun state. The returned flag stays truthful.\n\nRES-1253\n\n* fix: passivated RLM descendants survive restarts as saved-catalog rows\n\nAn RLM child's transcript lives in session-artifacts, which the saved-\nsession scan never visits. While something resident remembered the child\nits row survived; after a supervisor restart an inactive parent's\npassivated descendants silently disappeared from the agents view, and\ntheir spend vanished from the parent's subtree total.\n\nBoth list_saved_sessions composition points now append live spawn-ledger\nchildren the scan missed, through one shared walk: readSessionInfo per\ndescendant, parentSessionPath/rlmDepth backfilled from the edge, deleted\nedges excluded. The view already renders saved-only descendants, merges\nresident duplicates by session identity, and rolls saved usage into\nrecursive totals, so restored rows restore the money with no view change.\n\nMeasured at 300 sessions with 36 passivated descendants: scan 33ms,\nmerge +9ms (cold ledger, ~0.25ms per descendant).\n\nRES-1262\nRES-1258\n\n* feat: compaction and branch-summary calls bill the session they serve\n\nSummarization was invisible money: the compaction model call(s) - two on\na split turn - and branch-summary calls returned usage that was dropped\non the floor, so a session that compacted often under-reported what it\nactually cost. The summarizer responses' usage is now folded (both\nsplit-turn slices) and persisted on the compaction/branch_summary entry,\nand both own-spend producers add the same term: own spend =\nfold(assistant usage) + fold(summarization usage) - attributions,\nidentical resident and scanned. Old entries without the field fold as\nzero; a failed compaction persists nothing, so failed-call billing is\nnot recoverable - there is no committed entry to carry it.\n\nRES-1258\n\n* fix: harden the passive-descendant catalog merge (round 2)\n\nThree review findings on the merge, all real: the transcript header's\nparentSession can point at a forked-away ancestor, so the ledger edge is\nnow the authoritative topology (family() semantics) for parent and\ndepth; ledgers are per sessions-dir family, so each catalog request now\nreads the ledger of the directory it lists instead of always the\ndefault one; and a broken ledger (unreadable, over-quota) no longer\nfails the whole list_saved_sessions response - the merge logs and\nreturns the scanned catalog.\n\nRES-1262\n\n* chore: consolidate the accumulated review-round pins\n\nThe worker-daemon catalog pins from three rounds folded onto one\nfixture: restart rows, per-family ledger isolation, and broken-ledger\ndegradation now share the two-family scaffold. Redundant assertions and\nnarration comments cut; every behavior keeps exactly one pin.\n\n* test(coding-agent): align unified view regression with usage rows\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"cron-jobs.ts","kind":"file","size":53908,"lastCommitHash":"844e85545af6858dcb3d6cfe42bbfcf2ca0be4e5","lastCommitWhen":"2026-09-06T21:56:32-04:00","lastCommitMessage":"Harden session persistence, worker recovery, and daemon refreshes (#2028)\n\n* refactor(coding-agent): move the semantic-edge ledger onto the event-log substrate\n\nThe recorder's private append/replay/repair IO is deleted; EventLog owns it, the same move #1987 made for the RLM spawn ledger. One durability rule is unified in the substrate rather than dropped: an unterminated final line is an uncommitted append, skipped on read and truncated before the next append — never newline-completed and never surfaced to a consumer whose next append destroys it.\n\n* fix(coding-agent): make the explicit ledger reader's ENOENT contract atomic\n\nreadSemanticEdgeLedger probed with statSync before reading through EventLog, which swallows ENOENT; a ledger deleted between the two returned [] instead of throwing. The missing-file decision now lives at the single open (replaySync missingFileThrows), so no check-then-read window exists.\n\n* docs(coding-agent): state the event-log tail rule once\n\nThe unterminated-tail contract was restated four times (module doc, replaySync doc, two test comments). It now lives once in the module doc; the method doc keeps only its own parse/missing-file semantics and the test comments reference the contract.\n\n* fix(coding-agent): write event-log appends fully and gate appends on tail repair\n\nwriteSync may write short (ENOSPC after a prefix); appendSync now loops until the payload is fully on disk so write-before-action callers never act on a torn record reported as success. A tail-repair failure (e.g. append-only ACL permitting O_APPEND but not r+) now propagates instead of being swallowed: writing through an unrepaired torn tail would weld it to the new record as permanent interior corruption. ENOENT and the concurrent-writer instability path keep their existing semantics.\n\n* fix(coding-agent): reclaim short event-log writes instead of completing them\n\nThe rlm spawn ledger is multi-writer by documented design (supervisor plus each worker over one file), so completing a short O_APPEND write with a second write could interleave with a rival append and weld two records. A short write now truncates its own torn prefix back off (only while this writer still owns the tail) and fails the append; a torn tail is read-tolerated, a weld is permanent corruption. The append fd opens a+ so the ownership check can read the tail.\n\n* fix(coding-agent): leave the torn tail on a short write instead of reclaiming it\n\nThe tail-match reclaim could truncate a rival's committed record whose final bytes coincide with our torn prefix - committed-data loss, strictly worse than the torn tail it prevented. A short write now just fails the append: the torn tail is the one tolerated shape, skipped on read and truncated by any writer's next repair (verified for both topologies: a resumed single-writer recorder repairs on its first append; every rlm-ledger writer repairs before each append).\n\n* refactor(coding-agent): compress event-log comments\n\n* fix(ai): omit the default service tier, reprice cache writes from message_delta, repoint the zai default\n\nIncorporates #2032 at f82c7fa3688b7e25cef80e2663fe77ed153c5cd9.\n\n* fix(tui,coding-agent): survive lone surrogates in table cells and terminate the WebP EXIF scan\n\nIncorporates #2033 at a3d1139ee6e1f77337ab134b0f0c0cede8c942af.\n\n* fix(coding-agent): restart dead kernels on ensure() and read mcp>=2 tool schemas\n\nIncorporates #2034 at 749e216e901304b310ead9f46c3813a032608d7b.\n\n* fix: one crash-safe owner for durable state writes\n\nIncorporates #2035 at f0f02d2fb090ec427307a65b9e9578ae3c8fc783.\n\n* fix(coding-agent): one zombie-aware process-liveness probe\n\nIncorporates #2041 at 92a0eacf47efc831444b0b4e412f35bd17ac3f28.\n\n* fix(coding-agent): snapshot transfer ids from the materialized cursor; mismatches settle the transfer, not the worker channel\n\nIncorporates #2044 at 5af3bbe8090240507d6b0297d0da007159e15305.\n\n* fix(coding-agent): failed workers recover on touch; roster gaps answer a structured recovering error\n\nIncorporates #2047 at 77b747afab402a9e2f5eada227ffe6fed626a634.\n\n* fix(coding-agent): seven session and IO correctness defects\n\nIncorporates #2037 at 41b5d72d7758723f22ba07f8738d217868ed7baf.\n\n* fix(coding-agent): coalesce child-usage attribution and gate agent-status persistence on real changes\n\nIncorporates #2050 at 6b0af5d2679ddff987ef3b4d43235a872fe2b315.\n\n* fix(coding-agent): incremental single-flight session metadata scans\n\nIncorporates #2043 at df032c1192dd2e38d35fcbaca589db7194f26b6c.\n\n* fix(coding-agent): memoize the passive RLM topology derivation\n\nIncorporates #2051 at 0ee114ce77942d9298136ca193ddc2c0b5d27d58.\n\n* fix(coding-agent): preserve accounting and metadata across deferred updates\n\nKeep durable child-usage aggregates separate from pending sibling usage. Retry optional topology metadata after transient reads. Completes #2050 and #2051 integration.\n\n* fix: preserve session accounting and read-only persistence boundaries\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"defaults.ts","kind":"file","size":132,"lastCommitHash":"3e5ad67e0f325d4888f82f9b82966218eb4407f5","lastCommitWhen":"2026-05-07T15:59:42+02:00","lastCommitMessage":"chore: migrate pi packages to earendil works scope\n"},{"name":"diagnostics.ts","kind":"file","size":452,"lastCommitHash":"4719929f6a18ec897b6c0af00c51177df2efc9cb","lastCommitWhen":"2026-01-24T00:45:01+01:00","lastCommitMessage":"refactor(coding-agent): unify SkillWarning and ResourceDiagnostic\n\n- Create shared diagnostics.ts with ResourceCollision and ResourceDiagnostic types\n- Update loadSkills() to return diagnostics instead of warnings\n- Remove SkillWarning type and skillWarningsToDiagnostics() conversion\n- Update skills.test.ts to use diagnostics\n"},{"name":"event-bus.ts","kind":"file","size":795,"lastCommitHash":"be330fdd9caebbea8bb7e3df7669703b40843e7f","lastCommitWhen":"2026-01-04T22:04:50+01:00","lastCommitMessage":"Fix event bus async error handling, clear pending messages on session switch, improve SDK docs\n\n- event-bus.ts: await async handlers to catch errors properly\n- agent-session.ts: clear _pendingNextTurnMessages on newSession/switchSession/branch\n- sdk.ts: make eventBus first (required) param for discoverHooks/discoverCustomTools\n- docs/sdk.md: document eventBus sharing pattern for hook/tool communication\n"},{"name":"event-log.ts","kind":"file","size":6119,"lastCommitHash":"844e85545af6858dcb3d6cfe42bbfcf2ca0be4e5","lastCommitWhen":"2026-09-06T21:56:32-04:00","lastCommitMessage":"Harden session persistence, worker recovery, and daemon refreshes (#2028)\n\n* refactor(coding-agent): move the semantic-edge ledger onto the event-log substrate\n\nThe recorder's private append/replay/repair IO is deleted; EventLog owns it, the same move #1987 made for the RLM spawn ledger. One durability rule is unified in the substrate rather than dropped: an unterminated final line is an uncommitted append, skipped on read and truncated before the next append — never newline-completed and never surfaced to a consumer whose next append destroys it.\n\n* fix(coding-agent): make the explicit ledger reader's ENOENT contract atomic\n\nreadSemanticEdgeLedger probed with statSync before reading through EventLog, which swallows ENOENT; a ledger deleted between the two returned [] instead of throwing. The missing-file decision now lives at the single open (replaySync missingFileThrows), so no check-then-read window exists.\n\n* docs(coding-agent): state the event-log tail rule once\n\nThe unterminated-tail contract was restated four times (module doc, replaySync doc, two test comments). It now lives once in the module doc; the method doc keeps only its own parse/missing-file semantics and the test comments reference the contract.\n\n* fix(coding-agent): write event-log appends fully and gate appends on tail repair\n\nwriteSync may write short (ENOSPC after a prefix); appendSync now loops until the payload is fully on disk so write-before-action callers never act on a torn record reported as success. A tail-repair failure (e.g. append-only ACL permitting O_APPEND but not r+) now propagates instead of being swallowed: writing through an unrepaired torn tail would weld it to the new record as permanent interior corruption. ENOENT and the concurrent-writer instability path keep their existing semantics.\n\n* fix(coding-agent): reclaim short event-log writes instead of completing them\n\nThe rlm spawn ledger is multi-writer by documented design (supervisor plus each worker over one file), so completing a short O_APPEND write with a second write could interleave with a rival append and weld two records. A short write now truncates its own torn prefix back off (only while this writer still owns the tail) and fails the append; a torn tail is read-tolerated, a weld is permanent corruption. The append fd opens a+ so the ownership check can read the tail.\n\n* fix(coding-agent): leave the torn tail on a short write instead of reclaiming it\n\nThe tail-match reclaim could truncate a rival's committed record whose final bytes coincide with our torn prefix - committed-data loss, strictly worse than the torn tail it prevented. A short write now just fails the append: the torn tail is the one tolerated shape, skipped on read and truncated by any writer's next repair (verified for both topologies: a resumed single-writer recorder repairs on its first append; every rlm-ledger writer repairs before each append).\n\n* refactor(coding-agent): compress event-log comments\n\n* fix(ai): omit the default service tier, reprice cache writes from message_delta, repoint the zai default\n\nIncorporates #2032 at f82c7fa3688b7e25cef80e2663fe77ed153c5cd9.\n\n* fix(tui,coding-agent): survive lone surrogates in table cells and terminate the WebP EXIF scan\n\nIncorporates #2033 at a3d1139ee6e1f77337ab134b0f0c0cede8c942af.\n\n* fix(coding-agent): restart dead kernels on ensure() and read mcp>=2 tool schemas\n\nIncorporates #2034 at 749e216e901304b310ead9f46c3813a032608d7b.\n\n* fix: one crash-safe owner for durable state writes\n\nIncorporates #2035 at f0f02d2fb090ec427307a65b9e9578ae3c8fc783.\n\n* fix(coding-agent): one zombie-aware process-liveness probe\n\nIncorporates #2041 at 92a0eacf47efc831444b0b4e412f35bd17ac3f28.\n\n* fix(coding-agent): snapshot transfer ids from the materialized cursor; mismatches settle the transfer, not the worker channel\n\nIncorporates #2044 at 5af3bbe8090240507d6b0297d0da007159e15305.\n\n* fix(coding-agent): failed workers recover on touch; roster gaps answer a structured recovering error\n\nIncorporates #2047 at 77b747afab402a9e2f5eada227ffe6fed626a634.\n\n* fix(coding-agent): seven session and IO correctness defects\n\nIncorporates #2037 at 41b5d72d7758723f22ba07f8738d217868ed7baf.\n\n* fix(coding-agent): coalesce child-usage attribution and gate agent-status persistence on real changes\n\nIncorporates #2050 at 6b0af5d2679ddff987ef3b4d43235a872fe2b315.\n\n* fix(coding-agent): incremental single-flight session metadata scans\n\nIncorporates #2043 at df032c1192dd2e38d35fcbaca589db7194f26b6c.\n\n* fix(coding-agent): memoize the passive RLM topology derivation\n\nIncorporates #2051 at 0ee114ce77942d9298136ca193ddc2c0b5d27d58.\n\n* fix(coding-agent): preserve accounting and metadata across deferred updates\n\nKeep durable child-usage aggregates separate from pending sibling usage. Retry optional topology metadata after transient reads. Completes #2050 and #2051 integration.\n\n* fix: preserve session accounting and read-only persistence boundaries\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"exec.ts","kind":"file","size":3135,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"footer-data-provider.ts","kind":"file","size":9239,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"goals.ts","kind":"file","size":7729,"lastCommitHash":"6e1c74a85086204e714665a3a51adee0c23b8fc0","lastCommitWhen":"2026-09-17T09:21:12+03:00","lastCommitMessage":"fix(coding-agent): hide model-facing goal accounting metadata\n"},{"name":"index.ts","kind":"file","size":2610,"lastCommitHash":"8893b31d897aa1ab16473fdff7cb9eb82782632f","lastCommitWhen":"2026-06-15T14:04:34-07:00","lastCommitMessage":"Add harness refinement command (#97)\n\n* feat(coding-agent): add harness refinement command\n\n* fix(coding-agent): expose harness on callable rlm\n\n* test(coding-agent): cover refinement action matrix\n\n* feat(coding-agent): persist harness state globally\n\n* feat(coding-agent): inject harness overview into prompt\n\n* feat(runtime): add explicit harness CRUD methods\n\n* feat(coding-agent): align harness specs with rlm calls\n\n* fix(coding-agent): address harness review comments\n\n* fix(runtime): skip malformed harness records\n\n* fix(runtime): normalize harness entry versions\n\n* fix(runtime): normalize refinement change entries\n\n* fix(coding-agent): require current harness runtime\n\n* feat(refinement): add harness skill argument contracts\n\n* fix(refinement): require python references for harness skills\n\n* fix(refinement): address review hygiene issues\n\n* fix(runtime): normalize loaded harness entry ids\n\n* fix(runtime): normalize loaded harness entry kinds\n\n* fix(refinement): support agent connection refine command\n\n* fix(runtime): normalize loaded harness path fields\n\n* fix(refinement): harden daemon refine requests\n\n* fix(refinement): merge cross-process harness writes and make rollback global\n\n- reload harness_state.json on the kernel side when its mtime changes so\n  in-kernel rlm.harness writes no longer clobber host /refine edits\n- append refinement results to a global refinements.jsonl log and source\n  rollback history from it so a refinement applied in one session can be\n  rolled back from another\n- update kernel-and-rlm-recursion docs for global storage and rollback\n\n* fix(refinement): address review-bot findings on /refine\n\n- host /refine now plans the proposal, then re-reads harness_state.json\n  immediately before applying so concurrent kernel/cross-session writes\n  during the LLM pass are not clobbered (split planRefinement/apply)\n- RPC refine uses the 10min request timeout instead of the default 30s\n- interactive /refine rollback works in a fresh session (skips the\n  no-trajectory guard, which only applies to learning refinements)\n- python create/update sync from disk once via _upsert so create-or-fail\n  cannot be downgraded to a silent update by a second reload\n\n* fix(refinement): harden harness state against corrupt files and partial updates\n\n- load() tolerates corrupt/non-object harness_state.json (python and ts)\n  and degrades to empty instead of crashing the kernel or prompt build\n- guard module-level harness init so a load failure cannot break import rlm\n- skill/entry update preserves omitted reference/arguments/metadata instead\n  of wiping the stored contract; an explicit {} still clears\n\n* fix(refinement): preserve omitted update fields and guarantee safe harness fallback\n\n- python update/_upsert now preserves an entry's path when omitted (was reset\n  to the method default), matching the reference/arguments/metadata behavior\n- update_skill no longer requires re-sending the reference on title/content-only\n  updates; it validates only when a reference is supplied and otherwise preserves\n- HarnessState gains a true in_memory mode (no path resolution, no disk) used as\n  the import-time fallback so a path-resolution failure cannot recur or crash\n\n---------\n\nCo-authored-by: Kevin Thomas <kevin.jt2007@gmail.com>"},{"name":"keybindings.ts","kind":"file","size":13863,"lastCommitHash":"e5f052c63af15817e86a4862789d0e08982d4878","lastCommitWhen":"2026-09-17T12:13:45+03:00","lastCommitMessage":"refactor(coding-agent,tui): call the feature a pasted file, one line and no hash\n"},{"name":"logging.ts","kind":"file","size":988,"lastCommitHash":"e8b7168cc9972694232a9ed9c0a6a51655e44abf","lastCommitWhen":"2026-09-10T13:33:51+02:00","lastCommitMessage":"fix bedrock provider loading in packaged cli installs (#2134)\n\n* fix(ci): accept engineering and research Linear tickets\n\n* fix(ci): clarify the Research ticket project\n\nfixes #2124\n\n* fix(coding-agent): include the lazy Bedrock provider in CLI bundles\n\nFixes ENG-6006\n\n* fix(ci): clarify Prime Agent board routing\n\nfixes #2124\n\n* fix(coding-agent): preserve structured Bedrock logs\n\nfixes #2134\n\n* test(coding-agent): await Bedrock fixture daemon shutdown\n\nfixes #2134\n\n* fix(ci): require complete Linear ticket identifiers\n\n* test(coding-agent): guarantee Bedrock fixture cleanup\n\n* test(coding-agent): allow context before Bedrock prompts\n\n* test(coding-agent): allow context before literal prompts\n\n* fix(ci): isolate Ubuntu package sources"},{"name":"messages.ts","kind":"file","size":38217,"lastCommitHash":"a94490eda202a79bb524e9822bb6c8bf6f3f04ea","lastCommitWhen":"2026-09-18T00:07:24+03:00","lastCommitMessage":"coding-agent: answer the tool call a replaced session left unresolved\n"},{"name":"model-registry.ts","kind":"file","size":84135,"lastCommitHash":"d0913ca17f0784abfa2ae053d365fe7f9e9a4051","lastCommitWhen":"2026-09-17T10:01:48+03:00","lastCommitMessage":"fix(coding-agent): honor provider quota deadlines and preflight lane health\n"},{"name":"model-resolver.ts","kind":"file","size":25244,"lastCommitHash":"807ff048eb53506be7add0116c17f3047292ac8f","lastCommitWhen":"2026-09-14T02:50:56-04:00","lastCommitMessage":"[RSI] fix(coding-agent): wait for model catalog readiness before restore fallback (#2313)\n\n* fix(coding-agent): wait for model catalog readiness before restore fallback\n\nSession-model restore decided against pre-refresh registry state: right\nafter a daemon restart (nightly update), the Prime Inference catalog fetch\nand private-authorization refresh had not settled and auth storage had not\nbeen picked up yet, so a session saved with\nprime-inference/openai/gpt-6-astra could silently fall back to another\nprovider's same-named model (openai-codex/gpt-6-astra) that displays\nidentically in the TUI.\n\n- ModelRegistry now tracks the in-flight catalog refresh kicked by\n  refreshAvailableModels() and exposes waitForPendingModelRefreshes(ms),\n  a bounded wait that also covers the background private-authorization\n  refresh.\n- restoreModelFromSession() and the SDK buildSessionContext restore now\n  wait (bounded, default 5s) for those refreshes to settle and retry the\n  lookup once before concluding restore failure. Fallback ordering and\n  messages are unchanged when the wait expires.\n\n* chore(coding-agent): add changelog fragment for restore-readiness fix\n\n* docs(coding-agent): state current restore-readiness behavior in comment and test title\n\nThe findSessionModelWithReadinessWait doc comment and the expiry test title\nframed behavior as a comparison with the previous synchronous lookup\n(\"the old synchronous restore lookup\", \"keeps today's fallback\"). Rewrite both\nto state what the code does now: synchronous fast-path lookup, then a single\nrefreshed retry bounded by readinessTimeoutMs, then undefined with the caller\napplying the fallback. Behavior code unchanged."},{"name":"new-session-command.ts","kind":"file","size":2349,"lastCommitHash":"05aa747fec4311e6361165d4d1ea93fe0c93fce4","lastCommitWhen":"2026-07-28T19:34:27+02:00","lastCommitMessage":"feat(coding-agent): start named sessions with prompts (#546)"},{"name":"orphan-process-journal.ts","kind":"file","size":5676,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"output-guard.ts","kind":"file","size":2009,"lastCommitHash":"f1fe49a641cfd7698325a0c9024a127c50a104a9","lastCommitWhen":"2026-03-22T21:21:29+01:00","lastCommitMessage":"fix(coding-agent): reserve stdout in print and json mode closes #2482\n"},{"name":"package-manager.ts","kind":"file","size":75254,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"platform-fidelity.ts","kind":"file","size":8558,"lastCommitHash":"9c59b394cac2bad490a38d7eee55efe8b0d03d86","lastCommitWhen":"2026-09-15T11:58:21-07:00","lastCommitMessage":"fix issues found while validating native releases (#2361)\n\n* add platform fidelity telemetry: libc, cpu baseline, os release\n\nos_family + architecture cannot answer whether Linux users are on musl or\nwhether x86_64 users have AVX2. Both gate replacing the 377 MB standalone-Node\nbootstrap with a single native binary.\n\nbaseProperties() now also reports libc, libc_version, cpu_baseline, os_release\nand os_product_version. Detection lives in core/platform-fidelity.ts: no\nsubprocesses, bounded reads, memoized per process, and every failure path\ndegrades to \"unknown\" instead of throwing.\n\n* make the version check and npm bridge suites hermetic\n\nthese two suites read update and daemon-worker environment variables, so running\nthem from inside a live prime-agent session inherited that session's own settings\nand produced 4 and 24 failures while ci stayed green.\n\na shared test/ambient-env.ts helper now lists every variable the code under test\nreads, clears them for in-process tests, and strips them from the environment\nhanded to spawned children. no test behaviour was weakened; cases that need a\nvariable set it themselves.\n\n* route commands written after global flags\n\nprime-agent only treated argv[1] as a subcommand, so forms like\n`--offline model list` and `--daemon-socket <path> status --json` were sent to\nthe model as chat messages. Share the positional scan used by the early daemon\nlaunch decision with public command routing and rotate leading global flags\nbehind a recognized command. `--` and one-shot print runs still keep their\npositional as message text.\n\n* scope daemon discovery to the state root it runs in\n\n* give the compiled executable probe a workable timeout\n\ncold rosetta 2 translation of the 51 mb darwin-x64 binary takes about 11s, so the flat 10s probe deadline failed every install on apple silicon. raise the default budget to 60s, allow PRIME_AGENT_PROBE_TIMEOUT_SECONDS to override it, and report a probe timeout as a timeout instead of claiming the machine cannot run the executable.\n\n* keep hidden supervisors in scope for home-scoped daemon discovery\n\nA supervisor that hands its runtime to a successor is no longer the\nregistered owner, so the ownership registry cannot name it and only the OS\nsocket sweep can still see it. Scoping discovery to the socket dir plus the\nregistry therefore put those hidden supervisors out of reach of daemon ps\nand shutdown --force, leaking them permanently (ENG-4603 regression).\n\nA socket inside our agent dir is unambiguously ours, because another HOME\nresolves to another agent dir, so the matcher now honours it. That restores\nthe reach the regression test expects without widening scope back to the\nwhole machine.\n\n* keep rotated global flags ahead of the -- separator\n\n* treat help written after global flags as a help request\n\n* trust the glibc runtime over an installed musl loader in telemetry\n\n* describe os_release honestly in the telemetry disclosure\n\n* read leading-zero probe timeout overrides as decimal\n\n* fix(coding-agent): spawn the eng-4603 supervisor fixture in-process for shutdown discovery\n\nThe tsx CLI wrapper forks: the spawned pid owns only tsx IPC pipes while\nthe real supervisor (and its daemon socket) hides in an untracked child\npid, so the shimmed OS socket sweep only ever saw the wrapper pipes.\nPre-merge shutdown --force passed by force-killing those wrappers; the\nstate-root scoping correctly disowns them (they sit in TMPDIR/tsx-<uid>,\nnot our socket dir, agent dir, or registry), which left the chain\nstopped-nowhere and failed the regression. Run the fixture with\nnode --import tsx's ESM loader so the spawned pid is the listener again.\n\n* keep the help topic when an explicit help flag follows it\n\n* fix(coding-agent): include the legacy registry and skip stale records in scoped daemon discovery\n\nScoped discovery reads only the current supervisor ownership registry,\nso daemons started before the registry moved out of the socket dir became\ninvisible to daemon ps and shutdown --force under the same agent dir;\nand one record whose agent dir can no longer be canonicalized aborted\nthe whole sweep. Read the legacy location too (mirroring the fence and\nowner-assert paths, gated off when the registry is overridden) and skip\nper-record canonicalization failures so one stale record cannot hide the\nrest. Document why the socket dir stays part of the state root.\n\n* mirror parseArgs value consumption in the command scanner\n\n* keep a version request ahead of command routing\n\n* keep short version flags ahead of command routing too\n\n* treat system prompt runs as prompt runs instead of rotating their message\n\n* boot the daemon early for prompt-value runs that keep their word on the chat path"},{"name":"prime-inference-auth.ts","kind":"file","size":21756,"lastCommitHash":"988e4f41dd25a6f3df9cfc66f45496d630be1969","lastCommitWhen":"2026-09-17T08:25:36+03:00","lastCommitMessage":"fix: reconcile the rebased fork with upstream's refactors\n\nSecond pass over the residue the rebase left behind: the tree now\ntypechecks and lints clean, and the touched suites pass.\n\n- finish the credential reconciliation (firstCredential readers, MCP\n  static tokens, prime-cli config read/write helpers and the private\n  prime-cli accessors the fork's call sites need)\n- restore dropped wiring: the bash.consumed host request, the MCP\n  discovery assertions in the kernel ready check, and the snapshot\n  extras (activity, tool use, previews, labels, staleness) on kernel\n  roster entries next to the fork's turn/token accounting\n- rebuild the interactive-mode class fields and the /reload + /usage +\n  /context dispatch, and restore the async-bash header snippet\n- re-merge the agents view on upstream's newer file instead of the\n  per-commit resolutions, so the fork's view model survives: the\n  actions pane and its renderSessionRows early return, compactSessionRows\n  over the raw allRows, the pinned/expanded row markers and the\n  completed/needs-input icons, the running-subagent rows, and the\n  model-plus-host row label. upstream's timer-batched catalog reconcile\n  and its rebuild-free tick loop are kept, with a live cache ttl counted\n  as work so the ttl keeps counting down; the tray label providers dropped\n  upstream's redundant inline-picker guard\n- skip the quota wait when an unblocked sibling credential exists, so\n  the fork's quick account rotation still wins over a long Retry-After\n- restore real timers in the compaction regression suite, which the\n  preceding fake-timer test left mocked, and hold the fork's contracts in\n  the queue suite (200-message ceiling, batched steering) and the 4649\n  name-reservation test\n- drop upstream's subagentDefaultModel suite and its inherit-parent case:\n  this fork keeps an explicit model= on every spawn\n- move the deferred-session-event tests back to top level and wait on\n  the connection's own status sequence instead of a wall-clock poll\n- keep the fork's lazy session-open and sqlite catalog paths as the\n  session-loading fast path\n"},{"name":"prime-inference-model-catalog.ts","kind":"file","size":7355,"lastCommitHash":"2f5cd0cc163149ad8345f2c7eefe9ce08278cb0a","lastCommitWhen":"2026-09-14T08:24:50+02:00","lastCommitMessage":"fix(coding-agent): keep refinement passes from evicting the session prompt cache (#2220)\n\n* fix(coding-agent): keep refinement passes from evicting the session prompt cache\n\nRefinement review and planning run with their own prompt prefixes, so\nissuing them on the session model replaces the provider prefix-cache\nentry for the session; the next session request then re-reads its whole\ncontext. Add an auxiliaryModel setting that routes those passes to a\ndifferent model when configured, falling back to the session model.\n\nAlso send anthropic-style cache_control markers for anthropic/* Prime\nInference models so prompt caching engages on gateways that pass them\nthrough to the upstream Anthropic API, matching the Anthropic cache\npricing the catalog already applies to those entries.\n\n* fix(coding-agent): harden auxiliary refinement model review findings\n\nTreat malformed persisted auxiliaryModel values (non-string) as unset so\nrefinement falls back to the session model instead of throwing, and drop\ncaught error details from the fallback warning since auth-stack errors can\nembed credential material (CodeQL js/clear-text-logging).\n\n* refactor(coding-agent): drop unused setAuxiliaryModel setter\n\nCursor review flagged the setter as speculative surface: no product or test\ncode calls it, so the auxiliary model is configured only through settings\nfiles and read via getAuxiliaryModel."},{"name":"prime-inference-model-selection.ts","kind":"file","size":1088,"lastCommitHash":"a2bc615663993892a7dec49268ae6f5b8b5a96ea","lastCommitWhen":"2026-07-14T19:01:37-07:00","lastCommitMessage":"fix(coding-agent): persist prime inference model (#400)"},{"name":"prime-inference-models.ts","kind":"file","size":3111,"lastCommitHash":"b9cf467edf8bbbd8e607991cf770407d62daa8ec","lastCommitWhen":"2026-09-07T02:15:35-04:00","lastCommitMessage":"Improve session navigation, model discovery, and background commands (#2068)\n\n* feat(coding-agent): show the model label on every agents-view row\n\nResident summaries carry model info for all session kinds; only the\nrenderer restricted the label to subagent rows. Drop the special case so\nany row whose summary has a model renders provider/id[:thinkingLevel] in\nthe suffix region, still suppressed while pending delete/kill.\n\n* fix(coding-agent): open visible sessions without waiting for selection anchors\n\nConsolidates #2079 at d5b49266b5829a4ea8f46ad76b525e0e560ace03.\n\n* feat(tui): open local file links\n\nConsolidates #2073 at b6e83f0f2db71c705d48ef14b499a513c1506f4d.\n\n* feat(coding-agent): highlight file references and command options\n\nConsolidates #1145 at 285ccf457c2f94508b5764d0ab1cc1b4b79a6d61.\n\n* feat: refresh Prime Inference models from the live catalog\n\nConsolidates #1928 at 24d3413c304cefbb063e86a7e41c85207916d90e.\n\n* feat(coding-agent): let root agents create sibling sessions\n\nConsolidates #1996 at 0c9c883c951097183664cf82453856cca21c8ac3.\n\n* feat(coding-agent): wake agents when asynchronous bash finishes\n\nConsolidates #2053 at 1bb4d43a0a64366217f8fec38d574e3917fa550d.\n\n* feat(coding-agent): simplify the agents view while retaining model details\n\nConsolidates #2087 at dc67428af10b1b2fbe63d996e52ede6116bb4d62.\nRetains #2068 model visibility and #2079 immediate opening and query ownership.\n\n* fix(coding-agent): preserve background work and sibling-session credentials\n\nKeep managed shell commands active until completion delivery is accepted.\nForward only effective same-provider transient auth when creating root sessions.\nIntegration fixes for #2053 and #1996.\n\n* fix(coding-agent): address session lifecycle and rendering regressions\n\nPreserve sibling PATH and reject root creation after disposal.\nTreat background completions as new runs without duplicate as_completed wakes.\nKeep table delimiters visible and sanitize live catalog display metadata.\nScope the stale-auth regression fixture to its cached Prime team.\n\n* fix(coding-agent): forward the selected provider environment credentials\n\nPreserve alias priority and runtime credential identity when creating sibling sessions.\nPin that a create timeout never dispatches the task prompt.\n\n* fix(runtime): recheck creating-cell waits when shell commands settle\n\nPreserve late as_completed consumers without suppressing detached completion notices.\nDocument the cached-wrapper result limitation.\n\n* fix(runtime): preserve background bash completion lifecycle\n\nWait for process-group cleanup before releasing residency. Defer paused admission within the original request and report terminal rejection.\nPreserve notices after cancelled non-owning waits and clean up interrupted task construction.\n\n* fix(runtime): use a portable signal for construction cleanup\n\nKeep immediate POSIX cleanup and use the existing Windows job cleanup path without referencing SIGKILL.\n\n* fix(coding-agent): steer shell messages and stop losing supervisor launches\n\nDeliver labeled shell completion messages at the next safe turn boundary.\nStop only an owned replacement child that loses to a current authenticated supervisor.\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"prompt-admission.ts","kind":"file","size":1294,"lastCommitHash":"2f218e15130904568a805ac8d1920927747d7791","lastCommitWhen":"2026-07-30T17:38:20+02:00","lastCommitMessage":"feat: unified agents and resume view (#541)\n\n* feat(coding-agent): unify searchable session view\n\n* fix(tui): keep session durations stable\n\n* test(daemon): tolerate partial session manager fixtures\n\n* test(tui): narrow session view race coverage\n\n* fix(tui): stabilize unified session catalogs\n\n* fix(tui): preserve session view lifecycle\n\n* fix(tui): preserve compact session view layout\n\n* test(tui): align cumulative session fixtures\n\n* fix(tui): preserve unified session identity and drafts\n\n* feat(tui): color recognized slash commands\n\n* fix(tui): keep view cancels and subagent matches local\n\n* test(tui): avoid platform-specific markdown styling\n\n* fix(tui): align session view status, reselect, and local resume flows\n\n* test(tui): consolidate slash command rendering coverage\n\n* test(tui): cover session view exit shutdown from chat\n\n* fix(tui): preserve dynamic command presentation\n\n* test(coding-agent): deadline-wait the create dedup race\n\n* test(coding-agent): align stacked fixtures\n\n* fix(tui): show seconds for sub-minute heartbeat countdowns\n\n* test(coding-agent): align cumulative session behavior\n\n* fix(coding-agent): flush child traces regardless of retention\n\n* fix(tui): single-own replacement catalog refresh\n\n* fix(tui): preserve drafts and completed child traces\n\n* fix(coding-agent): align template argument whitespace\n\n* fix(tui): restore saved sessions after reconnect\n\n* test(coding-agent): consolidate command presentation coverage\n\n* feat(tui): resume saved sessions from the reply composer\n\n* fix(tui): require heartbeat reconnect probe\n\n* test(coding-agent): align cumulative admission errors\n\n* fix(tui): schedule resumed replies from the resume summary\n\n* test(tui): align lifecycle stash handoff result\n\n* test(coding-agent): preserve unique lifecycle coverage\n\n* fix(tui): preserve inactive reply state on failures\n\n* fix(tui): route local agents view startup\n\n* refactor(tui): single-owner command catalog refresh\n\n* fix(tui): preserve selection after saved resume\n\n* test(tui): align startup lifecycle handoff\n\n* test(tui): resolve cumulative submit fixture\n\n* fix(tui): preserve in-flight reply drafts\n\n* test(tui): align owned startup exit shape\n\n* test(daemon): align delivery waiter contract\n\n* fix(tui): refresh resumed reply failures\n\n* fix(tui): preserve search selection\n\n* style(test): format cumulative prompt coverage\n\n* fix(agents-view): refresh reply target before send\n\n* fix(tui): complete onboarding before sessions\n\n* fix(tui): fence resync rendering by generation\n\n* refactor(coding-agent): consolidate prompt-admission cancellation\n\nExtract one shared waitForPromptAdmission helper and typed\nPromptAdmissionCancelledError into core/prompt-admission.ts, replacing\nthree near-identical copies in agent-session, daemon-mode, and\ndaemon-supervisor along with their copy-paste tests and the supervisor's\nstringly cancelled-status cast.\n\nAlso:\n- make _steeringStopPending a derived getter instead of a cached field\n  manually re-synced at 15 call sites\n- surface genuine handoff errors in _isDeferredSessionInputError instead\n  of silently requeueing them when the session is coincidentally busy\n- remove the production-dead pauseQueuedWork shim and narrow\n  resumeQueuedWork to pump-suspension recovery only\n\n* test(coding-agent): deterministic waits and shared test helpers\n\n- replace the 50ms sleep proving no queued turn starts after\n  abortForUpdateRestart with waitForSessionInputIdle\n- replace the 300ms sleep proving no prompt retry after an uncertain\n  admission failure with a bounded microtask drain\n- use the shared createDeferred from suite/scheduling.ts instead of two\n  local reimplementations\n- guard Reflect-based private access in the agents-view and supervisor\n  harnesses so renamed members fail with explicit messages, and document\n  why the constructor-bypass supervisor harness exists\n\n* chore(coding-agent): trim redundant comments from recent refactors\n\n* fix(coding-agent): guard session-input error surfacing against listener throws\n\nA throwing extension error listener could escape _surfaceSessionInputError\ninside _isDeferredSessionInputError before the pump requeued undelivered\nprompts, dropping them. Surfacing is now best-effort.\n\n* chore(coding-agent): tighten fix comment\n\n* fix(tui): keep the selection anchor across fallback unblocking\n\nResolving a missing anchor no longer overwrites the persisted anchor\nidentities with the visible fallback row, and typing while the anchor is\npending no longer claims the fallback either, so a late poll that\ndelivers the intended session re-anchors selection instead of opening\nthe wrong session.\n\n* fix(tui): open the unified session view on back navigation in local chats\n\nThe left-arrow back gesture only worked for daemon-backed sessions;\nprocess-local chats could reach the same unified view only via /resume.\nBack navigation now routes through requestAgentsView, which opens the\nlocal session view in place for process-local sessions.\n\n* fix(tui): preserve reply statuses across post-reply catalog refreshes\n\nThe refreshes triggered after a reply send or a failed resumed send used\ndefault error handling, so a failing catalog refresh could overwrite the\nsticky cwd-fallback notice or the send-failure message. Both refreshes\nnow preserve the current status on error.\n\n* chore(tui): drop redundant back-navigation comment\n\n* chore(tui): tighten reply-status comments\n\n* feat(tui): new session shortcut and steer/queue reply delivery\n\nctrl+n (app.agents.new) creates a fresh daemon session from the agents\nview and opens it. In the reply composer, Enter now steers a streaming\nagent and alt+enter (app.message.followUp) queues the reply as a\nfollow-up. While the composer is armed the hint line switches to\ncomposer hints: steer/send/resume & send, queue once text is typed, and\nesc to cancel.\n\n* feat(tui): session-owned slash commands in the reply composer\n\n/compact, /refine, /goal, and /autonomous pass through the daemon\nprompt path from the agents-view reply composer, with slash\nautocomplete active only while a reply target is armed. Other built-in\ncommands are rejected with guidance instead of being sent to the model\nas plain text.\n\n* feat(tui): view commands in the agents view\n\n/new, /fork, /name, and /kill run from the search editor against the\nselected row and from the armed reply composer against its target,\nwith autocomplete in both contexts. /fork forks at the current leaf via\nthe existing daemon fork RPC, resuming saved rows first; /name renames\nactive or saved sessions; /kill stops a running agent. Unknown or\nsession-only commands are rejected with guidance and plain text remains\na search query. The search hints now advertise \"/ commands\".\n\n* fix(tui): harden new-session shortcut and follow-up delivery\n\nctrl+n no longer fires while the reply composer is armed, so an unsent\ndraft cannot be discarded by opening a new session. Alt+Enter now\nexpands paste markers like Enter does. A session created after the view\nalready finished is killed instead of orphaned in the agents list.\n\n* fix(tui): preserve rejected drafts and bind completions to the target cwd\n\nA rejected command no longer loses the typed text (submitValue clears\nthe buffer before onSubmit; the rejection path now restores it unless\nnewer input arrived). The composer autocomplete provider is rebuilt\nwhen a target is armed, so @-file completions resolve in the target\nsession's cwd instead of the view's startup directory.\n\n* fix(tui): harden view commands against races, stale composers, and cancels\n\nAdapter-mode search no longer suggests view commands it will not run.\nArmed view commands cannot double-run (the buffer is already clear\nduring the RPC) and a failed command restores the typed draft in both\nthe composer and the search editor, without clobbering newer input.\nComposer disarm after /kill and /fork is guarded against a composer\nre-armed mid-command, and a fork cancelled by an extension is reported\nas cancelled instead of success.\n\n* fix(tui): report new-session outcome to callers\n\ncreateNewSession returns whether a session was created and opened, so\ncommand callers can restore a cleared draft on failure.\n\n* fix(tui): refresh after failed resumed forks and propagate /new outcome\n\nA saved row resumed for a fork that then fails, cancels, or has nothing\nto fork now refreshes the catalog so the newly live session appears\nimmediately. /new propagates createNewSession's outcome so a failed\ncreate restores the cleared draft.\n\n* fix(tui): enable @-path completion in the reply composer\n\nThe composer provider was built without an fd path, so @ fuzzy file\nsearch always returned empty. The view now resolves fd once and rebinds\nan armed provider when it becomes available.\n\n* fix(tui): create sessions over a dedicated connection\n\nfinish() closes the shared client, which rejected an in-flight create\nand made its session unkillable; a missing client also threw before the\nguard reset, permanently disabling the shortcut. Session creation now\nruns on its own short-lived connection inside the guarded try, so the\norphan-kill path works even after the view finished.\n\n* fix(tui): harden view commands against stale targets and filter churn\n\nSlash input in the search editor no longer filters the list, which\ncould swap the selected row before Enter ran the command on it. The\narmed composer re-resolves its captured summary before dispatch so\n/kill, /name, and /fork act on the current runtime, and rejects view\ncommands under the local adapter instead of sending them as prompt\ntext. A session resumed only to serve a fork is stopped again when the\nfork fails or is cancelled.\n\n* docs(tui): move the dedicated-connection rationale to its helper\n\n* fix(tui): drop submitted view commands from the persisted query\n\nsubmitValue clears the editor without queryChanged, so a successful\nsearch-editor command stayed in persistentState.query and a remount\nrestored it where Enter could re-run it on an arbitrary row. Failed\ncommands restore the draft through setSearchQuery so the persisted\nquery stays in sync.\n\n* fix(tui): only freeze the search filter for recognized command input\n\nUnknown slash-prefixed terms like /foo stayed unfiltered because any\nleading slash suppressed the query. The filter now freezes only while\nthe input is a view command or a prefix that can still extend into one,\nso ordinary slash search terms keep filtering.\n\n* fix(tui): warn on view commands in the adapter search editor\n\nAdapter sessions fell through to openSelected() when a view command was\ntyped, opening an unrelated row. The search branch now rejects them\nwith the same unavailable-command warning the reply composer shows.\n\n* test: consolidate overlapping reply-composer tests\n\n* test: fold command-classification cases into one test\n\n* test: consolidate overlapping view-command tests\n\n* refactor(tui): drop the /fork view command\n\nThe in-place daemon fork semantics (runtime rebind at the current leaf,\nresume-then-rollback for saved rows) carried a third of the view-command\ncomplexity for a command whose behavior we already flagged as awkward\nuntil isolated forking lands. /new, /name, and /kill remain.\n\n* fix(tui): restore the draft when the adapter search rejects a command\n\nsubmitValue had already cleared the buffer, so the warning silently ate\nthe typed command; it now comes back through setSearchQuery like other\nfailed search-editor commands.\n\n* test: fold sendReply delivery and follow-up keybinding cases together\n\n* test: fold draft-restore rejection cases together\n\n* docs(tui): tighten create-session comments\n\n* docs(tui): tighten the fd-rebind comment\n\n* test: fold overlapping composer tests; tighten comments\n\n* fix(tui): ctrl+c cancels the armed composer as its hint advertises\n\napp.clear ran first and started the exit flow, so a second ctrl+c could\nexit the view and discard the draft.\n\n* fix(tui): refresh the saved catalog after a live /name rename\n\nOnly the live list was refreshed, so the stale saved entry resurfaced\nthe old name once the agent was killed. Mirrors confirmRename.\n\n* fix(tui): gate search autocomplete on command input; refresh both catalogs after /kill\n\nAbsolute-path queries like /tmp/ fell through CombinedAutocompleteProvider\nto filesystem completions; the search editor now uses the same\nisAgentsViewCommandInput predicate as the filter freeze. Catalog\nrefreshes after rename and kill go through a shared refreshBothCatalogs\nso a killed agent reliably reappears under Inactive.\n\n* refactor(tui): share one renameSession path between rename mode and /name\n\n/name reimplemented the rename separately: it reported success before\nthe refresh and missed the older-daemon restart hint. Both entry points\nnow use the same rename/refresh/report sequence.\n\n* fix(tui): tolerate an already-finished agent in /kill\n\ndeactivatePendingAgent treats \"Unknown active session\" as already\nstopped; /kill surfaced the same race as a raw error.\n\n* docs(tui): drop comments that restate adjacent code\n\n* refactor(tui): search-only search bar; retire /resume and the local session view\n\nThe agents-view search bar no longer parses commands: /name and /kill\nlive only in the armed reply composer (their target is captured\nexplicitly), and new-session stays on its keybinding. This deletes the\nsearch-command autocomplete, the filter-freeze machinery, and the\npersisted-query replay handling that command input required.\n\nSession browsing is daemon-only: /resume and bare --resume are removed\nalong with the process-local SessionViewAdapter and every adapter\nbranch in the view. --resume <id|path> still resumes directly;\nnon-daemon `agents` warns and opens a chat. The chat hint now reads\n\"agents/resume\".\n\n* test: port #502 saved-catalog regressions off the removed adapter seam\n\nThe adapter layer was removed with /resume, so refreshSavedSessions now\nstreams list_saved_sessions through the daemon client and confirmRename\ndelegates to the shared renameSession path. The #502 regression harnesses\nstill faked options.adapter, so three tests failed (and two more passed\nonly because the missing client stub produced the expected false). Rebuild\nthem against client.request with onProgress streaming and the renameSession\ndelegate; behavior under test is unchanged.\n\n* chore: drop orphaned JSDoc for the removed bare --resume option"},{"name":"prompt-cache.ts","kind":"file","size":6524,"lastCommitHash":"cd73c7651be077e59e3175d48b7df77535bc2307","lastCommitWhen":"2026-09-17T07:04:34+03:00","lastCommitMessage":"feat(coding-agent): a prompt payload ceiling and pinned model metadata (R15)\n\nModels empirically probed context limits and produced a 6.5M uncached-token\nblowout. Now:\n\n- the compiler computes a payload ceiling from the model's real context window\n  and refuses to build a larger payload, reporting what was dropped or what to\n  do rather than silently truncating mid-turn\n- model metadata (context window, max tokens, cost, reasoning) is pinned per\n  model id for the life of a session, so the per-request path no longer\n  re-derives it from a remote refresh (`refreshModelsDev` stays for discovery)\n- the effective context window and the ceiling are stated once where the model\n  can read them, instead of being something it probes for\n\nNo text was added that tells the model to compact or shorten because context is\nlong: per P1 the harness owns compaction and the numbers are measurements.\n\nTests: test/suite/prompt-payload-limit.test.ts (11); regressions re-run:\nagent-session-prompt (65), agent-session-compaction (39).\n"},{"name":"prompt-templates.ts","kind":"file","size":8307,"lastCommitHash":"24519c30856965a832551206b3e9ed87e814d602","lastCommitWhen":"2026-09-09T10:36:30+02:00","lastCommitMessage":"preserve literal dollar sequences in prompt arguments (#2128)\n\n* fix(ci): accept engineering and research Linear tickets\n\n* fix(coding-agent): preserve literal prompt arguments\n\nRefs: ENG-6014 and discussion #2106.\n\n* fix(ci): clarify the Research ticket project\n\nfixes #2124\n\n* fix(ci): clarify Prime Agent board routing\n\nfixes #2124"},{"name":"provider-display-names.ts","kind":"file","size":1128,"lastCommitHash":"ca67580b524800a971f92420d4c665bd83df1dfa","lastCommitWhen":"2026-09-11T23:36:41-07:00","lastCommitMessage":"add grok subscription authentication (#2252)\n\n* add grok subscription authentication\n\nFixes ENG-6059\n\n* trim redundant grok authentication tests\n\nRefs ENG-6059\n\n* keep xai authentication in the existing login modal\n\nFixes ENG-6059\n\n* return false for unsupported xai model availability\n\nFixes ENG-6059\n\n* refresh daemon model state after authentication changes\n\nFixes ENG-6059\n\n* use keyed fingerprints for credential-scoped model caches\n\nFixes ENG-6059\n\n* clean up credential rotation test formatting\n\nFixes ENG-6059\n\n* show all grok models and improve provider search"},{"name":"provider-retry.ts","kind":"file","size":10387,"lastCommitHash":"d0913ca17f0784abfa2ae053d365fe7f9e9a4051","lastCommitWhen":"2026-09-17T10:01:48+03:00","lastCommitMessage":"fix(coding-agent): honor provider quota deadlines and preflight lane health\n"},{"name":"resolve-config-value.ts","kind":"file","size":4461,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"resource-loader.ts","kind":"file","size":33417,"lastCommitHash":"05b6b37322425223a515ac7284a2593333076c45","lastCommitWhen":"2026-09-17T06:51:37+03:00","lastCommitMessage":"coding-agent: defer the client extension reload on daemon attach\n"},{"name":"rlm-max-depth.ts","kind":"file","size":356,"lastCommitHash":"5929ebee6004da12602e8051e43a77b05118c80e","lastCommitWhen":"2026-08-05T04:46:50+02:00","lastCommitMessage":"feat(coding-agent): /rlm-max-depth session command (#585)\n\n* feat(coding-agent): /rlm-max-depth session command\n\nSession-owned command (fifth SessionCommandAction arm) controlling the RLM\nrecursion cap per D6 of the recursive-agent-harness plan:\n\n- /rlm-max-depth shows the effective cap and its origin\n  (chat/inherited/global/env/default)\n- /rlm-max-depth <int> sets it for this chat, persisted forever via an\n  rlm_max_depth_state JSONL entry (goal pattern, flushNow); children spawned\n  afterward inherit copy-at-spawn; no retroactive push-down, no upward\n  propagation; a child's own setting overrides its inherited value across\n  reopen (persisted chat state > spawn config > global > env > 1)\n- /rlm-max-depth <int> --global sets the settings.json default for new\n  sessions everywhere and pins this session\n- branch navigation reloads the persisted state alongside goal state and\n  refreshes the system prompt when the effective value changes\n- absolute-depth cap semantics unchanged (depth >= maxDepth blocks spawn)\n\nTrack A PR 3 of the recursive-agent-harness plan.\n\n* refactor(coding-agent): make /rlm-max-depth immediate with one-line feedback\n\nUser decision: make this a state command like /name that never steers or queues. Replace the compaction-style status message with dim one-line feedback while leaving persisted chat state and global settings behavior unchanged.\n\nInteractive and daemon AgentConnection clients use the immediate direct API. RPC has no dedicated command yet; sending /rlm-max-depth as a prompt is no longer a command path.\n\n* fix(coding-agent): preserve live command and prompt state\n\n- Clear /rlm-max-depth input before awaiting its daemon RPC so new drafts survive.\n- Resolve the system prompt per turn so active runs observe max-depth updates.\n\n* fix(coding-agent): preserve extension prompt on depth changes\n\n- Refresh the active extension-modified system prompt when RLM max depth changes.\n- Add regression coverage for preserving extension doctrine while applying new depth doctrine mid-run.\n\n* fix(coding-agent): report failed global saves when settings cannot parse\n\nSettingsManager.save bailed silently when the global settings file had\na load error: no write was enqueued and no error recorded, so after the\nstartup diagnostic was drained, setRlmMaxDepth reported globalSaved\neven though nothing reached disk. The bail now records a scoped\nsettings error so the drain reports the failure.\n\n* fix(coding-agent): resolve prompt after API key lookup\n\n- Resolve the live system prompt after asynchronous API key lookup, immediately before the provider call.\n- Add regression coverage for prompt changes during API key resolution."},{"name":"rlm-models.ts","kind":"file","size":2614,"lastCommitHash":"db7ff1c1e8f8f3f3db17285b028f8e4c872e3638","lastCommitWhen":"2026-09-17T07:01:44+03:00","lastCommitMessage":"fix(ai): update deepseek flash model to deepseek/deepseek-flash\n"},{"name":"rlm-runtime.ts","kind":"file","size":18793,"lastCommitHash":"988e4f41dd25a6f3df9cfc66f45496d630be1969","lastCommitWhen":"2026-09-17T08:25:36+03:00","lastCommitMessage":"fix: reconcile the rebased fork with upstream's refactors\n\nSecond pass over the residue the rebase left behind: the tree now\ntypechecks and lints clean, and the touched suites pass.\n\n- finish the credential reconciliation (firstCredential readers, MCP\n  static tokens, prime-cli config read/write helpers and the private\n  prime-cli accessors the fork's call sites need)\n- restore dropped wiring: the bash.consumed host request, the MCP\n  discovery assertions in the kernel ready check, and the snapshot\n  extras (activity, tool use, previews, labels, staleness) on kernel\n  roster entries next to the fork's turn/token accounting\n- rebuild the interactive-mode class fields and the /reload + /usage +\n  /context dispatch, and restore the async-bash header snippet\n- re-merge the agents view on upstream's newer file instead of the\n  per-commit resolutions, so the fork's view model survives: the\n  actions pane and its renderSessionRows early return, compactSessionRows\n  over the raw allRows, the pinned/expanded row markers and the\n  completed/needs-input icons, the running-subagent rows, and the\n  model-plus-host row label. upstream's timer-batched catalog reconcile\n  and its rebuild-free tick loop are kept, with a live cache ttl counted\n  as work so the ttl keeps counting down; the tray label providers dropped\n  upstream's redundant inline-picker guard\n- skip the quota wait when an unblocked sibling credential exists, so\n  the fork's quick account rotation still wins over a long Retry-After\n- restore real timers in the compaction regression suite, which the\n  preceding fake-timer test left mocked, and hold the fork's contracts in\n  the queue suite (200-message ceiling, batched steering) and the 4649\n  name-reservation test\n- drop upstream's subagentDefaultModel suite and its inherit-parent case:\n  this fork keeps an explicit model= on every spawn\n- move the deferred-session-event tests back to top level and wait on\n  the connection's own status sequence instead of a wall-clock poll\n- keep the fork's lazy session-open and sqlite catalog paths as the\n  session-loading fast path\n"},{"name":"sdk.ts","kind":"file","size":14954,"lastCommitHash":"988e4f41dd25a6f3df9cfc66f45496d630be1969","lastCommitWhen":"2026-09-17T08:25:36+03:00","lastCommitMessage":"fix: reconcile the rebased fork with upstream's refactors\n\nSecond pass over the residue the rebase left behind: the tree now\ntypechecks and lints clean, and the touched suites pass.\n\n- finish the credential reconciliation (firstCredential readers, MCP\n  static tokens, prime-cli config read/write helpers and the private\n  prime-cli accessors the fork's call sites need)\n- restore dropped wiring: the bash.consumed host request, the MCP\n  discovery assertions in the kernel ready check, and the snapshot\n  extras (activity, tool use, previews, labels, staleness) on kernel\n  roster entries next to the fork's turn/token accounting\n- rebuild the interactive-mode class fields and the /reload + /usage +\n  /context dispatch, and restore the async-bash header snippet\n- re-merge the agents view on upstream's newer file instead of the\n  per-commit resolutions, so the fork's view model survives: the\n  actions pane and its renderSessionRows early return, compactSessionRows\n  over the raw allRows, the pinned/expanded row markers and the\n  completed/needs-input icons, the running-subagent rows, and the\n  model-plus-host row label. upstream's timer-batched catalog reconcile\n  and its rebuild-free tick loop are kept, with a live cache ttl counted\n  as work so the ttl keeps counting down; the tray label providers dropped\n  upstream's redundant inline-picker guard\n- skip the quota wait when an unblocked sibling credential exists, so\n  the fork's quick account rotation still wins over a long Retry-After\n- restore real timers in the compaction regression suite, which the\n  preceding fake-timer test left mocked, and hold the fork's contracts in\n  the queue suite (200-message ceiling, batched steering) and the 4649\n  name-reservation test\n- drop upstream's subagentDefaultModel suite and its inherit-parent case:\n  this fork keeps an explicit model= on every spawn\n- move the deferred-session-event tests back to top level and wait on\n  the connection's own status sequence instead of a wall-clock poll\n- keep the fork's lazy session-open and sqlite catalog paths as the\n  session-loading fast path\n"},{"name":"semantic-edges.ts","kind":"file","size":19655,"lastCommitHash":"844e85545af6858dcb3d6cfe42bbfcf2ca0be4e5","lastCommitWhen":"2026-09-06T21:56:32-04:00","lastCommitMessage":"Harden session persistence, worker recovery, and daemon refreshes (#2028)\n\n* refactor(coding-agent): move the semantic-edge ledger onto the event-log substrate\n\nThe recorder's private append/replay/repair IO is deleted; EventLog owns it, the same move #1987 made for the RLM spawn ledger. One durability rule is unified in the substrate rather than dropped: an unterminated final line is an uncommitted append, skipped on read and truncated before the next append — never newline-completed and never surfaced to a consumer whose next append destroys it.\n\n* fix(coding-agent): make the explicit ledger reader's ENOENT contract atomic\n\nreadSemanticEdgeLedger probed with statSync before reading through EventLog, which swallows ENOENT; a ledger deleted between the two returned [] instead of throwing. The missing-file decision now lives at the single open (replaySync missingFileThrows), so no check-then-read window exists.\n\n* docs(coding-agent): state the event-log tail rule once\n\nThe unterminated-tail contract was restated four times (module doc, replaySync doc, two test comments). It now lives once in the module doc; the method doc keeps only its own parse/missing-file semantics and the test comments reference the contract.\n\n* fix(coding-agent): write event-log appends fully and gate appends on tail repair\n\nwriteSync may write short (ENOSPC after a prefix); appendSync now loops until the payload is fully on disk so write-before-action callers never act on a torn record reported as success. A tail-repair failure (e.g. append-only ACL permitting O_APPEND but not r+) now propagates instead of being swallowed: writing through an unrepaired torn tail would weld it to the new record as permanent interior corruption. ENOENT and the concurrent-writer instability path keep their existing semantics.\n\n* fix(coding-agent): reclaim short event-log writes instead of completing them\n\nThe rlm spawn ledger is multi-writer by documented design (supervisor plus each worker over one file), so completing a short O_APPEND write with a second write could interleave with a rival append and weld two records. A short write now truncates its own torn prefix back off (only while this writer still owns the tail) and fails the append; a torn tail is read-tolerated, a weld is permanent corruption. The append fd opens a+ so the ownership check can read the tail.\n\n* fix(coding-agent): leave the torn tail on a short write instead of reclaiming it\n\nThe tail-match reclaim could truncate a rival's committed record whose final bytes coincide with our torn prefix - committed-data loss, strictly worse than the torn tail it prevented. A short write now just fails the append: the torn tail is the one tolerated shape, skipped on read and truncated by any writer's next repair (verified for both topologies: a resumed single-writer recorder repairs on its first append; every rlm-ledger writer repairs before each append).\n\n* refactor(coding-agent): compress event-log comments\n\n* fix(ai): omit the default service tier, reprice cache writes from message_delta, repoint the zai default\n\nIncorporates #2032 at f82c7fa3688b7e25cef80e2663fe77ed153c5cd9.\n\n* fix(tui,coding-agent): survive lone surrogates in table cells and terminate the WebP EXIF scan\n\nIncorporates #2033 at a3d1139ee6e1f77337ab134b0f0c0cede8c942af.\n\n* fix(coding-agent): restart dead kernels on ensure() and read mcp>=2 tool schemas\n\nIncorporates #2034 at 749e216e901304b310ead9f46c3813a032608d7b.\n\n* fix: one crash-safe owner for durable state writes\n\nIncorporates #2035 at f0f02d2fb090ec427307a65b9e9578ae3c8fc783.\n\n* fix(coding-agent): one zombie-aware process-liveness probe\n\nIncorporates #2041 at 92a0eacf47efc831444b0b4e412f35bd17ac3f28.\n\n* fix(coding-agent): snapshot transfer ids from the materialized cursor; mismatches settle the transfer, not the worker channel\n\nIncorporates #2044 at 5af3bbe8090240507d6b0297d0da007159e15305.\n\n* fix(coding-agent): failed workers recover on touch; roster gaps answer a structured recovering error\n\nIncorporates #2047 at 77b747afab402a9e2f5eada227ffe6fed626a634.\n\n* fix(coding-agent): seven session and IO correctness defects\n\nIncorporates #2037 at 41b5d72d7758723f22ba07f8738d217868ed7baf.\n\n* fix(coding-agent): coalesce child-usage attribution and gate agent-status persistence on real changes\n\nIncorporates #2050 at 6b0af5d2679ddff987ef3b4d43235a872fe2b315.\n\n* fix(coding-agent): incremental single-flight session metadata scans\n\nIncorporates #2043 at df032c1192dd2e38d35fcbaca589db7194f26b6c.\n\n* fix(coding-agent): memoize the passive RLM topology derivation\n\nIncorporates #2051 at 0ee114ce77942d9298136ca193ddc2c0b5d27d58.\n\n* fix(coding-agent): preserve accounting and metadata across deferred updates\n\nKeep durable child-usage aggregates separate from pending sibling usage. Retry optional topology metadata after transient reads. Completes #2050 and #2051 integration.\n\n* fix: preserve session accounting and read-only persistence boundaries\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"session-action-store.ts","kind":"file","size":15222,"lastCommitHash":"dca77ecfe450adbd61c2555c3f1e8c5b70f6cf3f","lastCommitWhen":"2026-09-14T14:28:18-07:00","lastCommitMessage":"prioritize human messages ahead of queued agent traffic (#2334)\n\n* fix(coding-agent): deliver human messages ahead of queued agent traffic\n\nThe prompt queue was FIFO inside each delivery lane, so a message the user\ntyped landed behind every queued agent-to-agent prompt, bash completion\nnotice, heartbeat, and continuation. A busy session could not be steered or\nstopped until the backlog drained.\n\nSession actions now carry a priority. Queued actions sort by priority and\nstay FIFO within a priority, and nothing is inserted ahead of an action that\nalready left the queue. Human input keeps its own arrival order; scheduled\ncron prompts and machine-generated turns stay in the background class, and\ngoal context keeps its pinned front position. Restored queues replay their\nstored order verbatim; the recovery snapshot carries the priority as an\noptional field and falls back to the inferred value.\n\nENG-6158\n\n* fix(coding-agent): keep completion-tracking prompts at human priority\n\npromptAndWait mints a synthetic prompt-wait id to await its own completion,\nso treating any agent message id as background demoted human prompts from\nprint mode, ACP, and the daemon prompt_and_wait command. Only ids that\nidentify agent-to-agent traffic now lower the queue priority.\n\nENG-6158"},{"name":"session-catalog-db.ts","kind":"file","size":15281,"lastCommitHash":"96940c48cd217c60a5c7c683dc89fd122166c78d","lastCommitWhen":"2026-09-17T06:59:15+03:00","lastCommitMessage":"coding-agent/core: pack the session entry structure into one blob\n"},{"name":"session-cwd.ts","kind":"file","size":1628,"lastCommitHash":"080af6fc062f41be2d0a4862a741d54ed4bc130a","lastCommitWhen":"2026-04-05T21:24:32+02:00","lastCommitMessage":"fix(coding-agent): handle missing session cwd\n"},{"name":"session-entry-structure.ts","kind":"file","size":5299,"lastCommitHash":"96940c48cd217c60a5c7c683dc89fd122166c78d","lastCommitWhen":"2026-09-17T06:59:15+03:00","lastCommitMessage":"coding-agent/core: pack the session entry structure into one blob\n"},{"name":"session-file-actions.ts","kind":"file","size":2784,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"session-id.ts","kind":"file","size":1411,"lastCommitHash":"b0a77adeb9f7e9c219803e25829c83a92c639ebb","lastCommitWhen":"2026-07-20T13:28:04-07:00","lastCommitMessage":"reject invalid resume session ids (#479)\n\n* fix(coding-agent): reject invalid resume selectors (ENG-4722)\n\n* fix(coding-agent): resolve ambiguous session selectors\n\nfixes #479\n\n* fix(coding-agent): prefer exact session ids\n\nfixes #479"},{"name":"session-import-errors.ts","kind":"file","size":243,"lastCommitHash":"032e3ee74574ca16efaf8745a1394b821256a5d0","lastCommitWhen":"2026-08-18T12:17:35+02:00","lastCommitMessage":"chore: remove redundant comments and unused internals (#1505)\n\n* chore: remove redundant comments\n\n* chore(tui): remove redundant export comments\n\n* chore(coding-agent): remove redundant example comments\n\n* chore(ai): remove redundant comments\n\n* chore(coding-agent): remove obsolete core comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(coding-agent): remove redundant rpc test comments\n\n* chore(coding-agent): remove redundant CLI comments\n\n* chore(agent): remove redundant comments\n\n* chore(tui): remove redundant source comments\n\n* chore(coding-agent): remove redundant mode comments\n\n* chore(coding-agent): remove redundant mode comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(ai): remove redundant source comments\n\n* chore(coding-agent): remove redundant session comments\n\n* chore(coding-agent): remove redundant core comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(tests): remove redundant test comments\n\n* chore: remove unused internal helpers\n\n* docs: restore public API contracts\n\n* chore(coding-agent): restore invariant documentation\n\n* chore(coding-agent): clarify agent family contracts\n\n* style(coding-agent): format restored contracts\n\n* fix: restore intentional catch explanations"},{"name":"session-lease.ts","kind":"file","size":10935,"lastCommitHash":"2ce443175b55a32075aa23ae41676a16b771d662","lastCommitWhen":"2026-09-06T23:14:48-04:00","lastCommitMessage":"fix: improve Windows session and Python reliability (#2036)\n\n* fix(coding-agent): resolve the kernel venv python under Scripts on win32\n\nuv creates <venv>/Scripts/python.exe on Windows, but both bootstrap sites\njoined <venv>/bin/python unconditionally, so first-run kernel bootstrap\nalways failed on native Windows. Mirror the existing win32 uv.exe branch\nwith one kernelVenvPython helper used at both sites.\n\n* fix(coding-agent): expand ~/ with the platform path separator\n\nTilde expansion concatenated homedir() with the posix remainder at three\nsites (expandPath, expandTildePath, and an inline PI_PACKAGE_DIR copy),\nproducing mixed-separator paths like C:\\Users\\u/rest on Windows. Join\nthrough the platform path module instead and route PI_PACKAGE_DIR through\nexpandTildePath.\n\n* fix(coding-agent): prefer non-System32 bash over the WSL trampoline on PATH\n\nfindBashOnPath took the first where-match, and System32\\bash.exe (the WSL\nlauncher, which executes Linux-side) precedes per-user Git Bash installs on\ndefault PATHs. Order matches so %SystemRoot% entries are only a last\nresort.\n\n* fix(coding-agent): dial the Herdr socket inside the named-pipe namespace on win32\n\nThe built-in Herdr reporter connected to the exported unix-style socket\npath verbatim; on Windows a local-domain connection must target\n\\\\.\\pipe\\, and the reporter swallows connect errors by design, so the\nmismatch was invisible. Map unmapped paths into the pipe namespace before\ndialing.\n\n* fix(coding-agent): cache the win32 process start id per pid for a short TTL\n\ngetWindowsProcessStartId spawns a synchronous powershell query that blocks\nthe event loop, and supervisor liveness checks plus daemon-ps poll loops\ncall it repeatedly for the same pid. Memoize successful ids for 5s so hot\npaths reuse one query.\n\n* fix(coding-agent): derive handshake budgets from the outer connect deadline\n\nconnectWorker granted every hello/worker_auth attempt a fixed 1s clock, so\na handshake that consistently needs longer (slow win32 boxes) failed every\nretry regardless of the 30s outer budget, and the adopt/recover paths\nshrank even the outer budget to 1.5-2s. Per-attempt waits now consume the\nremaining outer deadline, all connectWorker callers use the one 30s\nconstant, and the downward 1s hello/auth overrides in daemon-mode and the\nrouted client fall back to the client defaults.\n\n* fix(coding-agent): route background spawns through hidden-window wrappers\n\nwindowsHide defaults to false, so console-subsystem children of a\nwindowless daemon or detached worker allocate a fresh console and flash or\nsteal focus on every spawn; only one call site in the repo set the flag.\nAdd spawnHidden/spawnSyncHidden/execSyncHidden/execFileHidden/\nexecFileSyncHidden to utils/child-process.ts and migrate all 49\nnon-interactive coding-agent spawn/exec sites; the tui package's two\nbackground spawns set windowsHide inline. Interactive spawns (editors,\ninherit-stdio installers and relaunches) intentionally keep their console.\n\n* chore(coding-agent): add windows-seams changelog fragments; tighten new comments\n\n* test(coding-agent): align clipboard and login-dialog spawn assertions with hidden-window wrappers\n\n* revert(coding-agent): drop the win32 start-id TTL cache\n\nThe per-pid cache could hand a recycled pid the dead process's start id\nfor up to 5s. The start id exists solely to detect pid recycling, and its\nconsumers act on that identity: the orphan-process journal decides\ntaskkill /T from it and daemon-ps shutdown waits poll it for change, so a\nstale match can kill a replacement process tree or mask an exited owner.\nNo caller is both hot and staleness-tolerant; the handshake latency issue\nis already addressed by deriving budgets from the outer deadline.\n\n* fix(coding-agent): match Herdr pipe-namespace prefixes case-insensitively\n\nWindows pipe names are case-insensitive, but the pass-through check was\ncase-sensitive, so a valid \\\\.\\PIPE\\... target was re-joined into a\ndifferent pipe name and the error-swallowing reporter failed silently.\nLowercase only the prefix check; the returned path keeps its casing.\n\n* refactor(coding-agent): tighten windows-seam comments and consolidate pins\n\nCollapse the wrapper doc block to one line, drop test comments that restate\nassertions, share one recording wrapper in the child-process mock, unwrap\nsingle-test describes, and remove one posix assertion already covered by\nits sibling. No behavior coverage removed; all pins keep their failing\nassertions.\n\n* fix(coding-agent,tui): harden current-runtime Windows sessions\n\nImport selective Bun-independent fixes from #1994 at\nce2d04f872ae7df567e68695aa258a1a5cdf254c, relative to declared\n#1982 base 9680ac3dfa8bdafae0f9e53286e2274d8b9c9090.\n\nPreserve #2036 Windows seams and current Node runtime. Keep Bun,\ninstaller, shell-policy rollout, scratch directories, and CPython\nbatch overrides outside this consolidation. #1994 remains partial.\nAtomic writer and bootstrap-lock overlap awaits canonical #2035\nreconciliation after parent stacks land.\n\n* fix(coding-agent): normalize Windows bash candidate paths\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"session-manager.ts","kind":"file","size":107924,"lastCommitHash":"12624e0ead87ff8d4e5147a5d58987f53c14b923","lastCommitWhen":"2026-09-17T09:45:21+03:00","lastCommitMessage":"fix(coding-agent): close the scattered failures and settle the credential precedence\n\n- an explicitly stored Prime Inference key now wins over the Prime CLI\n  config; the CLI bridge stays the fallback for sessions that never\n  stored one, which is what the trace upload path and the fail-closed\n  rule both assume\n- session listing keeps a deterministic order when transcripts share a\n  modification time (results are collected in directory order instead of\n  completion order) and the in-memory retention tests pin the catalog off\n- a retry policy with maxRetries 0 no longer enters the quota wait\n- the autonomous, package-path, trace, quota and refinement suites mirror\n  the fork's contracts: the spawn gate and named model, daemon env\n  isolation, an async host request, and a digest ranking test that asks\n  for the detailed tier only (the shipped default also lists stubs, which\n  the neighbouring cases cover)\n"},{"name":"session-resolver.ts","kind":"file","size":5378,"lastCommitHash":"90dc81bdde8eb3fc2fdaf271cbe811ac20f5704c","lastCommitWhen":"2026-09-17T06:41:46+03:00","lastCommitMessage":"coding-agent/core: resolve session selectors from the transcript file name\n"},{"name":"session-stats.ts","kind":"file","size":420,"lastCommitHash":"032e3ee74574ca16efaf8745a1394b821256a5d0","lastCommitWhen":"2026-08-18T12:17:35+02:00","lastCommitMessage":"chore: remove redundant comments and unused internals (#1505)\n\n* chore: remove redundant comments\n\n* chore(tui): remove redundant export comments\n\n* chore(coding-agent): remove redundant example comments\n\n* chore(ai): remove redundant comments\n\n* chore(coding-agent): remove obsolete core comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(coding-agent): remove redundant rpc test comments\n\n* chore(coding-agent): remove redundant CLI comments\n\n* chore(agent): remove redundant comments\n\n* chore(tui): remove redundant source comments\n\n* chore(coding-agent): remove redundant mode comments\n\n* chore(coding-agent): remove redundant mode comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(ai): remove redundant source comments\n\n* chore(coding-agent): remove redundant session comments\n\n* chore(coding-agent): remove redundant core comments\n\n* chore(coding-agent): remove redundant test comments\n\n* chore(tests): remove redundant test comments\n\n* chore: remove unused internal helpers\n\n* docs: restore public API contracts\n\n* chore(coding-agent): restore invariant documentation\n\n* chore(coding-agent): clarify agent family contracts\n\n* style(coding-agent): format restored contracts\n\n* fix: restore intentional catch explanations"},{"name":"settings-manager.ts","kind":"file","size":50558,"lastCommitHash":"ba0ddb1062a6f6de20c25a892addeca7092d9fe7","lastCommitWhen":"2026-09-17T20:24:08+03:00","lastCommitMessage":"coding-agent: add a sessionRecap.enabled off switch for the daemon status recap\n"},{"name":"side-question.ts","kind":"file","size":7553,"lastCommitHash":"5255a6b88002d60ff810e27b33d104eb424c5e07","lastCommitWhen":"2026-09-11T14:42:44-04:00","lastCommitMessage":"Keep the session thinking level for /btw side questions (#2234)\n\n* fix(side-question): keep the session thinking level for /btw\n\nSide questions clone the main conversation but sent a clamped auxiliary\nthinking level. Anthropic-style APIs key message-level cache on the thinking\nparameters, so the first /btw of a long session re-read the whole\nconversation at full price. Sending the session level keeps the side\nrequest's cache key identical to the main thread's.\n\n* docs: changelog fragment"},{"name":"skill-blocks.ts","kind":"file","size":618,"lastCommitHash":"891b99800bdd40d53c8f67bbae03acc55262e585","lastCommitWhen":"2026-06-09T21:11:57-07:00","lastCommitMessage":"decouple interactive mode from agent runtime (#79)\n\n* decouple interactive mode from agent runtime\n\n* add rich tui attach for daemon sessions\n\n* clarify agent connection boundary\n\n* document agent connection architecture\n\n* fix daemon interactive session replacement\n\n* refresh transcript after session replacement\n\n* fix daemon session attach edge cases\n\n* fix remaining daemon tui review findings\n\n* fix daemon tui review regressions\n\n* fix daemon tui cancellation gaps\n\n* fix daemon attach by session file\n\n* fix daemon extension ui client routing\n\n* fix daemon close ui cancellation order\n\n* fix daemon active session lookup startup\n"},{"name":"skills.ts","kind":"file","size":19721,"lastCommitHash":"6b8fbd8b0831e14a085634ea8a395b60d8041c3b","lastCommitWhen":"2026-09-17T20:40:32+03:00","lastCommitMessage":"fix(coding-agent): harden kernel bootstrap lock, staging checks, import isolation and postinstall\n"},{"name":"slash-commands.ts","kind":"file","size":12386,"lastCommitHash":"419643717a968f6cacae6d180d1c60baa070e4ee","lastCommitWhen":"2026-09-17T07:10:10+03:00","lastCommitMessage":"feat(coding-agent): support automatic compaction thresholds via /compact at <tokens>\n"},{"name":"source-info.ts","kind":"file","size":852,"lastCommitHash":"4e5af01d73a09e78244029d766c352971b515398","lastCommitWhen":"2026-03-23T02:02:42+01:00","lastCommitMessage":"fix(coding-agent): unify source provenance, closes #1734\n"},{"name":"system-prompt.ts","kind":"file","size":7208,"lastCommitHash":"ae6ee379908f52365f7731a4812233694fd800c5","lastCommitWhen":"2026-09-17T07:04:42+03:00","lastCommitMessage":"feat(coding-agent): publish the generated skill surface, behind a capability gate (R7 S4/S5 host half)\n\nThe runtime generates one line per published call plus a shape line per result\ntype; the host now publishes it, so a signature is stated once instead of being\nhand-written in prose that drifts.\n\n- `KernelClient.skillDigest(skills, signal)` is capability-gated: the manager\n  records the `ready` event's optional `capabilities` list (reset per start and\n  teardown) and returns null without it, so an older runtime is never asked and\n  an old host keeps working. A runtime that rejects the request also yields null,\n  never an error.\n- the `ipython` provisioner reads the digest once after the runtime bootstrap and\n  caches it, and the session rebuilds its base prompt when it arrives, so the\n  first turn after a fresh kernel carries the surface.\n- the prompt prints the digest with the \"if the digest disagrees with the\n  installed code, the code wins\" sentence in place of the inspect.signature line.\n- with the digest as the published surface, the hand-written signature prose it\n  replaces is gone: the `search` description signature, the `git` `cwd=`/`n=`\n  examples, the `nix` handle-API list, and the `bash()` API half of the prompt\n  paragraph (R14's `timeout=` sentence, I1's `line_hint=` sentence and I6's\n  public-listen sentence stay).\n- docs/rlm-runtime.md lists the `signatures` request and the capability gate.\n\nAlso fixed: test/ipython-bootstrap.test.ts still asserted the\n`async def roles(self, role=None)` stub that role routing removed when\n`rlm.models()` discovery replaced it; it now asserts the stubs the prompt calls.\n\nTests: new test/repl-kernel-skill-digest.test.ts (4 fake-protocol kernel cases:\ncapable runtime asked with the right names, no-capability runtime null and\nunasked, capable runtime rejecting, empty list and stopped kernel),\nipython-provisioner (32), repl-kernel-execute (11, real kernel digest carries\n\"# skill surface\"), system-prompt (29), repl-kernel-abort (24). The capability\ngate has a negative control: sending the request without checking the capability\nfails the \"unasked\" case.\n"},{"name":"telemetry.ts","kind":"file","size":21812,"lastCommitHash":"b6ac5d014d99401b55820835a4966584271e9a3c","lastCommitWhen":"2026-09-16T16:20:18-07:00","lastCommitMessage":"mcp service catalog and oauth engine (#2330)\n\n* add a shared service catalog and generic mcp connections (#2256)\n\n* style(coding-agent): apply biome formatting to daemon-mode.ts\n\n* feat(coding-agent): add /plugins service catalog with verified MCP connections (ENG-6108)\n\n- Add /plugins and bare /mcp as the same searchable external-service picker with\n  honest states (Connect, Connected with verified tool counts, Reconnect,\n  Verifying, Requires setup, Disabled) and connect/disconnect actions\n- Add mcp.list_plugins, mcp.search_plugins, and mcp.list_connections host\n  requests with strict status filters, bounded limits, and honest nextCursor\n- Add local connection records (connectionId distinct from catalog serviceId);\n  verify every login with a real MCP handshake so token presence alone is\n  pending, never Connected; rejected credentials recover via Reconnect\n- Serve connected catalog services (Linear, Notion) through the generic mcp\n  runtime route: system-prompt inventory and mcp.config, no per-service wrappers\n- Drop the McpIntegration import from the kernel ready check ahead of the\n  Linear/Notion wrapper-package removal\n- mcp.connect is registered only behind an explicit UI-approved callback and\n  stays unregistered in daemon-hosted sessions (honest \"no handler\")\n\nTests: mcp-service-catalog, mcp-manager handlers, service-catalog-picker, and\nthe eng-6108 activation regression covering login -> verify -> session reload ->\nprompt inventory in the real services path without a restart.\n\n* fix(coding-agent): harden MCP verification, activation, and connection records (ENG-6108)\n\nReview follow-ups on the /plugins service catalog slice:\n\n- Verification now runs through the official @modelcontextprotocol/sdk\n  client (negotiated protocol version header, CRLF SSE support, explicit\n  session termination via HTTP DELETE) instead of a handwritten transport\n- Failures persist as fixed safe categories only; endpoint URLs,\n  server-controlled text, and tokens never reach records or messages\n- Connection records use the auth.json file-lock read-modify-write pattern\n  with unique temp files; concurrent UI/daemon writers no longer lose\n  records, and pending operations queue while a flush is in flight\n- Every verification result is bound to the exact grant it verified\n  (credential hash); stale probes after logout or token rotation are\n  discarded, never marking a newer or removed account Connected\n- An OAuth connection without a usable token is never probed anonymously\n- A login made while streaming or compacting queues automatic activation\n  at the next safe boundary (agent end / compaction end); the UI never\n  instructs the user to run /reload for MCP changes\n- /plugins and config-menu connect paths share the queue; failure categories\n  render as fixed user-readable wording\n- metadata-reviewed / legacyBuiltin rename absorbed from the catalog lane\n\nTests: probe (SDK fake server incl. CRLF/401/timeout/secret-leak), store\n(two-writer races, guard discard, mid-flight queueing), service catalog\n(stale verify after logout/rotation, non-connectable transports), manager,\nactivation queue (streaming/compaction/tool boundaries), regression suite.\n\n* fix(coding-agent): bind MCP credentials to endpoints, reconcile providers, honest connect (ENG-6108)\n\n- Endpoint binding everywhere a stored grant is consulted: catalog services and\n  user-declared servers require cred.endpoint === current URL before any token\n  fetch or probe (views, verify, dispatch inventory, demand-driven listing);\n  unbound legacy grants surface as Reconnect with the fixed credential-unbound\n  category and are recorded once on demand-driven verification\n- Provider ownership is one atomic reconciliation: legacy built-ins, eligible\n  catalog services, and user-declared OAuth servers are re-registered first and\n  only previously-owned ids unregister; the ModelRegistry reset hook calls the\n  full reconciliation, so catalog providers survive refresh and a removed user\n  override restores the catalog provider after a single manager.refresh()\n- Flush-time verification guards re-read fresh credential-source state\n  (authStorage.reload() under the backend lock), so probes that finish after\n  another client logged out or rotated the grant are discarded — no stale\n  Connected record survives across clients\n- mcp.connect (explicit-approver seam) verifies the real handshake before\n  reporting connected (tool count included) and reports fixed failure\n  categories on rejected handshakes\n- /plugins stdio user servers get a real management action: Enter disables the\n  server in global settings, refreshes providers, and reloads; already-disabled\n  and vanished entries report honest status\n- Catalog views keep the Reconnect action on error rows and add unverified/\n  unbound view tests; all oauth test fixtures now carry bound endpoints\n\nMinimal type-only addition in connection-probe.ts (lifecycle lane owns the file):\nMCP_PROBE_ERRORS.UNBOUND_CREDENTIAL.\n\nTests: manager 29, service-catalog 23, activation-queue 8 (incl. stdio\nmanagement), probe 7, store 6, picker 4, regression 2, slash-commands 18 —\n97/97; reviewer's mcp-service-safety suite verified 12/12 green against this\ntree (their file, their branch).\n\n* feat(ai): merged MCP service catalog with deterministic importer (ENG-6108)\n\n* feat(ai): metadata-reviewed catalog status, legacy builtins, local JSON sources, literal endpoint checks (ENG-6108)\n\n* fix(ai): harden local catalog loader and endpoint checks (ENG-6108)\n\n* feat(coding-agent): shared catalog resolver, local sources, per-account connections (ENG-6108)\n\n- resolveMcpServiceCatalog merges the built-in SERVICE_CATALOG with\n  settings-declared local sources (Settings.mcpCatalogSources): ~-expanded\n  before loadLocalServiceCatalog (which does no expansion), declared-but-missing\n  files and cross-source duplicate ids surface as visible diagnostics, first\n  source wins, total capped at 500 entries\n- The SAME resolution feeds the /plugins UI and the mcp host handlers; the UI\n  re-reads connection records from disk before rendering (no stale cache) and\n  shows resolver diagnostics on open\n- One-click Connect is metadata-reviewed-only (plus user-placed local files,\n  which still go through the login dialog's explicit approval); unreviewed\n  imported entries stay candidates with an honest setup hint\n- Per-account connections: \"Add another account\" allocates a distinct\n  connectionId (mcp:<serviceId>-N) with its own credential key, record, and\n  OAuth provider; the account picker lists accounts with per-account\n  Reconnect/Disconnect; alias ids join integrations, dispatch inventory,\n  mcp.config, and demand-driven verification through the same machinery; the\n  record's serviceId keeps the parent catalog id\n- test/mcp-service-catalog.test.ts settles the theme's cli-highlight preload\n  in beforeAll (deterministic fix for the pre-existing initTheme fire-and-forget\n  teardown race, evidence in ENG-6108 notes); ServiceCatalogPickerComponent\n  gains title/subtitle/hideSearch options for the account listing\n\nCatalog commits f8a4cf61a -> 50b79c3af -> be7445c3c integrated via authorized\nlocal cherry-picks; no catalog-source files modified.\n\nTests: manager 31 (alias integrations/provider lifecycle, demand-driven unbound\nrecord, reconciliation), service-catalog 29 (resolver, candidates, allocator),\nactivation-queue 9 (stdio management, add-account), probe 7, store 6, picker 4,\nregression 2, slash-commands 18 — 105/105; npm run check EXIT=0; 10/10\nconsecutive scoped runs with zero unhandled rejections, exit 0 each.\n\n* mcp: generic discovery surface, drop linear/notion wrappers (ENG-6108)\n\nAdd a bounded discovery surface to the kernel MCP module:\nlist_plugins, search_plugins, list_connections, search_tools and\ndescribe_tool, backed by host-owned catalog/connection handlers,\nwith cursor-safe tools/list pagination, explicit search scopes and\ndefensive secret scrubbing of inventory metadata only.\n\nReplace the bespoke Linear/Notion Python wrapper packages with one\ngeneric bundled mcp skill; remove the McpIntegration base class after\nauditing consumers, moving its shared helpers into rlm.mcp. Connecting\na service is a user action (/plugins or /mcp login), never an install\nor a per-service Python module.\n\n* mcp: fail-closed tool discovery, isolated schemas, redacted inventory errors (ENG-6108)\n\nFollow-up to 6514cbe6f per review:\n\n- discover() now publishes a tool map only when tools/list pagination\n  completes; a repeated or malformed continuation cursor, or exceeding\n  the page cap, raises McpDiscoveryError instead of a silent partial\n  inventory. Malformed cursors are rejected rather than read as done.\n- list_tools/describe_tool return deep copies, so caller mutations can\n  never reach the cached canonical schemas.\n- Per-connection search failures report a fixed exception type + hint\n  (McpCredentialsUnavailable and friends) instead of raw exception text;\n  host_request error text echoed by inventory calls is scrubbed of\n  credential-bearing URLs, query strings and auth headers and bounded.\n\n* mcp: never chain raw host errors in inventory wrappers (ENG-6108)\n\nFollow-up to ff738187e per review. _host_inventory raises a fixed\n\"MCP <request-type> request failed/timed out\" wrapper outside the\nexception handler, so arbitrary host/bridge error text (which can\nembed credential-bearing URLs, query strings, headers and HTTP\nbodies) is never echoed and cannot be reached through __cause__ or\n__context__ either; format_exception prints stay secret-free. The\nnow-unused redaction regex helper and bound constant are removed.\n\nRegression uses traceback.format_exception, not only str(exc), to\nassert the original exception is fully absent. Skill updated for the\nhost status vocabulary (pending, verified handshake) and PluginView\nfields (setupHint, unverified, verifiedAt/toolCount, connectionIds).\n\n* fix(coding-agent): bound MCP probe lifetime and connection-store races (ENG-6108)\n\nRoot review fixes on the lifecycle lane:\n\n- probeMcpEndpoint: the SDK passes its own controller's signal to every\n  fetch (including the cleanup DELETE and its body cancel), and the SDK\n  request timeouts only race the JSON-RPC promise, so an unresponsive\n  DELETE could hang the probe forever. One lifecycle AbortController now\n  bounds the probe: a fetch wrapper merges its signal into every\n  transport fetch, terminateSession/close are each raced against a\n  cleanup grace deadline whose expiry aborts the signal, an absolute\n  deadline timer plus a final abort end lingering body reads, and every\n  timer is cleared. Failure categories stay fixed and safe.\n- McpConnectionStore: the pre-lock exists-then-write-empty create could\n  rename an empty file over records another process just wrote; the file\n  is now created exclusively (wx, never truncating) before the canonical\n  realpath lock, with mode 0600. A failed atomic write no longer drops\n  queued mutations: the batch is unshifted back to the front of the\n  queue and retried by the next flush (ops are idempotent; verify\n  guards re-evaluate under the lock).\n- MCP_PROBE_ERRORS gains UNBOUND_CREDENTIAL (\"credential-unbound\") for\n  grants not bound to the endpoint, consumed by the service catalog.\n\nOffline regressions: never-returning cleanup DELETE, hanging response\nbody, exclusive first-create race with mode 0600, injected atomic-write\nfailure with in-order retry and stale-guard discard, plus the existing\nsuites. All fetch stubs; no live credentials or provider calls.\n\n* test(coding-agent): multi-PID first-create regression for MCP connection store (ENG-6108)\n\nRoot review follow-up: in-process instances cannot reproduce the\nfirst-create exists/write race because their pre-await work is\nserialized on one event loop. The store test file now also spawns four\nreal first-writer processes (temporary .mts worker imported through the\nproject tsx loader, no production entry point), aligned by ready\nmarkers + a file barrier, racing the first create and the locked flush\non the shared store path. Asserts distinct PIDs, all children exit\ncleanly, every record survives, and the file keeps mode 0600; children\nare terminated in a finally on every path.\n\nTest-only: no production files touched.\n\n* test(coding-agent): Windows-portable multi-PID store regression (ENG-6108)\n\nTest-only portability follow-up: the generated first-create worker\nimported the store module by resolved absolute OS path, which is not a\nvalid ESM specifier on Windows; it now imports by file URL, and the\nexact 0600 mode assertions are POSIX-only (Windows mode bits do not\nmap meaningfully). No production changes.\n\n* test(coding-agent): add service-safety adversarial regressions for MCP credentials and providers (ENG-6108)\n\nAdversarial regression suite for the ENG-6108 service-catalog safety\ncontract, red on the 4bd8abc12 baseline and green on the wave-2 fixes:\n\n- Credential binding before probe/token access: a stored credential bound\n  to a different endpoint, or unbound, is rejected before any probe call\n  and before authStorage.getApiKey - for user-declared servers and\n  catalog services, through direct verifyConnection and the demand-driven\n  mcp.list_plugins background verification; never a connected record.\n- Cross-client stale probes: two AuthStorage instances share one\n  auth.json; a probe finishing after a second client logs the grant out\n  or replaces it mid-flight must not persist a connected record or\n  verifiedAt for the current grant.\n- OAuth provider lifecycle: a full OAuth registry reset (through the\n  real createAgentSessionServices + modelRegistry.refresh seam)\n  preserves non-bundled catalog providers, and removing a user override\n  restores the catalog provider after one refresh.\n\nOffline-only: injected probes, denied fetch, per-test temp credential\nand connection stores, no live endpoints or real credentials.\n\n* fix(coding-agent): durable account reservations, per-account views, honest actions (ENG-6108)\n\nFinal-review wave 4:\n\n- Account allocation is a durable reservation under the connection-store file\n  lock: reserveConnectionId applies atomically on disk (exactly one winner in\n  a cross-process race; the loser allocates the next id), pending markers are\n  visible to every client, and removeReservation is ownership-validated (id +\n  still-pending + same createdAt) so a late callback never removes or resurrects\n  another client's account. Allocation consults store records, credentials,\n  configured user servers, and catalog ids; configured names are never taken.\n- Views aggregate every account of a service: connectionIds lists all accounts,\n  each account's status reflects its own bound credential, the service card\n  survives on a remaining account after the default disconnects, and the\n  inventory emits one row per account (no phantom primary row). Alias account\n  ids are searchable (search_plugins alias contract). Connections whose local\n  catalog source vanished keep a pinned descriptor at the recorded endpoint —\n  credentials are never retargeted.\n- Explicit state actions: pending accounts retry verification without a\n  relogin (the \"retry from /plugins\" path works), error accounts keep\n  Reconnect (catalog and user rows), each account gets an explicit Remove\n  row, and a verification result that could not be saved reports pending —\n  never a false Connected.\n- resolveMcpServiceCatalog isolates local-source failures per source: one\n  unreadable or invalid file becomes a bounded visible diagnostic while the\n  built-in catalog and every other source keep resolving.\n\nTests: two-client simultaneous reservation race with barrier, ownership\nvalidation, full add-second -> reload -> inventory -> disconnect-default ->\nsecond-still-manageable regression, per-account view aggregation, vanished-\nsource pinning, per-source failure isolation, state-based action tests, and\nallocation that skips configured ids.\n\nOwnership: bootstrap.ts untouched (delegated lane).\n\n* fix(coding-agent): require MCP discovery methods in the kernel ready check (ENG-6108)\n\nThe runtime ready check only asserted mcp.list_tools/mcp.call_tool; the\nfive new discovery methods were validated once by the bootstrap import\nscan, so a cached kernel venv with an old prime-agent-runtime could\npass readiness. The check now requires callables for list_plugins,\nsearch_plugins, list_connections, search_tools and describe_tool, and\nfails with an actionable message so the venv is rebuilt instead of\nsilently reused.\n\nRUNTIME_READY_CHECK is exported so the new regression executes the\nexact shipped check against a real project runtime: it accepts the\ncurrent runtime, and rejects a runtime simulated as old by deleting\neach discovery method in-process (not a text-grep test). No provider\ncalls, credentials, or real daemon involved.\n\n* fix(coding-agent): guarded account credential commits and computed account status (ENG-6108)\n\nFinal-review wave 5:\n\n- Reservations resolve only after the durable record write COMMITS: the\n  store defers reserve/remove/finalize callbacks past writeFileAtomicSync,\n  resolves them false on write failure, and drops the one-shot ops instead\n  of requeueing them — a failed write can never produce a ghost reservation\n  a login could start on (injected-write-failure regression: no marker, no\n  requeue surprise, retry works)\n- Ownership is an opaque random attempt nonce (not createdAt): cancel and\n  the NEW successful-commit guard both validate it under the same store\n  lock. Add-account logins stage the OAuth credential under\n  mcp:<id>--<attempt> and move it to the real account key only inside a\n  guarded finalizeAttempt commit — a late login success after remove or\n  replacement discards the staged credential and never touches the\n  account (regressions: late-success-after-remove and same-id-new-owner,\n  both assert the final credentials)\n- Per-account status is one computed helper (accountStateFor): credential\n  binding, expiry, and the record combine through httpConnectionStatus, and\n  the plugin aggregate, connection inventory, and account picker all use\n  it — previously-connected records with unbound, retargeted, or\n  expired-no-refresh credentials report Reconnect everywhere (6\n  regressions across default and alias accounts)\n- Catalog metadata aliases ride the view DTO and are searchable again\n  (regression: an alias absent from label/id/description matches)\n- Vanished-source pins are their own trust path (never localSource trust;\n  never one-click connectable)\n\nTests: 147/147 across 10 files; npm run check EXIT=0; 10/10 consecutive\nscoped runs with zero unhandled rejections, exit 0 each.\n\n* fix(coding-agent): exactly-once account transactions and locked disconnects (ENG-6108)\n\nFinal-review wave 6 (transaction issues):\n\n- Every one-shot store callback (reserve/removeReservation/finalizeAttempt/\n  removeAccount) settles EXACTLY once: deferred callbacks resolve with the\n  commit outcome (not `didCommit && resolve(true)`), losing and throwing\n  branches resolve false inline, one-shot ops are dropped on write failure,\n  and trailing ops in a failed batch can never hang — batched-two-reserves\n  write-failure regression included\n- Account removal runs credential deletion AND record removal under the SAME\n  store lock (new store.removeAccount; disconnect, remove-action, and\n  /mcp logout all use it): a concurrent finalize can never re-add an orphan\n  credential after a disconnect — interleaving regression on real stores\n  covers both orders (remove-then-finalize loses ownership; finalize-then-\n  remove clears record AND credential)\n- finalizeAttempt compensates: if the RECORD write fails after the credential\n  move, the compensate callback runs under the same lock and restores the\n  staged credential (the real key was empty before the attempt), so a failed\n  finalize is all-or-nothing; the flow then releases the reservation and\n  reports honestly — UI regression asserts the real key untouched, staged\n  restored+discarded, reservation released, and the honest message\n\nTests: 151/151 across 10 files; npm run check EXIT=0; 10/10 consecutive\nscoped runs with zero unhandled rejections, exit 0 each.\n\n* fix: honest MCP account recovery edges (ENG-6108)\n\n- removeAccount logs a credential-only integration out even when no\n  connection record exists; outcomes are typed (removed, credential-only,\n  missing, failed) and every UI route maps them honestly.\n- finalizeAttempt registers its rollback BEFORE any side effect: a\n  throwing or partial commit is compensated under the same lock, and a\n  FAILED rollback surfaces an explicit recovery-required state with the\n  credential retained instead of a silent false.\n- the guarded commit refuses to clobber a credential an ordinary login\n  wrote at the account key mid-flight, and the rollback only ever undoes\n  its own write; a bystander credential survives byte-for-byte.\n- one-shot store operations settle cleanly when the file lock itself\n  cannot be acquired; durable operations requeue (pre-splice).\n\n* fix: atomic MCP credential moves and honest partial logouts (ENG-6108)\n\n- staged logins move their credential to the account key with a new\n  disk-authoritative compare-and-set under the auth backend's own file\n  lock: moveStagedCredential (set-if-absent, returns the exact moved\n  credential), restoreCredentialIfAbsent, and removeIfCredentialMatches\n  (exact full-object own check, not access-token equality). A bystander\n  credential written by another process can no longer be clobbered by a\n  get/set race across AuthStorage instances.\n- the finalize compensation restores ours only into an empty staged slot\n  and deletes only its own exact credential from the account key.\n- removeAccount now reports \"logged-out\" when the credential logout\n  committed but the record save failed: the logout is preserved, the UI\n  wording says so and never claims the account is still connected; plain\n  \"failed\" wording is state-neutral.\n- two-real-storage-instance regressions: a bystander login written after\n  staging survives byte-for-byte; a generic /logout in another client\n  before/after the finalize races atomically (last-writer-wins under the\n  backend lock, record shows an honest unbound state); an injected\n  record-write failure after the logout reports the honest partial state.\n\n* fix: disk-verified MCP logouts and logout-cancelled login attempts (ENG-6108)\n\n- the three removeAccount authCleanup paths now use removeVerified\n  (extended to return whether a credential was actually removed from\n  disk): a failed auth-file write can no longer report Removed/\n  Disconnected while the credential persists; the honest \"failed\"\n  wording is state-neutral.\n- a real generic /logout of an MCP account now cancels that account's\n  pending login attempts: runLogout calls the new\n  ProviderAuthFlowsHost.onMcpCredentialRemoved hook, and the host\n  invalidates the pending reservation under the connection store's lock\n  (new invalidatePendingAttempts), so a stale in-flight OAuth attempt\n  resolves denied and can never re-activate the logged-out account.\n  Non-MCP logouts are unchanged.\n- regressions: auth-file write failure with a fresh disk reader (the\n  credential survives, nothing claims success), a route-exact\n  cross-client pending-finalize vs real /logout test driven through the\n  selector, store-level invalidation semantics, and stale\n  interactive-mode-status fixtures repaired to the current seams.\n\n* fix: one shared store-locked MCP logout op for the generic /logout route (ENG-6108)\n\n- the route delegates the ENTIRE MCP logout before touching auth: the new\n  exported logoutMcpAccount(providerId, store, authStorage) performs\n  verified credential deletion (removeVerified) AND pending-attempt\n  cancellation in one store-locked removeAccount with the new\n  preserveCompletedRecord semantics (pending attempts cancelled,\n  completed records kept for the honest unbound/Reconnect state).\n- removeAccount now runs the verified cleanup BEFORE mutating the\n  working records map: a failed auth-file write resolves \"failed\" with\n  the record intact in memory AND on disk (no half-applied deletion),\n  and a partially-saved logout still reports the honest \"logged-out\"\n  state.\n- the id resolution is exported as resolveMcpAccountLogoutTarget:\n  exact ids win (service ids may contain \"--\"), and staged keys map\n  back only through their actually recorded attempt nonce.\n- regressions: a barrier test fires the REAL generic route inside the\n  finalize's locked commit (verified deterministically red against the\n  old logout-first ordering); store-level half-applied-deletion and\n  preserve-semantics tests; route delegation/wording tests; handler\n  tests for double-hyphen ids, staged-key mapping, and preservation.\n\n* fix: fail-closed refusal for stale staged-key MCP logouts (ENG-6108)\n\n- a staged-key logout that races a completing finalize now refuses\n  fail-closed instead of orphaning the moved credential: the shared\n  handler resolves the account from CURRENT records and CURRENT on-disk\n  auth state under the store lock (never a pre-lock cache snapshot), and\n  when the staged credential already moved onto the account key it\n  returns \"refused\" — the record and the newer credential both survive,\n  and the route reports the completed login explicitly instead of\n  claiming Logged out.\n- new removeAccountForProvider store op (one critical section: resolve\n  under lock -> disk-verified refusal checks -> verified cleanup ->\n  cancel pending / preserve completed); resolveMcpAccountLogoutTarget\n  now returns a stale variant for nonce-matched non-pending records.\n- new disk-authoritative AuthStorage.hasVerified existence check used\n  for the current-state refusal decisions.\n- regressions: the staged-key race queued behind a finalize-first move\n  (refused, record + credential survive), resolver stale semantics, and\n  the route-level refused wording.\n\n* fix: staged-key MCP logouts cancel the attempt and preserve the account shell (ENG-6108)\n\n- removeAccountForProvider no longer gates record deletion on an auth\n  existence snapshot (not atomic with another client's ordinary login):\n  a staged-key logout removes only the staged credential, INVALIDATES the\n  attempt nonce on the pending record (so the in-flight login's denied\n  path can neither finalize nor removeReservation-delete it), and\n  PRESERVES the account record — deletion stays the explicit Remove\n  action's job; a bystander credential on the real key can never be\n  orphaned.\n- the \"refused\" outcome is now state-neutral (\"This login attempt is no\n  longer current; manage the account from /plugins\") — no Logged out or\n  Connected claim from token presence; failed verified auth deletion\n  still changes no record.\n- the interim AuthStorage.hasVerified helper is removed (no auth-state\n  snapshot decisions remain); regressions pin the both-exist contract\n  (staged removed, bystander byte-for-byte, record + nonce-invalidated\n  shell preserved, old-nonce finalize denied, removeReservation no-op)\n  and the finalize-first race with the same invariants.\n\n* feat: one guarded connect operation for every MCP OAuth login route (ENG-6108)\n\n- new one-shot store ops claimConnectionId/releaseClaim: a guarded login\n  claims an EXISTING account record (any status) under the store lock and\n  cancel releases it — the record, its status, and any credential survive\n  untouched; finalizeAttempt ownership is now the EXPLICIT nonce on any\n  record status.\n- every user-facing MCP OAuth login (initial connect, error-state\n  reconnect, add account, /mcp login, generic /login service options,\n  config menu) routes through the guarded flow: claim/reserve, staged\n  OAuth, guarded finalize. The raw dialog remains internal.\n- the finalize commit is a full-identity compare-and-swap on the auth\n  backend lock: set-if-absent for fresh accounts, replace-only-if-matching\n  for intentional replacements (reconnects and credential-only legacy\n  grants); it consumes the nonce and marks the record pending-verification\n  so an old Connected status never carries onto a replaced grant; the\n  compensate RESTORES the previous credential (never delete-only, never\n  clobbering a newer writer).\n- every preserving logout clears the ACTIVE claim nonce regardless of\n  record status, so a logout cancels an in-flight reconnect too; a nonce\n  match in the resolver is always a LIVE attempt (finalizes consume\n  nonces, so the stale variant is gone).\n- new AuthStorage primitives: getVerified (disk-authoritative identity\n  capture) and replaceStagedCredential / replaceCredentialIfMatches\n  (full-identity CAS move and restore).\n- regressions: error-state reconnect (CAS, pending-verification, nonce\n  consumed, old verification state cleared), cancelled reconnect\n  preservation, late-reconnect-after-logout discard, claim/release one-shot\n  settlement on failed batch writes, rollback-restores-previous via CAS,\n  and the generic /login + config-menu delegation to the guarded hook.\n\n* fix: preserve MCP login intent and cancelled account settings (ENG-6108)\n\n* test: cover MCP account lifecycle commit safety (ENG-6108)\n\n* fix: merge-main regressions and secret-free grant binding (ENG-6108)\n\n* fix: fail closed on unproven MCP catalog entries and expired grants (ENG-6108)\n\n* fix: keep built-ins in the catalog cap and harden grant-type regressions (ENG-6108)\n\n* fix: match MCP connectors to the inline configuration pickers (ENG-6108)\n\n* fix: make MCP picker actions match settings-backed targets (ENG-6108)\n\n* feat(ai): complete the generic MCP OAuth engine (ENG-6108)\n\nThe MCP OAuth engine only handled public-client dynamic registration and\nexact endpoint/protected-resource matches: it discarded all registration\nresponse fields beyond client_id, requested every AS-advertised scope,\nissued unbounded uncancellable requests, and rejected the official\nNotion/Slack metadata shape (pathful endpoint, origin-level PRM resource)\nat discovery, so those servers could not log in or refresh at all.\n\nThe engine now follows the SDK 1.30 auth standards via pure helper/schema\nimports from @modelcontextprotocol/sdk (never the auth() orchestrator,\nwhose redirect model does not fit the staged consent UI):\n\n- Client auth-method negotiation (client_secret_basic > post > none,\n  DCR hint honored, RFC 8414 defaults) applied to exchange and refresh,\n  with a compatibility gate: a secret-only server never receives a doomed\n  no-auth request; it fails early with typed setup guidance.\n- Full RFC 7591 registration responses: persisted DCR client identity,\n  issued secret and expiry (respected on refresh), and registration-mode\n  binding. Config-supplied secrets are never persisted or embedded.\n- CIMD/SEP-991: a configured Prime-controlled client-metadata URL becomes\n  the client id when the server advertises\n  client_id_metadata_document_supported; no URL is invented or deployed.\n- SEP-835 scope precedence: configured > protected-resource > omitted;\n  authorization-server-wide scope lists are never blindly joined.\n- Narrow audience policy: the PRM resource must equal the canonical\n  endpoint or its exact HTTPS origin (URL-component compared); refresh\n  pins both values and the audience mode, fail-closed on any change, and\n  legacy exact grants never refresh against origin audiences.\n- Every request is bounded (10/15s deadlines, 256KiB bodies) and login\n  honors the host abort signal, including callback-server cleanup.\n- Token errors are typed and sanitized: whitelisted RFC error codes only,\n  fixed guidance, never raw server-controlled descriptions.\n\nAll flows run against offline fake OAuth/MCP servers in\npackages/ai/test/mcp-oauth.test.ts (39 tests: official Notion/Linear\nfixtures, Slack post-only negotiation, CIMD, refresh binding and\nrotation, abort/cancellation); no live endpoints or credentials.\n\n* feat(ai): read-only catalog metadata audit with readiness evidence (ENG-6108)\n\nAdd a reproducible read-only public metadata audit of all 103 remote catalog endpoints (public unauthenticated GETs only, bounded, DNS-pinned per request through an undici dispatcher lookup) and merge the committed evidence into the catalog offline. New additive, optional interface: setup.readiness (informational, never a Connect gate), setup.requirement, setup.fields[].kind, auth.alternatives[] per-path alternatives, and the observational auth.metadata evidence block. Placeholder-only OAuth blockers are cleared with evidence (Airtable, Shopify stay Connect-attemptable); genuine documented requirements stay hard (API keys, bearer tokens, tenant config, registered clients, transport and local-runtime limits). CIMD alone is never oauth-ready, audience-mismatched PRM documents stay unknown with notes until the approved engine audience policy lands, and local sources cannot self-assert readiness, alternatives or evidence.\n\n* docs(ai): correct stale oauth-marker consumer comment (ENG-6108)\n\nThe host keys OAuth support off authStrategy, not entry.oauth?.kind; the comment now points consumers at auth.strategy. Comment-only change.\n\n* fix(coding-agent): guard mcp account ownership and capability policy (ENG-6108)\n\n* fix(ai): adopt engine component comparison for readiness re-derivation (ENG-6108)\n\nThe importer audience rule now uses the engine component comparison: a protected-resource document must match the exact canonical endpoint or the exact origin (root-slash normalized). notion plus the 9 DCR-capable origin-mismatched entries (airtable, amplitude, appwrite, lovable, miro, rootly, vercel, windsor-ai, zoominfo) re-derive to oauth-ready and their stale not-yet-landed notes are gone; logrocket stays unknown (its resource drops the ?toolsets=all query, failing closed under the component rule); slack and hubspot stay unflipped (no dynamic client registration). Counts re-derive to 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown. Catalog oauth validation now rejects client secrets explicitly instead of silently dropping them, symmetric with the client-id rejection.\n\n* feat(coding-agent): wire oauth client identity through shared mcp provider factory (ENG-6108)\n\n* fix(ai): mirror engine PRM selection in the metadata audit (ENG-6108)\n\nBugbot PRRT_kwDOSXZbXs6hvVZP + PRRT_kwDOSXZbXs6hvVZS: auditEndpoint now mirrors oauth.ts exactly - a WWW-Authenticate resource_metadata pointer is followed alone and any failure fails closed with no well-known fall-through; absent a pointer the pathful well-known is tried then the origin-level root location (SDK parity, 4xx continues); a candidate is selectable only when its document passes the engine audience component comparison and carries authorization servers. protectedResourceUrl is used at the call site instead of an inline construction. The bounded read-only audit was re-run (public GETs only, DNS-pinned, all bounds unchanged) and readiness re-derived: the reviewer obligation flips stay intact; codspeed and resend flip to oauth-ready via the SDK-parity origin-level fallback (valid documents, DCR, coherent AS); confidence-docs/-flags stay unknown with fail-closed notes (served-but-invalid documents); logrocket stays unknown with the precise fail-closed reason; slack/hubspot stay unflipped (DCR-less); shopify metadata is now available but DCR-less. Counts: 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown; metadata 97 available / 6 unavailable.\n\n* fix(ai): require the exact engine fallback condition for oauth-ready (ENG-6108)\n\nBugbot PRRT_kwDOSXZbXs6hva2k: evidenceSupportsStandardOauth granted oauth-ready via origin-AS evidence for ANY no-served-JSON state, but the engine reaches its origin-level AS fallback ONLY when no resource_metadata pointer was followed and every tried well-known candidate returned exactly a 4xx (5xx, fetch errors, 2xx/3xx non-JSON bodies and served-but-invalid documents all throw with no fallback). A precise engineFallsBackToOriginAs predicate is now derived from the recorded attempts (followed or rejected pointer, served document, and per-attempt httpStatus), so fail-closed discovery stays honestly unknown. The audit script selectionNote now fires only for true fail-closed states; the all-4xx state is the engine honest fallback and records no note. The bounded read-only audit was re-run to match the corrected note semantics (aggregates stable: 103 audited, AS 97/6, DCR 78, CIMD 25, PKCE 97). Zero readiness flips - pure hardening; 7 all-4xx entries lose stale generic notes; new regression assertions pin intercom (oauth-ready via the legitimate origin-AS fallback, no note) and adobe-for-creativity (unknown, unavailable AS, no note). Counts unchanged: 72 oauth-ready / 53 user-setup / 5 prime-restricted / 10 unknown.\n\n* fix(ai): classify figma as registered-client after live DCR 403 evidence (ENG-6108)\n\nDogfooding PR #2256 head 8e77f0cc1 surfaced what the read-only audit could\nnot observe: Figma's advertised dynamic-client-registration endpoint returned\nHTTP 403 to the engine's anonymous registration POST during a real\n/mcp login figma attempt (2026-09-13), while its AS metadata still advertises\nthe endpoint with confidential-only client auth. A public metadata-only GET\nof the register endpoint returns 404, and public reports corroborate the 403\nfor anonymous DCR requests; whether self-registered Figma apps can obtain\nmcp:connect is publicly unresolved.\n\n- Audit store: the live attempt is recorded as an authorizationServer\n  registrationAttempt block with explicit provenance (the audit script never\n  POSTs registration endpoints); the script now preserves these blocks\n  verbatim on re-runs, and the $comment sanctions exactly this supplement.\n- Importer: an advertised registration endpoint whose live anonymous\n  registration was rejected (401/403) is gated evidence —\n  auth.metadata.dynamicClientRegistration flips to an explicit false (gated,\n  distinguishable from omitted \"not advertised\"), the gated finding becomes\n  the default metadata note, and the entry can never be oauth-ready\n  (fail-closed, the same honest class as DCR-less Slack/HubSpot).\n- overrides.json: figma mirrors the Slack precedent — pre-registered client,\n  registered-client requirement, prime-restricted readiness, requires-setup\n  with the 403-documented reason and FIGMA_MCP_CLIENT_ID / FIGMA_MCP_CLIENT_SECRET\n  setup fields.\n- Regenerated catalog.json + catalog.data.generated.ts via the importer;\n  counts: ready 82 -> 81, requires-setup 58 -> 59, oauth-ready 72 -> 71,\n  prime-restricted 5 -> 6 (user-setup 53, unknown 10 unchanged; sum 140).\n\nOffline verification: catalog suite 25/25, coding-agent catalog eligibility\n12/12, tsgo --noEmit clean, and both catalog scripts typechecked under the\nrepo base config.\n\n* drop the revert changelog fragments\n\nthe reland makes the \"removed\" entries moot before any release cut them;\nthe release notes should only describe the additions.\n\n* feat(ai): cut the service catalog to zero-app self-serve only (ENG-6108)\n\n2026-09-14 product decision: Prime maintains ZERO provider OAuth apps, so\nthe catalog advertises only what works self-serve — dynamic client\nregistration (readiness \"oauth-ready\") or user-supplied tokens/keys\n(\"user-setup\"). Every entry classified prime-restricted (needs a\nprovider-registered client) or unknown (no verified self-serve path) is cut\nfrom the shipped catalog; audit/engine parity, the readiness vocabulary and\nthe fail-closed classification machinery are unchanged.\n\n- overrides.json: the 16 cut providers (figma, gmail, google-calendar,\n  google-drive, mongodb-atlas, slack, adobe-for-creativity,\n  confidence-docs, confidence-flags, hubspot, logrocket, mapbox-docs,\n  shopify, sumup, synthflow, synthflow-docs) are excluded via the documented\n  excludedServers list — one entry per upstream record (18 keys: figma and\n  slack are merged from both upstreams, so both sides are cut and no ghost\n  entry can re-enter), each with a per-entry reason citing the decision and\n  the specific audit evidence. The now-dead servers overrides for excluded\n  identities were removed; their honesty content lives on in the exclusion\n  reasons.\n- Importer: the cut is enforced structurally — buildCatalog refuses to emit\n  an entry whose readiness classifies prime-restricted or unknown and fails\n  with a curation prompt (exclude with a documented reason, or curate\n  readiness with evidence), so an unverified provider can never ship\n  silently again. The gated-DCR honesty machinery (advertisedRegistrationGated,\n  explicit-false dynamicClientRegistration semantics) is kept and now\n  exported for direct unit tests, since the live case (figma) is excluded\n  rather than classified; the predicate still guards future entries.\n- Audit store: untouched — the pinned source snapshots and metadata-audit\n  results for the excluded endpoints stay committed as evidence (including\n  figma's live 403 registrationAttempt). The audit script now also retires,\n  never drops, registration-attempt evidence for servers that leave the\n  audit target set via the new top-level retiredRegistrationAttempts array,\n  so a re-run can never silently delete the figma evidence.\n- Regenerated catalog.json + catalog.data.generated.ts via the importer;\n  counts: total 140 -> 124 (http 102 -> 86; stdio 32, templated 5, sse 1\n  unchanged), ready 81 -> 71, requires-setup 59 -> 53, oauth-ready 71,\n  user-setup 53, prime-restricted 6 -> 0, unknown 10 -> 0 (sum exact).\n- Tests: mcp-catalog.test.ts now asserts the cut (all 16 ids absent, both\n  upstream sides of merged providers excluded, all 18 keys documented in the\n  import report with zero-app reasons, source snapshots and audit evidence\n  kept incl. figma's 403 attempt), pins the gated-DCR machinery directly\n  with synthetic evidence, updates the count assertions (124/71/53/0/0) and\n  keeps the byte-for-byte regeneration pin; the figma assertions now assert\n  exclusion instead of prime-restricted-in-catalog.\n\nOffline verification: catalog suite 27/27, coding-agent catalog eligibility\n12/12 (plus all 13 coding-agent mcp test files: 281 passed, 1 skipped),\ntsgo --noEmit clean at the repo root, both catalog scripts typechecked\nclean under the repo base config, biome clean on the changed files.\n\n* test(coding-agent): adapt activation-queue route host to the inline auth panel host surface\n\n* test(coding-agent): drive logout route assertions through the inline auth panel surface\n\n* fix(ai): demote confidential-only AS providers to the user-setup OAuth path (ENG-6108)\n\nLive gap found in dogfooding: Hugging Face /mcp login failed at connect with\n\"no compatible client authentication method (advertised: client_secret_basic,\nclient_secret_post)\" because the catalog classified the entry oauth-ready\nwithout ever checking token_endpoint_auth_methods_supported; the engine checks\nit at runtime and fails closed.\n\n- Extract the engine's fail-closed client-auth decision from\n  negotiateAuthMethod into the exported decideClientAuthMethod and add the\n  catalog predicates tokenAuthMethodsSupportPublicClient /\n  tokenAuthMethodsSupportConfiguredClient in packages/ai/src/mcp/oauth.ts —\n  the importer runs the SAME decision, so classification and the connect-time\n  gate share one source of truth.\n- Wire the gate into importer readiness: coherent DCR evidence with\n  confidential-only advertised methods now demotes honestly to the user-setup\n  OAuth path (requires your own OAuth app reason, registered-client\n  requirement, client-id/client-secret setup fields) instead of oauth-ready —\n  the user's own registered app, zero-app compliant, never an exclusion.\n  Advertised methods that serve not even a configured secret-bearing client\n  (mTLS-only) keep failing closed as today; omitted lists stay oauth-ready\n  per the engine's public-client spec default.\n- Regenerate catalog.json, catalog.data.generated.ts and import-report.json:\n  14 entries demote (airwallex, airwallex-sandbox, atlan, gitlab,\n  hugging-face, legalzoom, lusha, miro, monday-com, planetscale, supabase,\n  vercel, windsor-ai, zoominfo) — readiness counts move 71->57 oauth-ready and\n  53->67 user-setup; total 124 and zero prime-restricted/unknown invariants\n  hold, each entry carrying its confidential-only evidence and note.\n- Document tokenAuthMethods as required engine-compatibility capture in the\n  audit script and catalog README so future audits keep the check.\n- Tests: pin the hugging-face demotion with its confidential-only evidence and\n  the full demoted set, add the synthetic classification matrix\n  (confidential-only demotes, none/omitted stay one-click, mTLS-only stays\n  unknown) and direct predicate tests; update readiness count pins. The\n  byte-for-byte regeneration pin and the coding-agent eligibility thresholds\n  pass unchanged.\n\n* test(coding-agent): pin the MCP auth routes to the inline auth panel surface\n\nthe guarded-credential race test kept an unobserved showOverlay stub on the\nfake route TUI; it now asserts the generic /logout service selector never\nmounts an overlay popup, so MCP auth can only render through showAuthPanel\nlike #2331 provider logins. adds the changelog fragment documenting that\nevery MCP auth surface (guarded staged OAuth dialog, /login and /logout\nservice selectors, mcp-connections tab, /mcp login) mounts inline under\nthe chat with stacked closers, focus restore, and rows-aware sizing.\n\n* feat(ai): cut the catalog to one-click DCR or user token/key only (ENG-6108)\n\n2026-09-15 product decision (\"remove everything that's not one-click auth\nor api key\"): the shipped catalog advertises only one-click dynamic client\nregistration (readiness \"oauth-ready\") and user token/key entries; the\nclassification machinery and audit/engine parity are unchanged.\n\n- overrides.json: the 49 non-token/key entries — the 14 registered-client\n  entries whose authorization servers accept only secret-bearing client auth\n  (airwallex, airwallex-sandbox, atlan, gitlab, huggingface-skills,\n  legalzoom, lusha, miro, monday-com, planetscale, supabase, vercel,\n  windsor-ai, zoominfo), the 32 local-runtime stdio adapters and the 3\n  url-only tenant templates (activecampaign, jfrog, pigment) — are excluded\n  via the documented excludedServers list: one entry per upstream record\n  (64 keys: monday-com/supabase/vercel are merged from both upstreams, so\n  both sides are cut; every stdio server of the multi-server adapter plugins\n  is excluded), each with a per-entry reason citing the decision and the\n  specific evidence. The now-dead servers overrides for excluded identities\n  were removed; their honesty content lives on in the exclusion reasons.\n- Importer: the cut is enforced structurally — buildCatalog refuses to emit\n  a user-setup entry whose requirement is not token/key-shaped\n  (bearer-token/api-key credentials, a tenant config with a genuine non-url\n  field, or a legacy-transport entry that still collects a token/key) and\n  fails with a curation prompt, so a registered-client demotion, a\n  local-runtime adapter or a url-only template can never silently re-derive.\n  The auth-methods honesty machinery (decideClientAuthMethod parity,\n  confidential-only demotion, tokenAuthMethods capture) is unchanged and\n  stays active for the survivors.\n- Audit store and source snapshots: untouched — evidence for the excluded\n  endpoints stays committed as history.\n- Regenerated catalog.json + catalog.data.generated.ts + import-report.json\n  via the importer; counts: total 124 -> 75 (http 86 -> 72, templated 5 -> 2,\n  sse 1 unchanged, stdio 32 -> 0), ready 57 unchanged, requires-setup 67 ->\n  18, oauth-ready 57, user-setup 18, prime-restricted 0, unknown 0 (sum\n  exact); api-key strategy 32 -> 16.\n- Tests: mcp-catalog.test.ts pins the cut (all 49 ids absent, both upstream\n  sides of merged providers excluded, all 64 keys documented in the import\n  report with 2026-09-15 reasons, source snapshots and audit evidence kept,\n  the shipped user-setup set is exactly the 18 token/key entries), keeps the\n  confidential-only machinery matrix (now pinned on the committed\n  huggingface-skills audit evidence plus the synthetic matrix), adds the\n  structural invariant regression (lifting the gitlab exclusion fails the\n  import with the curation prompt), updates the count assertions (75/57/18/\n  0/0) and keeps the byte-for-byte regeneration pin; coding-agent\n  mcp-service-catalog count comment + eligibility sweep thresholds updated\n  for the 75-entry catalog (api_key >= 10 still holds at 16; unknown 53).\n\nOffline verification: ai catalog suite 29/29, ai mcp-oauth 40/40, all 13\ncoding-agent mcp test files 276 passed 1 skipped (catalog eligibility 12/12,\nservice catalog 63/63), tsgo --noEmit clean at the repo root, biome clean on\nthe changed files.\n\n* fix(tui): separate the oauth url from the browser-step text with a blank line\n\n* fix(tui): keep the service-catalog picker at one description line with stable frames\n\n* feat(tui): persist MCP connect outcomes as refinement-style chat entries (ENG-6108)\n\nConnect outcomes (\"Connected Linear (12 tools verified)\" and its\nsaved-but-unverified variants) were transient status lines that vanished;\nthey now persist in the chat transcript like harness refinement notices.\n\n- Add the mcp_connection_outcome custom message with structured details\n  (label, login/retry source, connected/unverified/unsaved verification\n  state, tool count, account id, activation) and the exact legacy wording\n  as its content; keep it out of LLM context like refinement outcomes.\n- Render it with a purple refinementHeader \"◆ Connected <service> · N\n  tools verified\" header over a refinementSummary body via the\n  ExpandableEventMessage base; register live rendering and transcript\n  replay (malformed entries included) and gate both on display.\n- Route both emit sites (pending-account retry verification and the\n  guarded login completion) and their failure/partial variants through\n  completeMcpConnectionOutcome: reload, then append the durable entry via\n  the new AgentConnection.appendCustomMessage (in-process sendCustomMessage,\n  daemon legacy append_custom_message RPC). Mid-turn connects keep the\n  transient \"will activate automatically\" line and record the durable\n  entry at the next safe boundary; a failed reload marks the entry\n  \"not active in this session\". Pre-outcome login failures (eligibility,\n  claim, finalize, incomplete login) remain transient warnings.\n- Focused tests: component rendering/replay, formatter wording parity,\n  and both emit sites including queued-boundary, inactive, and\n  append-failure fallback paths.\n\n* fix(tui): flatten multi-line catalog copy before it becomes a picker line\n\n* fix(tui): repair /mcp picker chrome nits and search ranking (ENG-6108)\n\nFive chrome nits from Kevin's live testing plus the picker search:\n\n- The scroll counter aligns with the row indent (rows render their label\n  at column 2; the counter and the empty-state message now do too).\n- Enter on an accounts-picker row 1 (the account name) re-verifies the\n  account instead of disconnecting it; only the explicit Remove row\n  removes. connectServiceFromPicker's connected branch now re-verifies\n  exactly like the pending branch.\n- One blank line between the last row and the description line in both\n  catalog and accounts mode, budgeted in updateLayout so frames stay\n  height-stable.\n- Accounts search matches identity only (account label + connection\n  id): every account row shares the same description/setup hint, so\n  matching that text could never filter anything.\n- Every inline MenuPanel opens with exactly one separator rule between\n  the chat view and the picker: a titled panel draws the rule above its\n  title; a headerless panel keeps the bordered search's top border as\n  that rule, never both. Model/provider/oauth/extension/prime-team\n  pickers budget the rule through the shared inlineMenuPanelTopRuleRows\n  helper.\n- Search ranking rewritten: exact/prefix/word-start/substring matches on\n  label, service id, and aliases rank far above description/setup-hint\n  text; the identity-only subsequence fallback requires a consecutive\n  run of half the query (minimum two); descriptions match only as\n  word-start/substring. Searching vercel against a catalog without\n  Vercel now yields the No-matching-services empty state instead of\n  eight unrelated rows matched through setup-hint boilerplate.\n\n* fix(mcp): cut non-token catalog survivors and say what to paste\n\n2026-09-16 product decision, from live picker testing: the catalog ships\none-click DCR connectors and simple paste-an-API-key/token services only.\n\nCut 5 survivors with documented per-entry reasons in overrides.json:\n- cockroachdb (cockroach-labs): tenant config, only input is the\n  per-cluster `mcp-cluster-id` header, no key/token field\n- dynatrace, sourcegraph: tenant instance URL next to the token\n- paypal-sandbox: legacy SSE, the runtime cannot connect to it at all\n- render: api-key requirement with zero setup fields, nothing to paste\n\nThe importer now enforces the narrower rule structurally: a user-setup\nentry ships only when its requirement is bearer-token or api-key AND it\ncollects at least one bearer-token/api-key field. An entry the readiness\npass never classified also fails closed instead of slipping past every\nshipping guard.\n\nAll 13 surviving setup reasons are now picker copy for a human: one line,\nstarting with \"paste\", naming the entry's real field. \"requires provider\ncredentials supplied as headers\" and \"requires an auth token supplied via\nenvironment variable\" are gone; github no longer stutters the same clause\ntwice; zoom-meetings drops the upstream placeholder note that never\nchanged what the user does. A test pins the shape.\n\nCatalog: 75 -> 70 entries (57 oauth-ready, 13 user-setup), all plain\nstreamable-http. Evidence, source snapshots and audit store unchanged.\n\nENG-6108\n\n* fix(tui): drop the restated MCP connect body and add disconnect feedback\n\nKevin saw the durable connect entry print the same sentence twice: the\nheader and the body both said \"Connected Granola (6 tools verified)\".\nThe header is the outcome line, so the body now carries ONLY what the\nheader omits - added account, verification issue plus next step, deferred\nactivation - and a plain success renders as the header alone. The\npersisted `content` keeps the full legacy sentence, because the transient\nfallback and status lines still need a whole sentence.\n\nDisconnects had no durable feedback at all. A successful disconnect from\n/plugins, `/mcp logout <name>`, or the generic `/logout` route now leaves\nthe same kind of entry, in the muted theme key: not the connect purple (a\ndisconnect is no refinement) and not the error red (it succeeded) - the\ngrey /plugins already uses for \"Not connected\". Only outcomes that really\nremoved the credential (removed, credential-only, preserved) get an\nentry; \"logged-out\" (partial save failure), \"failed\", \"missing\", and the\nstate-neutral \"refused\" keep their honest warnings and record nothing, so\nno entry can claim a disconnect that did not finish.\n\nThe generic /logout route still runs ONE store op and ONE reload: the\nhost records the outcome under its existing delegation and the selector\nappends it after the reload it already did.\n\nENG-6108\n\n* fix(tui): record the picker disconnect entry on the remove row\n\n* fix(tui): rebuild the /mcp accounts menu as a choice list (ENG-6108)\n\nKevin's live-testing redesign: the accounts menu drops its no-op search box\nand account-name row, renders '<service> MCP' with the muted description\n(wrapped, capped at three lines) above the options, and lists Reconnect /\nDisconnect <id> / Add another account in the PR #2340 selection language\n(mirrored locally until #2340 lands). Reconnect keeps the existing re-verify\npath and never disconnects; Disconnect keeps the store-locked removal and\nits durable disconnected entry.\n\nCatalog picker nits: the Connect trailing status reads in the text colour\ninstead of the accent purple, and the empty state gains one blank row above\nthe shortcuts line, aligned with the row labels (pinned at width 120).\n\n* fix(tui): stop inline pickers doubling the separator rule\n\n* feat(mcp): connect paste-a-key catalog services through an inline masked paste panel (ENG-6108)\n\n* fix(mcp): collapse the paste flow to ONE credential per service, cut named-header pairs (ENG-6108)\n\nTwo Bugbot findings, one root cause: the generic MCP runtime sends exactly\none Authorization: Bearer per connection, but the paste flow treated every\nrequired credential field as a separate mandatory prompt, and GitHub's two\nsetup fields (GITHUB_PAT_TOKEN / GITHUB_PERSONAL_ACCESS_TOKEN) were presented\nas two required tokens when they are alternative names for one PAT.\n\n- Curate GitHub's fields as alternatives via a shared field-level\n  credentialSet (\"github-pat\") in mcp-catalog/overrides.json; the paste flow\n  now prompts ONCE, labels honestly (\"GitHub personal access token\") and\n  stores the value under the first alternative's id.\n- Cut datadog and cloudinary-mediaflows from the catalog (documented\n  excludedServers reasons citing the named-header evidence: DD_API_KEY +\n  DD_APPLICATION_KEY, cld-api-key + cld-secret - one bearer can never\n  authenticate them). Catalog: 68 entries = 57 one-click DCR + 11 paste.\n- The importer now throws when a shipped requires-setup entry collects more\n  than one distinct required credential, so an unmarked multi-credential\n  entry can never silently re-derive; tests pin the guard by lifting the\n  datadog and cloudinary exclusions.\n- Simplify the host flow to one prompt/one value (no multi-field loop, no\n  per-field checkmark rows); masking, Esc-cancels-nothing-stored, the\n  empty-value guard, verification and the durable Connected outcome are\n  kept; services with genuinely distinct credentials stay honest\n  setup_required and are not pasteable.\n\n* fix(mcp): drop the dead paste-credential branch and trim the importer comment\n\n* fix(tui): render paste outcomes honestly and polish the accounts menu\n\n* fix(tui): budget the accounts frame for the trailing blank row\n\n* fix(tui): keep the /mcp picker chain open after connect, disconnect, and paste actions\n\nSelecting a row no longer drops the user back to the prompt after the action: the picker chain re-enters the right surface, rebuilt from the live catalog and connection store. Disconnecting one account reopens that service accounts menu without the removed row; disconnecting the last account, or a cancel that stored nothing, reopens the catalog; reconnect/re-verify, add-account, and paste re-enter the accounts menu with refreshed state. Esc closes the whole chain, and actions blocked before they start (login in progress, guidance, target drift) end the chain with their status line instead of re-opening, so there is no re-entry loop.\n\n* fix(tui): drop the accounts description instead of overflowing tight viewports\n\n* fix(tui): one reconnect/disconnect row per service with an account sub-picker, and left-arrow back to the catalog\n\nA service's accounts menu is now exactly three rows — Reconnect, Disconnect, Add another account — instead of a reconnect/disconnect pair per connection id. With one account, Enter acts on it directly with the existing re-verify and remove semantics. With several accounts, Enter on Reconnect or Disconnect opens a second inline picker in the same choice-list shape that lists the account ids; picking one runs the action on that connection id only, and Esc or left there returns to the accounts menu without acting. The sub-picker never nests deeper, and after an action the existing re-entry table decides the next surface (the accounts menu while an account survives, the catalog otherwise).\n\nLeft arrow from the accounts page now navigates back to the /mcp catalog — the picker chain's parent surface — remounted fresh, using the same app.modal.back binding the dialogs share; Esc still closes the whole chain, and left in the catalog stays inert. The accounts frame budget is unchanged (the option count is the only thing that grows), the budget test now pins the three-row count, and the multi-account re-entry tests drive the sub-picker end to end.\n\n* fix(tui): colour mcp outcome entries by outcome, warning for non-success\n\n* fix(mcp): keep alias OAuth providers behind the parent service catalog classification (ENG-6108)\n\n* fix(mcp): probe the origin-level oauth-protected-resource document without the endpoint query\n\n* test: bring ENG-6108 suites into the main-branch testing policy (#2336)\n\nShrink the branch's test additions from a net 16,514 to 16,610? -> net 11,610\ntest lines (the same as the branch's source additions), clear all 46 new\ntest-policy pattern violations, and consolidate per the policy's \"one file\nper module, regressions live in the owning suite\" rules. No test survives\non a timer, poll, sleep, skip, or env gate; every wait resolves on a\nconcrete deferred signal (mount hooks, probe gates, store flushes).\n\nFolded per-issue regression files into the owning module suites:\n- suite/regressions/eng-6108-inline-picker.test.ts -> the picker-chain\n  describe in test/service-catalog-picker.test.ts (mount/stale/replacement\n  settling, action routing, re-entry, settings-actions freeze, paste flow,\n  blocked actions) with vi.waitFor replaced by ui.setFocus-mount and\n  action-start deferred signals; the pure row-shape/menu layout pins\n  already covered by the component tests were deleted.\n- suite/regressions/eng-6108-service-catalog-activation.test.ts -> the\n  connect-then-activate end-to-end test in test/agent-session-services\n  .test.ts; the stored-token-pending duplicate died (already pinned in\n  mcp-service-catalog).\n\nDissolved test/mcp-account-commit-safety.test.ts; its unique invariants\nmoved to the owning suites and the rest were duplicates:\n- store->auth gap interleave + finalize nonce ownership + no-resurrection\n  -> test/mcp-connection-store.test.ts\n- CAS-absence replaceStagedCredential -> test/auth-storage.test.ts\n- /mcp login on a PENDING account, vanished-source repair (record+grant\n  evidence; bare shell refuses), and the paste-flow seam (single-credential\n  static token, cancelled/empty value, login-in-progress and target-changed\n  refusals) -> test/mcp-activation-queue.test.ts.\n\nConsolidated near-identical seams (surviving test -> invariant it owns):\n- grant-state matrix pinned ONCE in mcp-catalog-eligibility (predicate +\n  prompt + dispatch + view parity); manager's copy deleted.\n- reserved-name ownership pinned at dispatch level in mcp-manager; the\n  view-level copy and mcp-service-safety's provider-lifecycle duplicate\n  deleted.\n- cap protection pinned in mcp-service-catalog (resolver's own module);\n  mcp-catalog-eligibility's copy deleted.\n- remove/logout-vs-finalize races pinned once at the REAL route seam in\n  mcp-activation-queue; the store-level interleave duplicate deleted.\n- exact rendered copy kept only where it is a durable protocol contract\n  (outcome notice wording); component render pins made structural.\n- oauth client-auth negotiation + PRM-mismatch refusals + python discover\n  cursor/table families -> it.each/subTest tables.\n\nViolation conversions (all 46 cleared):\n- wall-clock-timer/poll/sleep: setFocus-mount signals, action-start\n  deferreds, queueVerifyResult+flush chains, an asyncio.Event hang, and\n  fs.watch for the multi-process ready barrier.\n- environment-gated-path: the 11 false positives in mcp-oauth (mock route\n  conditions carrying token/credential substrings) renamed via aliases;\n  the rest made unconditional.\n- explicit-test-timeout: allowed with policy comments only where the\n  probe's own timeout bound IS the behavior under test (probe hang tests,\n  real multi-process spawn).\n- conditional-or-disabled-test: kernel-bootstrap made unconditional\n  (file-scoped venv resolution, no cwd dependence; merge of main's #2336\n  had dropped the branch's theme bootstrap in menu-panel too - restored).\n\nVerified: every modified suite passes standalone and under 6 shuffle\nseeds; npm run check (biome + check:test-policy + tsgo + installer +\nbrowser-smoke) is green; spot-reverts of the chain re-entry rule and the\nstore finalize-ownership guard both fail the consolidated tests.\n\n* fix(mcp): mirror the engine audience rule and first-issuer selection in the audit\n\n* fix(mcp): fail closed on a malformed advertised issuer and fix the notion URL substring check"},{"name":"thinking-levels.ts","kind":"file","size":691,"lastCommitHash":"81cd5390dbc871afb87be0d2012d205dd633bae3","lastCommitWhen":"2026-09-10T13:50:11+02:00","lastCommitMessage":"preserve reasoning in refinement and side questions (#2130)\n\n* fix(ci): accept engineering and research Linear tickets\n\n* fix(ci): clarify the Research ticket project\n\nfixes #2124\n\n* fix(coding-agent): preserve reasoning in auxiliary calls\n\nRefs ENG-6010 and discussions #1482 and #2081.\n\n* fix(ci): clarify Prime Agent board routing\n\nfixes #2124\n\n* fix(coding-agent): reserve refinement reasoning output budget\n\nRemove fixed output caps when reasoning is enabled and reserve prompt context within the model limit. Keep truncation failures bounded without retrying.\n\nfixes #2130\n\n* fix: preserve refinement context and valid thinking budgets\n\nEstimate refinement tokens and shorten only older trajectory content when space is tight. Enforce valid minimum thinking budgets for budget-based Claude requests.\n\nfixes #2130\n\n* fix(ci): isolate Ubuntu package sources\n\n(cherry picked from commit 7656902c301c5d9c26d8646f66461bf75dba5a9f)\n\n* test(coding-agent): allow context before literal prompts\n\n(cherry picked from commit 59e97147e4f559e969f629da9430be4613cc7898)\n\n* fix(coding-agent): bound dense refinement context (fixes #2130)"},{"name":"timings.ts","kind":"file","size":1117,"lastCommitHash":"8fcdb67cb7a326cc372dce4526a818fd853f70ec","lastCommitWhen":"2026-09-17T06:43:53+03:00","lastCommitMessage":"coding-agent: attach with the daemon summary instead of parsing the transcript\n"},{"name":"usage.ts","kind":"file","size":2428,"lastCommitHash":"d74a75fea3411136fdd2ba95c7f723ddefdadf05","lastCommitWhen":"2026-09-03T18:08:28-04:00","lastCommitMessage":"feat: token and cost details on agents view rows (#2003)\n\n* fix: count busy descendants in the agents-view subagents indicator\n\nThe \"N subagents running\" indicator only tallied direct children whose\nrow classified as running, so a busy grandchild under an idle\nintermediate child left every ancestor reading \"N subagents\" with a zero\ncount. The tally is now a bottom-up pass over the built rows - the live\nper-descendant truth - replacing the direct-child increment.\n\nIndicator only, per policy: a session is Running when it works itself;\nidle ancestors of busy subtrees stay in Idle. Within Idle they now rank\nabove plain idle rows, and a collapsed group's summary row renders its\nrunning count in the success color instead of dimmed so the busy subtree\nis discoverable without expanding.\n\nDiagnosis credit: Vincent Bailly (VincentBailly/prime-agent#9) traced\nthe stale hasRunningRlmChildren snapshot and the row-walk mechanism;\nthis adopts his walk for the indicator while rejecting the section\npromotion.\n\nRES-1253\n\n* fix: tally busy descendants before heartbeat promotion inflates sections\n\nThe descendant tally read row sections after\npropagateHeartbeatStateToAncestors had promoted idle ancestors to\nrunning, so a heartbeat-active grandchild counted its promoted parent\ntoo. The tally now runs before the promotion pass and counts\nintrinsically busy rows only; once that propagation pass is deleted\n(#1967) the ordering is a no-op.\n\nRES-1253\n\n* fix: make the descendant tally iterative so deep chains cannot overflow\n\nThe recursive tally threw RangeError on a deep child chain just by\nopening the agents view. The nesting loop assigns every row at most one\nparent, so the tree is a forest: a reverse breadth-first pass over one\nwork list computes the same bottom-up counts iteratively, with the\npre-promotion ordering kept.\n\nRES-1253\n\n* fix: classify running from the session's own work, not delegated children\n\nSecond half of the RES-1253 policy, user-approved: Running means the\nsession you enter is doing work now. Delegated child work no longer\nclassifies a session as running - the busy-descendant badge, count, and\nidle ranking from the first half carry the delegation signal.\n\nhasRunningRlmChildren loses its section-classification role in both\nowners: classifySessionRosterStatus composes busy from the session's own\nactivity/isSessionActive, and isActiveSessionBusy (the worker's activity\naxis) no longer holds a settled parent at \"working\" for its children.\nThe \"subagents running\" status label dies with the section it had to\nagree with. The field itself stays on the wire, and isSessionSummaryBusy\nkeeps it on purpose for its residency and shutdown-safety consumers\n(worker eviction snapshots, empty-draft eviction, busy client-owned\nsession counts, daemon stop confirmation).\n\nRES-1253\n\n* chore: note the running-means-the-session policy in the changelog fragment\n\n* fix: split display activity from live-work safety in the busy predicates\n\nisActiveSessionBusy served two meanings after the classification change:\nthe display activity axis (session's own work only, correct) and worker\nrecovery plus draft-discard (where a running RLM child is live work that\ndies with the worker). The recovery journal recorded busy:false for a\nsettled parent with a running child, so a worker death skipped its\ninterruption record and notice.\n\nThe shared predicate is deleted and each meaning gets one named owner:\nactiveActivityForSession reads the session's own isSessionActive\ndirectly, and hasLiveSessionWork (own turn or running RLM child) backs\nrecordWorkerRecoveryState and isDiscardableDraft. No caller can grab the\nwrong meaning blind.\n\nRES-1253\n\n* feat: show token and cost totals on agents view rows\n\nEvery agents view row with usage data now reads\n`<input>/<output> | $<own> ($<recursive>)` in the details cell, replacing\nthe message-count detail. Own numbers are the session's whole-file spend\n(every branch, forks included, attributed child usage subtracted) - the\nmoney answer, deliberately broader than /usage's current-branch context\nanswer, and identical for resident and on-disk rows so nothing shifts at\npassivation or revival. The recursive total rides the same reverse\nbreadth-first traversal as the running-subagent tally, summing each\ndescendant row's own cost exactly once.\n\nProducers: resident summaries compute the total from the already-loaded\nentries, memoized until entries change (0.27 ms measured cold at 10k\nentries); saved rows accumulate it inside the existing mtime/size-cached\ncatalog scan, so old files get costs with no new IO and no new cache.\nEntries over the scan's max line length keep their existing skip, so a\ngiant assistant message can undercount slightly. Schema revision 26\npublishes the new optional summary and saved-row field.\n\nRES-1258\n\n* feat: final row usage format with arrows and conditional recursive cost\n\nDetails cell now reads `↑12k ↓1.2k · $0.42 ($1.10 w/ subagents)`; the\nparenthesized total renders only when descendants added spend visible at\ncent rounding, so leaf rows read `↑500 ↓50 · $0.68`. Arrow glyphs follow\nthe existing TUI vocabulary (keybinding hints, token status) and the\nwidth pipeline already treats them as single cells.\n\nRES-1258\n\n* fix: one own-spend truth across scan, loader, and filters\n\nReview round on the usage feature:\n\n- The catalog scan subtracted attributed child usage from disk values\n  that (in append-only files) still carry the assistant's ORIGINAL\n  model-response usage, double-subtracting and shifting numbers at\n  passivation. Full-file rewrites (migrations, forks) can also persist\n  the already-folded aggregates, so raw summation is wrong for those\n  files instead. The scan now mirrors the loader exactly: fold each\n  attribution's aggregate onto its target, then subtract the child usage\n  - both disk representations cancel to the same own spend the resident\n  computation reports. The equality pin now goes through a real v3\n  flushed-then-attributed fixture (the old fixture had no attribution,\n  which is why it never caught this).\n- Recursive cost was computed over search-filtered rows, so a matching\n  parent showed an incomplete \"w/ subagents\" total. The rollup now comes\n  from the unfiltered record hierarchy (computeRecursiveCosts over the\n  unified index) and filtering can no longer change the number.\n- Zero-spend sessions published 0/0/$0.00 live and nothing once\n  passivated; sessionUsageSummaryFrom now returns undefined for zero\n  totals, shared by both producers, so rows stay age-only until real\n  spend exists.\n\nRES-1258\n\n* fix: gate destructive agent actions on live work, not display section\n\nSince Running means the session's own work, an idle parent of a running\ncrew was branching into the delete path: killSubagent chose stop-vs-\ndelete from the display section and stopAgentForDeletion treated\nactivity==='working' as the only live work. Destructive actions are\nsafety consumers of the display/safety split: one row-level hasLiveWork\n(own section running, busy descendants, or the wire running-children\nflag) now drives the stop-first branch, the deletion flow, and the\nconfirmation verb.\n\nAlso trimmed the tally comment to current behavior.\n\nRES-1253\n\n* fix: stop live descendants when cancelling a settled child run\n\nStopping a subagent row whose own run already settled reported\n'Subagent already finished' while a nested descendant kept running:\ncancelRlmChildRun only cancelled the targeted run itself, and a fully\nreleased child (run removed, session retained) was never matched by id\nat all. Cancellation now descends where the tree lives: a settled target\nstops every running or queued run in its retained session's subtree\n(cancelRunningRlmDescendants, mirroring hasRunningRlmChildren's walk),\nand the returned flag stays truthful so the UI says stopped only when\nsomething stopped.\n\nRES-1253\n\n* feat: render the usage cell unconditionally, zeros included\n\nEvery agents view row now renders the full details cell\n`↑<up> ↓<down> · $<own> ($<total> w/ subagents)` over four defaulted\nnumbers - no presence branching, no thresholds, no conditional paren. A\nsession that never spent reads `↑0 ↓0 · $0.00 ($0.00 w/ subagents)`, and\na zero-usage parent with billed subagents shows its subtree spend\ninstead of hiding it.\n\nRES-1258\n\n* chore: trim comments and fold overlapping pins on the indicator branch\n\nComment pass: multi-line narration cut to one-line invariant guards\n(destructive live-work gate, residency-vs-section busy split, worker-\ndeath live work) and code-readable notes deleted. Test pass: the direct-\nchild indicator pin folded into the grandchild pin (the general case),\nwhich now also carries the idle-label and wire-flag assertions.\n\n* chore: cut the usage feature's comments and collapse its pins\n\nComment pass (>80%): 24 added comment lines down to 4 one-line invariant\nguards (loader-fold cancellation in the scan, passivation-invariance on\nthe resident getter, unfiltered rollup, the revision note). Test pass:\nthe scan-accumulation and resident-equality pins merged onto one forked-\nand-attributed fixture; the descendant-rollup and filtered-total pins\nmerged with a grandchild; the format pin asserts all four row shapes\nfrom one fixture; redundant zero-case and permutation tests deleted.\n\n* fix: cancel and descend at every node of the rlm cancel walk\n\nCancelling a live child run aborts it, and abort cascades into the\nchild's ACTIVE runs - but running work retained under a settled\ndescendant of that child was the end of the line: neither the cascade\nnor the cancel walk visited it. cancelRlmChildRun now descends into the\ntarget's session after cancelling it, and cancelRunningRlmDescendants\ndescends at every node instead of treating running runs as leaves, so\ncancellation is exhaustive over the subtree regardless of each node's\nrun state. The returned flag stays truthful.\n\nRES-1253\n\n* fix: passivated RLM descendants survive restarts as saved-catalog rows\n\nAn RLM child's transcript lives in session-artifacts, which the saved-\nsession scan never visits. While something resident remembered the child\nits row survived; after a supervisor restart an inactive parent's\npassivated descendants silently disappeared from the agents view, and\ntheir spend vanished from the parent's subtree total.\n\nBoth list_saved_sessions composition points now append live spawn-ledger\nchildren the scan missed, through one shared walk: readSessionInfo per\ndescendant, parentSessionPath/rlmDepth backfilled from the edge, deleted\nedges excluded. The view already renders saved-only descendants, merges\nresident duplicates by session identity, and rolls saved usage into\nrecursive totals, so restored rows restore the money with no view change.\n\nMeasured at 300 sessions with 36 passivated descendants: scan 33ms,\nmerge +9ms (cold ledger, ~0.25ms per descendant).\n\nRES-1262\nRES-1258\n\n* feat: compaction and branch-summary calls bill the session they serve\n\nSummarization was invisible money: the compaction model call(s) - two on\na split turn - and branch-summary calls returned usage that was dropped\non the floor, so a session that compacted often under-reported what it\nactually cost. The summarizer responses' usage is now folded (both\nsplit-turn slices) and persisted on the compaction/branch_summary entry,\nand both own-spend producers add the same term: own spend =\nfold(assistant usage) + fold(summarization usage) - attributions,\nidentical resident and scanned. Old entries without the field fold as\nzero; a failed compaction persists nothing, so failed-call billing is\nnot recoverable - there is no committed entry to carry it.\n\nRES-1258\n\n* fix: harden the passive-descendant catalog merge (round 2)\n\nThree review findings on the merge, all real: the transcript header's\nparentSession can point at a forked-away ancestor, so the ledger edge is\nnow the authoritative topology (family() semantics) for parent and\ndepth; ledgers are per sessions-dir family, so each catalog request now\nreads the ledger of the directory it lists instead of always the\ndefault one; and a broken ledger (unreadable, over-quota) no longer\nfails the whole list_saved_sessions response - the merge logs and\nreturns the scanned catalog.\n\nRES-1262\n\n* chore: consolidate the accumulated review-round pins\n\nThe worker-daemon catalog pins from three rounds folded onto one\nfixture: restart rows, per-family ledger isolation, and broken-ledger\ndegradation now share the two-family scaffold. Redundant assertions and\nnarration comments cut; every behavior keeps exactly one pin.\n\n* test(coding-agent): align unified view regression with usage rows\n\n---------\n\nCo-authored-by: Seth <seth@primeintellect.ai>"},{"name":"websearch-credential.ts","kind":"file","size":350,"lastCommitHash":"d773015ba9b1f3e9d17a5eb801601f7688792fcf","lastCommitWhen":"2026-06-24T20:37:36-07:00","lastCommitMessage":"feat(coding-agent): bundle default websearch skill (#86)\n\n* feat(ai): add Claude Opus 4.8 to Prime Inference\n\n* feat(coding-agent): bundle default websearch skill\n\nShip a Serper-backed websearch Python skill with Prime Agent so web\nsearch works without manually installing a skill package. Bundled\nskills load by default and are overridden by user/project/package/CLI\nskills with the same name; --no-skills excludes them.\n\n* fix(coding-agent): resolve bundled skills dir by src checkout\n\nMatch the established srcOrDist asset convention: pick the package-root\nskills dir on source checkouts and dist/skills otherwise, so a stale\ndist/ from a prior build does not shadow live source edits.\n\n* fix(coding-agent): configure bundled websearch skill\n\n* fix(coding-agent): clarify websearch startup warning\n\n* store serper websearch key via /login instead of env var\n\nAdd the Serper key as an api-key credential in the /login screen so it is\nstored in auth.json and injected into the kernel as SERPER_API_KEY; an env\nvar still takes precedence. Drop the startup warning and make the skill's\nmissing-key error instruct the agent to guide the user through /login.\n\nAlso fix two websearch.py bugs: bad numeric env vars no longer crash run(),\nand truncation stays within max_output.\n\n* put serper under a services tab in /login and read its key from auth.json\n\nAdd a Providers/Services tab split to the /login selector (left/right to\nswitch) so the Serper web-search credential lives under Services instead of\nbeing buried in the provider list. Skip the post-login model picker for\nservice credentials.\n\nThe websearch skill now resolves its key from SERPER_API_KEY or auth.json on\neach call, so a key added via /login works even when the kernel started\nfirst.\n\n* harden websearch key resolution and login tab cursor handling\n\nAddress review feedback: resolve the Serper key from a programmatic (SDK)\nagentDir by exporting it to the kernel, ignore non-mapping auth.json and\n\"!command\" key references instead of crashing or sending them verbatim, and\nonly steal left/right for tab switching when the /login search field is empty\nso cursor editing still works.\n\n* resolve serper key via auth storage and fix login tab layout\n\nInject the Serper key resolved through AuthStorage (handles literal, env-var,\nand !command credential forms) into the kernel when websearch is active,\nusing the session's own storage so it is correct for SDK-injected managers.\nThe skill's mid-session auth.json fallback now resolves env-var-reference\nkeys too. Reserve the extra rows the /login tab bar consumes so the selector\nno longer overflows small terminals.\n\n* always export agent dir for websearch and clamp truncation\n\nExport PRIME_AGENT_CODING_AGENT_DIR regardless of the bundled-skill setting so\na --skill or project websearch copy can still locate auth.json; only the key\ninjection stays gated on the bundled skill. Hard-clamp truncated output so it\nnever exceeds max_output when the budget is smaller than the marker.\n\n* scope agent dir to explicit config and use callable skill form in docs\n\nPass agentDir to the session only when the caller set it explicitly, so an\ninjected custom auth storage backed by another directory is not overridden by\nthe default path. Update the websearch docs to call the skill directly. Trim\ncomments.\n\n* gate serper key injection on a loaded websearch skill, not settings\n\nInject the key whenever any websearch skill is loaded (bundled, --skill, or\nproject), so a custom skill relying on the agent to resolve command-backed\ncredentials still works when bundledSkills.websearch is off.\n\n---------\n\nCo-authored-by: Kevin Thomas <kevin.jt2007@gmail.com>"}]