fix(runtime): harden Codex, restart flow, tool previews, and restart gating - #27
fix(runtime): harden Codex, restart flow, tool previews, and restart gating#27kdegeek wants to merge 11 commits into
Conversation
…he sorted test run config.test.ts and a telegram shouldUsePolling test depended on the developer's ambient environment (a host running Hivekeep exports HIVEKEEP_DATA_DIR, DB_PATH, TASKS_MAX_CONCURRENT, PUBLIC_URL...), so they failed locally. The subprocess config loader now starts from a minimal env instead of inheriting the ambient one, the suite loads config hermetically, and shouldUsePolling is asserted against the resolved config URL. Fix the pre-commit hook: run 'bun run test' (the sorted, explicit-path script) instead of a bare 'bun test', whose discovery order leaks process-global state between files and produces spurious failures; and raise the typecheck heap so tsc does not OOM on low-RAM hosts.
MarlBurroW
left a comment
There was a problem hiding this comment.
Thanks @kdegeek for another substantial PR! There is genuinely good work in here: the pending tool-preview normalization fixes a real rendering gap, the shell-tools realpath fix is a proper hermeticity improvement, and the crash-safe pre-inserted assistant row attacks a real restart-replay problem. We test-merged the branch onto current main, ran typecheck plus the full suite (green), and booted the merged app through a full LLM turn.
We cannot land it as is though: three blockers, plus a large part of the Codex work has been superseded on main since you branched (main is 100+ commits ahead).
Blockers
- The toolset-resolver change breaks onboarding.
filterToolboxGrantedToolNamesstrips everydefaultDisabledtool from all toolbox grants, including tools a toolbox lists explicitly by name. The built-inconfiguratortoolbox explicitly listscreate_agent,update_agentandrestart_platform(alldefaultDisabled), and Queenie's only grant source is that toolbox, so after this change she cannot create agents and onboarding is dead. It also turns explicitly checked entries in user-created toolboxes into dead affordances. The grant semantics here are settled project design:allowed = CORE ∪ toolbox names ∪ per-agent extras, where listing a tool in a toolbox IS the grant. If the concern is the*wildcard expanding to dangerous tools, the right scope is to filterdefaultDisabledonly inside the wildcard expansion, never from explicitly named grants. - The restart confirmation gate only works in English.
textMentionsRestartrequires the literal words restart/reboot andresponseLooksAffirmativerequires yes/confirm/etc., butprompt_humanquestions and option values are authored by the agent in the user's language (10 locales are supported). On a French instance the agent asks "Redémarrer Hivekeep ?" and stores "oui", so the gate fails closed forever andrestart_platformbecomes unusable. The text matching is also weak in the other direction: any answered confirm mentioning a restart of anything (a cron, an email sync) within the 10-minute window authorizes a platform restart. A structured correlation would be robust in both directions: makeprompt_idrequired, or tag the prompt with an explicit purpose field, instead of regexing agent-authored natural language. _anthropic-oauth-auth.tscan now crash the server at boot.getRealHome()throws whenHOME/REAL_HOMEare unset or relative andUSERis unset, and it runs at module load time. A container or systemd unit withoutHOME/USERgoes from a soft "credentials not found" to a hard boot crash, even when that provider is never used. Your own_codex-auth.tsreturnsenvHomein the same case; doing the same here fixes it.
Superseded by main
The Codex model-catalog area was rebuilt on main after your branch point: it now fetches the live per-account catalog (GET /codex/models?client_version=...), falls back to the CLI cache, then a one-entry static floor, derives reasoning levels and modalities from backend metadata, and auth moved to a vault-first getCodexOAuthCredentials(config) flow. The expanded hardcoded fallback list and its test conflict with both the new code and the project rule against hardcoded model ids, so on a rebase those resolve to main's versions. The salvageable pieces are your multi-candidate models_cache.json path resolution (macOS and nonstandard homes) and the HOME-path candidates in the two auth helpers (with blocker 3 fixed); both would make a nice small patch against current main. Same story for package.json and telegram.test.ts: main already bumped the typecheck heap and fixed the flaky telegram test differently, and test:e2e was removed on purpose (the Playwright suite is gone).
Also worth addressing
- Pre-inserted assistant row, crash window: if the process dies between the pre-insert and the first checkpoint, an empty assistant row (
content: '', no toolCalls) stays in the DB and Anthropic rejects every later turn (the guard comment the PR removes describes this exact trap). It needs a boot-recovery sweep for empty assistant rows, or the insert deferred to the first checkpoint. messages.tsmid-stream mount: suppressingstreamingMessagewhen the pre-inserted row is in the page means a client mounting mid-stream never seeds its streaming bubble and sees a frozen partial untilchat:done. Better to return the snapshot anyway and let the client reconcile against the listed row.useAgentshydrate: writingisProcessing: falsefor every agent means a slow/agentsresponse finishing after aqueue:updateclobbers fresher SSE state (the stale-refetch trap from sse.md). The newagent:errorhandler also clears the main-turn spinner on quick-lane errors because it does not checktaskId/sessionIdlike thechat:donehandler does.- Missing locale keys:
tools.status.pending,tools.renderers.editingFileandtools.renderers.writingFileexist in no locale file, so the EnglishdefaultValueleaks into all 10 locales. Please add them toen.jsonand the other locales and runbun scripts/check-locales.ts.
Suggested path
Splitting this would get most of it merged quickly:
- (a) a small PR with the tool-preview normalization, the pending renderer states (with locale keys) and the shell-tools realpath fix, rebased on main: easily mergeable;
- (b) the crash-safe pre-insert/checkpoint work with the two streaming/SSE items above addressed;
- (c) a small patch for the multi-candidate auth and cache paths;
- and for the restart gating and the toolbox semantics, let's agree on the design here first before more code.
Thanks again for the deep work. The direction on tool previews and restart safety is right and we want most of this in.
…e keys Split out of PR #27 as the independently-mergeable UI slice, rebased on main. - Normalize tool-call args to {} before rendering previews so a chat:tool-call-start event (which fires before streamed args arrive) can't crash a preview renderer reading args.title / args.path / args.command etc. Centralized in registerPreviewRenderer + normalizeToolCallArgs, with safe getStringArg/getPathArg accessors in the preview renderers. - FileEdit/FileWrite renderers show explicit pending states while args stream. - Add the three previously-missing i18n keys these states use (tools.status.pending, tools.renderers.editingFile, tools.renderers.writingFile) to en.json and all nine other locales so the English defaultValue no longer leaks into every language. `bun scripts/check-locales.ts` passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(ui): normalize pending tool-call previews + pending renderer states (split 1 of #27)
|
Closing this in favor of the smaller, rebased splits suggested in review:
|
Summary
Validation
Previously passed before this split PR branch was prepared:
Additional lightweight verification during fork PR creation: