0.1.137
Changes
- Single-channel notebook workflow — Removed Chat/Notebook/Auto send targeting. Every chat now owns one frozen notebook context while all user commands and agent summaries remain in the center channel.
- Read-only notebook projection — The right Notebook panel is now a passive SSE-backed record with no Save, Save As, Undo, cell mutation, execution, restart, kernel selection, or context-pill controls.
- Project-bound notebook lifecycle — Chat notebook records continue to persist automatically under
{cwd}/.annodex/notebooks/ with lifecycle metadata. Archiving a chat releases runtime resources but leaves its notebook in place as an orphan project asset.
Fixes
- Deleted notebook resurrection — Externally deleted chat notebook files are reported as
missing and are no longer silently recreated from stale process memory. A new record requires an explicit chat request.
- Draft first-turn MCP targeting — New chats re-sync notebook MCP environment after receiving the real thread id, preventing first-turn tools from writing to the draft notebook namespace.
0.1.136
Fixes
- Memory promotion data race —
markPromoted in memory-runtime.ts now performs read-modify-write atomically inside withFileMutationQueue, preventing concurrent retainMemory calls from silently dropping records.
- Tree builder cycle detection —
buildTreeFromMessageEntries in session-reader.ts now checks the entry parentId chain via isAncestorInEntryChain, catching cycles that isDescendantInTree misses when the parent node's children haven't been attached yet.
Changes
- Port allocation TOCTOU —
findFreePort in codex-server.ts keeps the probe server alive until codex app-server is spawned, then closes the holder via releasePort(). Eliminates the race window where another process could grab the ephemeral port before codex binds.
- Dead code removal — Removed unused
replaceRecords function from memory-runtime.ts (replaced by inlined write in markPromoted).
0.1.133
Changes
- Jupyter UI clean-up — Removed Jupyter-centric UI from
NotebookRuntimePopover (replaced "Jupyter: not connected" with "Engine: Science Kernel"), KernelSelector (deleted Jupyter Server management section ~340 lines), NotebookKernelPicker, NotebookPanel, useAgentSession, and context-pills. All notebook execution uses Science Kernel (python3/Rscript directly); no Jupyter Server required.
- Science Kernel idle timeout configurable —
python-kernel.ts and r-kernel.ts now read notebookIdleTimeoutMs from app settings instead of hardcoding 30 minutes. Default 2 hours. Settings → Kernels → Kernel Lifecycle provides dropdown (30m / 2h / 6h / 24h / 48h / Never).
- Project kernel command resolution — Science Kernel now uses the project-configured conda/venv kernel binary (
resolveEffectiveKernelCommand) instead of always spawning PATH's python3. getKernel() chain accepts optional command parameter; switching project kernel auto-releases old process and spawns new one. Falls back to PATH detection when no project kernel is configured.
Fixes
- Runtime popover empty state — No longer shows "Jupyter server is not running" when kernel processes exist; says "No active kernel processes. Open a notebook and run a cell to start."
- Settings Kernels tab — Jupyter start/stop/scan/attach buttons removed (APIs were deleted in Phase 5). Replaced with Science Kernel configuration and idle timeout dropdown.
- kernelCommands cleanup —
release() and shutdownAll() in both PythonKernelManager and RKernelManager now properly clean up the kernelCommands map.
0.1.132
Changes
- Notebook double-SSE merged —
NotebookInner no longer opens its own /api/science-kernel/events SSE connection; kernel status, kernelStateReason, and executionCount flow via props from NotebookPanel → useAgentNotebook unified SSE.
- Notebook sessionId single source of truth —
NotebookPanel now prefers activeNotebookTarget.sessionId from AppShell's buildActiveNotebookTarget, eliminating duplicate sessionId computation across components.
- Scroll-to-bottom rewrite — staggered re-pin timers (80 / 200 / 450 / 800 / 1500 ms) +
ResizeObserver (3 s deadline) replace the old rAF settle loop; scrollToBottom uses direct el.scrollTop assignment instead of scrollIntoView, bypassing overflow-anchor cross-browser inconsistencies.
- Optimistic session delete — delete fires
onDeleted first (optimistic removal from the sidebar list), then calls the API; on failure onDeleteFailed triggers loadSessionsForCwd to restore the item.
Fixes
- Cell output consistency — local output cache in
NotebookInner is now cleared when server-side outputs differ, preventing stale user-run outputs from overriding agent-updated outputs for the same cell. setOutputs is awaited before onRefreshCells() to avoid a race where the server hasn't persisted yet.
- reloadFromFile concurrent guard — added per-session
reloadInFlight Set in the cells API route to prevent overlapping reloads from mount useEffect, the 2 s poll interval, and SSE notebook_saved events.
- Kernel language-switch mutex — added
withSessionLock per-session promise-chain mutex to lib/science-kernel/manager.ts, serializing getKernel and releaseKernel calls to prevent Python ↔ R fast-switch kernel process leaks.
- MCP env sync race —
syncNotebookMcpEnv is now awaited before the turn's prompt is sent, ensuring ANNODEX_NOTEBOOK_SESSION_ID is injected before the agent's first tool call.
- loadSession deduplication — added
loadSessionInflightRef Map to prevent concurrent duplicate readThread requests for the same sessionId (e.g. initial load + SSE reconnect reconcile).
- Scroll settle initialScrollDoneRef — delayed
initialScrollDoneRef.current = true to the 3 s settle deadline to prevent the agent-end smooth scroll effect from competing with staggered instant pins during session switch.
0.1.131
Changes
- Notebook single data source —
NotebookInner no longer creates a duplicate useAgentNotebook hook; cells and refresh are owned by NotebookPanel and passed as props. Each notebook view now has one SSE connection and one poll loop (was two of each).
- Immediate external notebook reload via SSE — agent-signalled
.ipynb saves (POST /api/notebook/reload) now reach the client through the existing SSE event stream (path-matched to file-mode sessions), triggering reloadFromFile without waiting for the 2s poll interval. Own saves carry a sessionId and are ignored on the client.
Fixes
- Fixed
eventMatchesSession dropping session-less notebook_saved events — the events route now matches by the file path encoded in the session id.
- Fixed missing
cwd in the SSE effect dependency array (useAgentNotebook), eliminating a React hooks warning.
0.1.130
Fixes
- Fixed npm publish failure — reverted
--provenance from the publish workflow (sigstore provenance requires a public repository; v0.1.129 code identical, republishing).
0.1.129
Changes
- Science kernel replaces Thebe — notebook execution now runs on annodex's own persistent Python/R kernel processes (
lib/science-kernel/) with per-session serialization; the thebe-core/thebe-react frontend, Jupyter server management, and the /api/kernel/* proxy routes are removed. New components/notebook/ cell UI edits/executes directly through the cells + science-kernel APIs.
- Notebook file-sync hydration tracker — per-session file mtime tracking distinguishes own writes from external edits: external
.ipynb changes (editor, git, agent file tools) are picked up on next API call, own exports no longer trigger redundant re-imports, and deleted files are recreated.
- Notebook security hardening —
assertNotebookFileAccess + cwd resolution (explicit → draft session → registry). Read APIs without cwd only serve .ipynb (blocks secret exfiltration via context views); write APIs additionally require a scope anchor; context apply enforces write scope; registry openFile/saveFile/export share the same realpath-safe checks.
- Kernel lifecycle — language switches release the previous kernel (no more leaked python processes);
isKernelReady/getKernelStatus report real process state; deleting a notebook cascades to snapshots, kernel leases, and the live kernel.
- Snapshots — dedup consecutive identical snapshots, skip >8MB notebooks, no more snapshots on failed validations, per-notebook purge on delete.
- Draft scratch persistence — draft chats (no thread yet) persist scratch cells to
.annodex/notebooks/scratch-draft-.ipynb and survive server restarts; draft→chat migration writes the chat file before removing the draft file.
- Bounded runtime state — async execute jobs (100 + 10min TTL), reload tokens (200 FIFO + 1h TTL), hydration tracker (500 FIFO).
- Lazy notebook instructions — the ~150-line notebook API block is only injected into chats whose project shows notebook activity.
- Tests — new
tests/notebook-core.test.mjs (session ids, hydration, memory, state, snapshots, registry, security) via npm run test:notebook; shared tests/compile-lib.mjs harness fixes tsc alias/js-sibling compilation for codex-server/rpc-manager/session-reader/codex-session/stream-session suites — full suite is green again (76/76).
Fixes
- Fixed notebook Save / Save As wiping the entire notebook — the client source handle was never wired after the UI rewrite, so saves pushed an empty cell list and overwrote the project
.ipynb. Saving now exports the server-side session (the true source); the cells API also refuses to replace a non-empty notebook with an empty sync unless force: true.
- Fixed file-change reload never firing — reload token lived in the server process while the panel polled a browser-local map; panel now polls
GET /api/notebook/reload.
- Fixed UI cell execution hardcoding Python — the notebook language preference now reaches the execute call.
- Fixed cell reorder dropping outputs/execution counts — new atomic
move cells action replaces delete+add.
- Fixed
execution_count never persisted to cells or exported .ipynb files.
- Fixed memory recall returning results when no query term matched; execution memories are now retained under the real project cwd.
- Fixed notebook session ids not round-tripping paths containing
~.
- Fixed registry saveFile resetting R notebook kernelspec to python3 — existing kernelspec/language_info metadata is preserved on save.
- Fixed cells/registry GET creating sessions and default notebooks as read side effects.
- Fixed chat target block falling back to a shared global
default notebook session.
- Fixed execute route not hydrating sessions after a server restart (runFromIndex saw zero cells).
- Fixed HMR duplicate notebook sidecar subscriptions causing duplicate trajectory/memory writes.
0.1.128
Changes
- Composer memory — new chats inherit the last-used model and thinking level from the previous session (persisted in browser localStorage).
Fixes
- Fixed Save As rejecting paths on symlinked project cwd (e.g.
/Volumes/... vs /work/... mount aliases).
- Fixed notebook Save dialog browse listing no subfolders — API returns
isDir, not kind: directory.
- Fixed user messages showing the raw
[annodex target: notebook]…[/annodex target] block — UI now shows clean prompt text with a to notebook pill.
- Fixed new chat defaulting to notebook send target instead of chat.
- Fixed notebook Save As filename normalization when the input includes a path segment.
0.1.127
Fixes
- Fixed npm publish CI build failure — split client-safe
notebook-scratch-path and extension-ids modules so notebook context pills no longer pull Node fs into the browser bundle.
0.1.126
Changes
- Notebook context layer — agent-view, projection apply, TOC/cell query, dependency analyzer, mutation preview cards in chat, cross-session memory, snapshot/undo, trajectory export;
annodex-notebook-mcp wrapper.
- Scratch & file true-source —
.ipynb on disk is primary store for both modes; runtime JSON disabled; hydrate on API entry; execute/setOutputs sync outputs to file.
kernel_state SSE — idle/busy/dead events from execute + Thebe; UI banners, context pills, and agent prompt injection for error recovery (§7).
- Save / Save As — notebook save flows use cells API +
syncToFile (preserves agent outputs and kernelspec metadata).
Fixes
- Fixed Save As writing Thebe-only sources via raw file PUT — now exports full runtime session to
.ipynb.
- Fixed cells API accepting
filePath outside project cwd — assertNotebookProjectScope on GET/POST.
- Notebook execute server-side
python3 -c fallback remains off by default (ANNODEX_NOTEBOOK_EXECUTE_FALLBACK).
0.1.125
Changes
- Notebook offline view — scratch/file notebook shows agent cells with a Jupyter-offline banner when no server is connected, instead of a full-screen blocker.
Fixes
- Fixed thinking dropdown showing
high (minimal) / high (medium) for DeepSeek — inferred API routing maps no longer override UI labels; only custom thinkingLevelMap in providers.json changes display text.
- Fixed Settings → Kernels tab not scrolling — Jupyter server, memory, and kernel list now scroll together when content exceeds the dialog height.
- Fixed context overflow errors showing raw upstream JSON — readable message with
/compact guidance.
- Fixed codex context budgeting using the largest model window across providers — workspace server now uses the smallest configured
contextWindow so auto-compaction triggers before any model's limit.
0.1.124
Changes
- Composer thinking (v0.1.116 style) — desktop restores separate thinking dropdown; model picker is models-only with clearer selected state and provider grouping.
- DeepSeek thinking levels — infer
thinkingLevelMap from compat/reasoning profile; deepseek-v4-pro caps at high (no xhigh).
Fixes
- Fixed notebook/agent
401 Invalid token on local router for deeprouter and other compat-proxy providers — annodex router now routes them through Responses→Chat compat instead of native /v1/responses.
- Fixed missing API key returning opaque upstream 401 — router now reports which provider needs a key in Settings → Models.
- Fixed codex server reusing stale router after provider API key changes.
- Fixed notebook agent instructions hardcoding
localhost:30121 — use dynamic annodex origin/port.
0.1.123
Fixes
- Fixed annodex startup crash
TypeError: WebSocket.Server is not a constructor — use WebSocketServer from ws v8 ESM exports in Jupyter WebSocket proxy.
0.1.122
Fixes
- Fixed npm publish build failure: split client-safe
jupyter-browser-url from server-only jupyter-upstream so NotebookPanel no longer bundles Node modules.
0.1.121
Changes
- Jupyter browser proxy — notebook thebe connects via same-origin
/api/kernel/jupyter (HTTP + WebSocket) instead of 127.0.0.1:8900, fixing remote/mobile LAN access.
- Custom annodex server —
server/annodex-next-server.mjs wraps Next.js with Jupyter WebSocket upgrade proxy; npm run dev and production annodex use it.
Fixes
- Fixed right-panel notebook Server: not reachable (127.0.0.1:8900) / Failed to fetch when annodex is opened from another device or non-localhost URL.
- Fixed model/thinking display to match v0.1.116 semantics — model name and reasoning level shown separately; custom
thinkingLevelMap labels only when configured.
0.1.120
Changes
- Notebook chat targeting — chat notebook target follows persisted
notebookSelection, independent of which right-panel tab is focused; opening .ipynb registers the file notebook and updates the target.
- Draft notebook migration — scratch/file notebook cells in draft scope migrate to the real thread session on first message (
POST /api/notebook/migrate-draft).
- Notebook runtime UX — top bar Runtime popover merges server status, kernel picker entry, and memory; notebook panel uses a unified kernel picker modal.
- Notebook kernels — auto-pin effective Py/R kernels when selecting notebook send target; notebook language preference per project.
- Mobile composer — model/thinking bottom sheets portal to
document.body; More (⋯) menu splits Model and Thinking entry points.
Fixes
- Fixed thebe-core load failure in notebook panel (
ThebeCoreShim for window.thebeCore.module mismatch).
- Fixed notebook chat target falling back to scratch while the Files tab was focused.
- Fixed mobile model/thinking sheets mispositioned or untappable under sticky
backdrop-filter composer chrome.
- Fixed notebook targeting when Jupyter server is not yet connected (agent can still write cells).
- Removed top-bar Generate UI toggle (generative UI stays on by default).
0.1.119
Changes
- Cursor-style composer — unified
+ menu (plan mode, tools, extensions, slash commands), integrated model/thinking picker, streaming stop button, drag/paste attachments with vision-model guard.
- Chat send target — Send to Chat / Notebook / Auto via
+ menu; segmented control appears when Notebook tab is open; status chip when routing away from Chat.
- Session sidebar — pin chats to a strip above Projects; unread blue dot and running indicator; New Project button in Projects header.
- Notebook memory manager — top-bar Notebook button opens global kernel memory popover (RSS by chat/project, Release, idle timeout); kernel lease tracking for thebe + agent execute APIs.
- Plan mode — plan/code toggle in composer; plan panel integration; can switch back to code while agent is running.
Fixes
- Fixed notebook kernel leases not updating when a draft/unattributed kernel is later claimed by a chat session.
- Fixed plan mode toggle blocked entirely during agent runs (only switching into plan is blocked now).
- Fixed historical pasted images not opening in lightbox; block send when model lacks image input.
0.1.118
Fixes
- Fixed scratch notebook remounting on every agent cell sync — stable key prevents Thebe session/kernel teardown.
- Fixed
findOrphanJupyterPids doing 100 sequential lsof calls; now single lsof with port-range filter.
- Fixed
@types/ws fragility by adding declare module "ws" to types file (prevents breakage on npm install).
0.1.117
Changes
- KernelSelector: three-state server UI — Disconnected / Managed / External mode cards with port + label display, replacing single-status indicator.
- External Jupyter validation — connect flow validates tokens, shows auth-required hints, separates port scan from external probe (
lib/jupyter-external-probe.ts).
- Notebook save — Save / Save As buttons in notebook toolbar; new
NotebookSaveDialog with folder browser, kernel picker, and auto-increment filenames (lib/notebook-ipynb.ts, lib/notebook-save-paths.ts).
- Scratch notebook ↔ agent sync — bidirectional source sync via
useScratchNotebookSync, fingerprint-based dedup to avoid loops (lib/notebook-scratch-sync.ts).
- Project kernel settings — Default Python/R kernel selector per project in Settings → Project, with effective/default/project-selected labels.
replaceNotebookCells API — POST /api/notebook/cells { action: "sync" } for bulk cell replacement.
- Jupyter scan extras —
/api/kernel/scan accepts extraPorts / probeToken for user-specified ports.
Fixes
- Fixed
no-store cache header on /api/files/[...path]?type=list responses.
- Fixed
findOrphanJupyterPids to only scan annodex-managed ports (8900–8999), never touching external Jupyter on other ports.
- Fixed
replaceNotebookCells duplicate function definition causing TS compile failure.
- Fixed all pre-existing TypeScript errors: missing
@types/react / @types/react-dom / @types/ws installs via overrides; added types/missing-modules.d.ts for packages without type definitions.
- Fixed
docx-preview renderAsync call signature (4 args → 3 args).
0.1.116
Changes
- Interactive & Agent Output merged — removed Agent Output tab; agent now edits .ipynb files directly via file tools, thebe reloads on change via POST /api/notebook/reload. Single unified notebook experience.
- Notebook create card — when no .ipynb is selected, panel shows a creation UI with folder browser (navigate subdirs, ../ up, pick name) instead of typing paths.
- External server probe —
/api/kernel/config now probes external Jupyter servers and returns reachable/probeError; NotebookPanel and Settings only render thebe when reachable.
- Server status in Settings — external servers now show "Not reachable" with probe error when port is configured but unreachable (e.g. missing token).
Fixes
- Fixed Settings → Kernels showing "Running" for external servers that were configured but unreachable.
0.1.115
Fixes
- Fixed CI typecheck failure:
ScanResponse to Record cast (added unknown intermediate).
0.1.114
Changes
- Jupyter server management moved to Settings → Kernels — start/stop/scan for Jupyter servers from the Settings dialog. Right-panel notebook no longer shows kernel setup UI; instead shows a guide button when no server is connected.
- Server config persistence — Jupyter server connection (managed or external) saved to
~/.config/annodex/kernel-server.json, survives restarts.
- Port scanning — Settings → Kernels can scan local ports (8888–9000) for running Jupyter servers and connect to them with one click.
- Science kernel → Jupyter registration — selecting a Python/R kernel for a project now auto-registers it as a Jupyter kernel spec (
ipykernel install / IRkernel::installspec), so the notebook server can use the selected environment.
- Notebook execute uses project kernel —
/api/notebook/execute now looks up the project's selected Python/R kernel instead of hardcoding python3. Falls back to default when no project kernel is selected.
- Notebook panel shows active kernel — status bar displays project-selected kernel (e.g.
K: Python 3.10 (conda:bio)).
- Right-panel file tab scoping — notebook/file tabs are filtered when switching projects; tabs from other projects are auto-closed.
Fixes
- Fixed R kernel registration single-quote escaping (was a no-op).
- Fixed external Jupyter servers not being discoverable by the execute API (added
getServerConfig() fallback).
- Removed dead
buildNotebookPrompt function (replaced by inline cwd injection in rpc-manager).
0.1.113
Fixes
- Fixed
TypeError: Failed to fetch when opening chat sessions — the FileExplorer's useEffect had store (entire object, new reference every render) in its dependency array, causing an infinite loop of file-list requests that exhausted browser connections. Changed to store.refresh (stable useCallback reference).
0.1.112
Fixes
- Fixed old chat sessions failing with
TypeError: Failed to fetch after upgrading to v0.1.108 — the auth middleware was blocking localhost API requests (/api/sessions/:id, etc.) when web-auth.json is enabled, but localhost access should never require authentication. Removed isLocalSidecarApiPath restriction; all localhost requests now bypass auth (password is only for remote tunnel access).
0.1.111
Fixes
- Fixed old chat sessions returning empty messages — tree building failure from malformed parent references no longer prevents messages from loading.
buildTreeFromMessageEntries is now wrapped in safeBuildTree try-catch, falling back to empty tree on error.
0.1.110
Fixes
- Fixed old chat sessions showing "Failed to fetch" — old Codex sessions (pre ~2026-05) lack item-level
id fields, causing circular references in the session tree that broke JSON serialization. Synthetic IDs are now generated for items without real IDs, and cycle detection guards the tree builder.
0.1.109
Changes
- Projects tab redesigned — split layout (left project list + right detail panel), drag-to-reorder projects with persistence, "current" badge, hover-to-show-remove.
- Remote tunnel UI — new Settings → Remote tab with start/stop/copy URL controls.
- Auth middleware activated — password auth now enforced for all non-localhost requests (existing proxy.ts promoted to middleware.ts).
- Default sandbox mode — changed to Full access ("danger-full-access"), Safe/Full toggle removed from sidebar.
- Docs updated — file tree features (context menu, shortcuts, search), project tab, auth middleware, tunnel UI documented in both languages.
0.1.108
Changes
- Tunnel simplified — removed JWT/session/token complexity, tunnel is now just a network bridge (start/stop cloudflared). Authentication handled by annodex's existing password system via the activated middleware.
- Auth middleware activated —
proxy.ts renamed to middleware.ts, enabling the existing annodex-auth cookie-based authentication for all external requests.
Fixes
- Fixed JWT double-encoding bug in tunnel token verification.
- Fixed cloudflared
require() usage replaced with ESM import.
- Fixed tunnel stop race condition (state nulled before process kill).
0.1.107
Changes
- Remote access via Cloudflare tunnels —
POST /api/tunnel/start starts a cloudflared quick tunnel exposing the local annodex server. Returns a share URL with an embedded JWT for authenticated access. JWT verification via Next.js middleware (Edge-compatible WebCrypto) protects all routes when a tunnel is active. Includes tunnel status, session management, token revocation, and a dedicated login page.
- Usage docs updated — Remote access (Tunnel) section added to both Chinese and English usage guides with setup instructions, API reference, and security notes.
0.1.106
Changes
- Fuzzy file search API —
GET /api/file-tree/search endpoint with BFS traversal and fuzzy match scoring (exact/prefix/substring/character-by-character).
- Button reorder — Settings and permission toggle buttons swapped in sidebar footer.
0.1.105
Changes
- File tree redesign — in-memory caching with O(1) path lookups, manual virtual scrolling (only renders visible rows), right-click context menu (rename / delete / copy path / reveal), keyboard shortcuts (↑↓→← Enter F2 Delete), dimmed secondary directories (.git / node_modules / etc), and file operations (New File / New Folder / Rename / Delete / Reveal in Finder).
- File-tree API module — new
/api/file-tree/* endpoints (write / mkdir / rename / delete / reveal) with atomic writes (tmp+rename), workspace boundary enforcement, and cross-platform reveal support.
0.1.104
Changes
- Chat-owned notebook registry — notebook state is now scoped to chat threads instead of project-wide
scratch:{cwd}, with active notebook selection, multi-notebook support per chat, and copy-on-fork behavior.
- Agent notebook output panel — Notebook panel adds an Agent Output view that renders cells produced through the notebook API, including stream output, errors, HTML/text, and PNG/JPEG/SVG display data.
- Notebook persistence and export — Annodex scratch/agent notebooks persist runtime cells under
~/.config/annodex/notebooks/runtime-sessions/, registry metadata under ~/.config/annodex/notebooks/index.json, and can be exported to project .ipynb files.
- File-backed
.ipynb bridge — project .ipynb files register as file-backed notebooks, import into runtime cells for agent execution/editing, and can be explicitly saved back to their project path.
- Permission toggle wiring — the left-bottom Safe/Full permission toggle now controls new sessions, existing sessions, and resumed sessions via
defaultSandboxMode.
Fixes
- Notebook execution robustness — notebook execution supports async jobs with polling, longer kernel timeouts, and
sourceFile cell creation/update to avoid fragile shell JSON escaping.
- Notebook ownership isolation — different chat sessions in the same project no longer share or overwrite each other's notebook cells.
- Project asset boundary —
.ipynb files are never stored under ~/.config/annodex; that directory only contains Annodex registry metadata and runtime cache.
0.1.103
Fixes
- 自动清理僵尸 Jupyter 进程 —
startJupyterServer() 启动前用 lsof 扫描并 kill 所有孤儿 jupyter-server 进程,防止 annodex 重启后端口被旧进程占用累积
- Notebook 面板错误可见性 — 顶部状态栏直接显示 kernel 错误信息(不再仅藏于初始设置面板中),新增 "↻ Retry" 按钮用于重新检查状态
- 删除 ThebeNotebookInner 死代码 — 移除
dangerouslySetInnerHTML 注入的 标签(React 中不执行),thebe-core 已自行处理 window.thebeCore.module 包装
- NotebookStatusBar 错误信息增强 — 新增
loader.error 显示,错误文本更宽、字号更大、可 hover 查看全文
0.1.102
Changes
- Notebook target routing — ChatInput 新增 Chat/Notebook/Auto 三态目标切换按钮,消息按目标路由:
-
chat: 纯对话,不动 notebook
-
notebook: 消息注入
[annodex target: notebook] 指令,驱动 agent 通过 notebook API 操作 cell
-
auto: agent 自行判断是否需要操作 notebook
- Notebook tab 常驻右侧面板 — 右侧面板新增独立 Notebook tab,支持 scratch notebook 和
.ipynb 文件两种模式,通过 dropdown 切换项目目录及其子目录下的所有 notebook 文件
- 新建按钮文案 — 左侧 channel 右上角
+New 改为 +Chat
Fixes
- 修复 thebe-core.min.js 被认证中间件拦截 —
proxy.ts 添加 STATIC_ASSET_RE 正则,放行 public/ 目录下静态资源(.js/.css/.woff2/.wasm 等),notebook 引擎不再因 307 重定向到 /login 而加载失败
0.1.101
Fixes
- Fix CI: sync package-lock.json after version bump —
npm ci failed in both
release-preflight and npm-publish workflows because
package-lock.json version
was not updated to match
package.json after the 0.1.100 release.
0.1.100
Changes
- annodex science — interactive notebook — new notebook system with Jupyter kernel
integration via thebe-core and jupyter_client bridge:
-
components/NotebookPanel.tsx +
ThebeNotebookInner.tsx — thebe-based interactive
notebook with cell editing, keyboard navigation (↑↓/Enter/Esc/Shift+Enter), and
CodeMirror-based code editor (
components/CellEditor.tsx,
NotebookCell.tsx)
-
components/KernelSelector.tsx — Python/R kernel discovery (conda envs, system
Python) with project-level default selection, integrated into Settings > Kernels
-
lib/jupyter-manager.ts — singleton Jupyter server lifecycle (start/stop/status)
with automatic port assignment and kernel listing
-
lib/science-kernels.ts — scans conda environments and system Python/R for
ipykernel/IRkernel availability, powers the kernel discovery UI
-
lib/notebook-state.ts — shared in-memory cell state (globalThis) with CRUD API
-
lib/notebook-codex-bridge.ts — notebook API instructions injected into Codex
agent system prompt so the agent can read/write/execute cells via curl
-
bin/annodex-kernel-exec.py — Python bridge that uses jupyter_client to execute
code on a shared Jupyter kernel, returning rich mime outputs (HTML tables, PNG
images) instead of plain text
- API routes:
POST /api/kernel/start|stop,
GET /api/kernel/status,
POST /api/notebook/cells,
POST /api/notebook/execute,
POST /api/science/kernels (scan/select/setDefault/add/delete)
- Right-sidebar TabBar integration:
.ipynb files open as notebook tabs, new
"+Notebook" button next to "+Chat" in the session sidebar project headers
- Spike page at
/science/spike for standalone thebe verification
Fixes
- Login page password-manager autofill — password input switched from React
controlled (
value={}) to uncontrolled (
defaultValue + ref) so password
managers (Chrome/1Password/Bitwarden) can autofill without leaving the Sign In
button greyed out.
- Legacy cookie cleanup —
getClearLegacyCookieHeader() and
getClearPidexCookieHeader() now use hardcoded cookie names (not port-scoped)
to match the middleware's legacy cookie read paths, preventing stale
annovibe/pidex cookies from persisting after logout.
0.1.99
Changes
- Cross-platform process manager — new
lib/process-manager.ts module unifies
Codex app-server subprocess lifecycle across Linux, macOS, and Windows:
- POSIX: spawn with independent process group,
kill(-pid) to clean the tree
- Windows:
taskkill /T to recursively terminate
- All platforms: SIGTERM → grace period → SIGKILL with exit-event waiting
- Zombie process detection on Linux —
isZombieProcess() reads /proc//status
and filters
State: Z from
isPidAlive(), preventing zombie PIDs from being
mistakenly treated as live.
- Escape hatch —
ANNODEX_CODEX_DETACHED=0 disables detached mode on POSIX,
useful if macOS Gatekeeper compatibility issues arise.
Fixes
- Codex app-server shutdown in
stopInstance() now waits for the process to exit
instead of fire-and-forget, eliminating zombie accumulation after idle cleanup
or dev reloads.
- Windows
taskkill subprocesses are .unref()'d so a hung taskkill cannot
prevent the annodex process from exiting.
0.1.98
Fixes
- Session rename robustness — five improvements: (1) wasted wrapper cleaned up after connection errors so follow-up operations don't fail on a dead connection; (2) empty name now rejected with 400 instead of sent to codex; (3)
CodexSessionWrapper.send("rename") now syncs to session-runtime.json so direct calls (not through HTTP PATCH) also persist; (4) AppShell and SessionSidebar now share a single renameSession() helper in agent-client.ts eliminating duplicated fetch/error-handling logic.
0.1.97
Fixes
- Session rename process cleanup — session rename now first uses the live session connection and only falls back to a managed codex server when needed, avoiding unnecessary codex app-server/router process churn. Codex app-server shutdown now includes a SIGKILL fallback for detached Linux processes, reducing orphaned background processes after idle cleanup or dev reloads.
0.1.96
Fixes
- Session rename not working — three root causes fixed: (1) frontend
commitRename didn't check HTTP response status, silently proceeding after server errors; (2) session name had no local persistence, so it was lost when thread/list didn't return the name field or when falling back to local cache; (3) top bar and sidebar rename were completely independent — renaming from the sidebar never updated the top bar's selectedSession. Fixes: commitRename now checks res.ok and shows error toasts; PATCH endpoint persists name to session-runtime.json via upsertSessionRuntime; sessionInfoFromThreadSummary and summarizeCodexSessionFile recover name from runtime store; new onSessionRenamed callback syncs sidebar rename to AppShell's top bar.
0.1.95
Fixes
- Stop button triggers HTTP 500 during streaming — clicking Stop while the AI was responding could cause a 500 error due to a race condition between SSE cleanup and the abort POST handler. The abort case in
CodexSessionWrapper.send() and the POST /api/agent/[id] route now both wrap their logic in try/catch, ensuring any exception is safely caught and a clean { running: false } response is always returned.
- "Stream idle timeout" after AI finishes — when the SSE connection closed after turn completion and the client auto-reconnected, the new SSE stream would receive no events (turn already done), causing the idle watchdog to fire after 3 minutes. The SSE
events/route.ts now checks session.isBusy() after subscribing; if the session has no active turn, it immediately sends agent_end so the watchdog never starts.
0.1.93
Fixes
- Stuck chat after agent completion — when the SSE
agent_end event was missed (due to network disconnect or timing), the UI would stay stuck showing "Stop" button and appear to be streaming, even though the agent had actually finished. Root cause: the reconcileSession polling loop fetched the session state every 10s but never updated agentRunning based on the server response. Now reconcileSession checks agentState.running after each reconcile and self-heals the UI if the agent has actually stopped, preventing the stuck state without requiring a page refresh.
- Reduce left sidebar polling interval — changed from 10 seconds to 1.5 minutes (90s) to reduce unnecessary network traffic.
0.1.92
Changes
- Rename right-panel tab "Tools" → "Status" — the right-panel tab previously labeled "Tools" primarily shows agent runtime status (phase, uptime, active tools, model info) and working memory, not tool presets. The rename aligns the tab label with its actual content. A new pulse/activity SVG icon is used for the Status tab.
Fixes
- Defensive error handling in runtime status —
getRuntimeStatus() now wraps each session's isAlive() and getRuntimeStatus() calls in try/catch blocks. Previously, a partially destroyed session wrapper could cause the entire status query to throw, resulting in an empty Tools panel.
- Runtime API route hardening —
GET /api/agent/runtime now catches errors from getRuntimeStatus() and getMemoryStatus() independently, falling back to an empty status instead of returning a 500 error. This prevents transient state issues from breaking the frontend Status panel.
0.1.91
Fixes
- Sidebar refresh delay — new chat sessions now appear in the sidebar within seconds. Two changes: (1)
AppShell.handleSessionCreated dispatches a session-created DOM event, and (2) SessionSidebar listens for that event and polls every 10s as a fallback (pattern adopted from CodePilot). Previously the sidebar relied solely on refreshKey prop propagation, which could lag behind the Codex app-server thread index.
- Scroll-to-bottom on session open (v2) — the settle loop now uses a
lastSettledSessionIdRef to reliably detect session switches, preventing the settle from being skipped when messages arrive in batches across renders. Also aborts the animation if the session changes mid-settle.
0.1.90