Start stable desktop update downloads in the background during automatic checks, then prompt only after the update is ready to install.
Keep manual update checks interactive so users still confirm the download after explicitly checking.
Return a recorded SOCKS proxy before a fallback DIRECT rule so local model downloads fail explicitly instead of silently bypassing the configured system proxy.
Make desktop proxy saves await Electron session proxy application before model download proxy resolution.
Resolve HTTP, HTTPS, and SOCKS system proxy rules for semantic index model downloads while preserving DIRECT precedence.
Combine the PR review fixes for push import validation, deduplication, system sender handling, and pull import lock scoping into one reviewable change.
- Change default port from 5200 to 3110 in sync config-manager, Vue store,
and settings UI to match CLI DEFAULT_API_PORT
- Desktop API server now tries up to 10 consecutive ports when preferred
port is occupied (e.g. CLI already running); reports actual bound port
- Scope Desktop import route lock to session (Set<string>) matching the
push-importer fix
- Docs: remove unimplemented JSONL/X-Dry-Run claims, fix port references,
replace platform-specific examples with generic ones
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Session index is now built inside the shared incremental-importer, so the
explicit post-import worker.generateIncrementalSessions(sessionId) calls in
the Desktop layer were no-ops. Remove all four call sites.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add archive reader, Google Chat resolver and source manager in node-runtime.
Expose prepared archive sources via CLI HTTP route and Electron IPC.
Add frontend service adapters and an import selection flow with i18n support
for all four locales. Fix rescanning on repeated archive imports.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Front-end error reporter was posting to /_web/_web/logs/report (double
base URL prefix); fixed to /logs/report
- uncaughtException/unhandledRejection handlers in CLI and Electron did not
exit after logging, overriding Node's default crash behavior; added
process.exit(1)
- NodePathProvider constructor in run() and chatlab status triggered
migrateFromElectronIfNeeded() as a side effect; added getSystemLogsDir()
to get the system logs path without resolving user data
- formatData() was called outside write()'s try/catch, so errors with
circular cause objects could escape appLogger.error(); moved inside
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build a shared appLogger (node-runtime) that all three runtimes write to a
single rolling logs/app.log (10 MB → rename to app.old.log). Replaces the
four independent hand-written loggers (app.log/api.log Electron wrappers)
with a unified entry point while leaving AiLogger/perf-logger intact.
Key additions:
- packages/node-runtime/src/logging/app-logger.ts: initAppLogger/appLogger
singleton, INFO threshold by default (CHATLAB_LOG_LEVEL to override),
atomic rename rotation, Error data auto-extracts message+stack
- Three-runtime init: Electron main, CLI Web (http/index.ts), CLI (run())
- Global crash capture: uncaughtException + unhandledRejection on all three
Node runtimes now land in app.log scope 'crash'
- Fastify setErrorHandler fallback logs scope 'http' on CLI Web and Electron
internal server for unexpected 5xx errors
- Frontend: window.onerror + unhandledrejection + Vue errorHandler feed into
POST /_web/logs/report (scope 'web') with dedup+throttle
- AGENTS.md: logging rules section requiring key-path logs on new/changed features
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Extract shared AnalyticsService to packages/node-runtime using direct
Aptabase HTTP API (removes @aptabase/electron dependency)
- Add POST /_web/telemetry/track route for generic event reporting
- Desktop: migrate analytics.json from userData to systemDir (~/.chatlab/),
trigger daily active from renderer via new IPC so user-selected locale is used
- CLI: inject APTABASE_APP_KEY at build time, create AnalyticsService on
server start, report app_active with platform: cli-web
- Both platforms report user-selected locale via platform service abstraction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When deleteConfig was called, the auth profile written to
auth-profiles.json during addConfig was never cleaned up, leaving
orphaned credentials on disk indefinitely.
Add onApiKeyDeleted callback to LLMConfigStoreDeps and call it in
deleteConfig with the removed config so callers can clean up the
corresponding auth profile. Wire up deleteAuthProfile in both the
CLI HTTP server and the Desktop internal API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete NotificationBus interface (no implementations, no callers)
- Delete useAsyncData/useMultipleAsyncData composables (zero import sites)
- Inline CHART_CAPABILITY_SKILL_ID into tool-catalog.ts (was a single-constant file)
- Inline AsyncSqlExecutor into message-query-functions.ts (was a single-interface file)
- Rename tools TimeFilter → ToolTimeRange to eliminate name collision with shared-types
- Shrink useToast wrapper: two interfaces → one type, 40 lines → 17 lines
- Simplify deepMerge: remove recursion, config is at most 1 level deep
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bring the Electron desktop client to parity with CLI web for semantic
index, and package the local embedding runtime correctly.
- Inject semanticIndexService into the desktop AI tool debug executor so
manual tool runs reach semantic search tools, matching the Agent stream.
Extract a platform-agnostic tool-executor-core with unit tests.
- Persist the API key by reference in the degraded semantic-index config
route (vector service unavailable) so API mode keys are not dropped;
make auth-profile read/write injectable and add route + unit regression
tests that never touch the real ~/.chatlab.
- Package desktop local embedding deps: declare @huggingface/transformers,
asarUnpack onnxruntime-node / @img native libs, and trim onnxruntime-node
binaries to the build target platform/arch to avoid shipping ~175M of
unrelated Linux/Windows binaries.
Co-authored-by: Cursor <cursoragent@cursor.com>
sqlite-vec loads its native .dylib/.dll/.so via require.resolve(), which
in a packaged Electron app resolves to a path inside app.asar where native
extensions cannot be loaded. Adds sqlite-vec* to asarUnpack so the extension
lands in app.asar.unpacked and require.resolve() returns the correct path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add an "evidence" planner intent and tiered retrieval guidance so
fact/occurrence/count questions are routed to retrieve_chat_evidence
instead of a single low-level search path.
- planner: new evidence intent + prompt strategy suggesting only
retrieve_chat_evidence for that step
- semantic-search guidance: three-tier tool selection (evidence > semantic > keyword)
- expose retrieve_chat_evidence as an always-on Agent tool (desktop special
append; CLI via AGENT_TOOL_REGISTRY core), semantic tool stays dynamic
- export evidence tool + payload types from @openchatlab/tools
- TDD: planner evidence-intent test
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce a high-level evidence retrieval tool for fact/occurrence/count
questions. It resolves auto mode, runs semantic + keyword paths, de-identifies
keyword snippets via an injected desensitizeMessages callback, applies a
tool-layer millisecond time-range fallback (keyword path can't rely on the CLI
provider's timeFilter), and merges/dedupes candidates into conservative groups.
- Add ChatEvidencePayload / group / source types and EvidenceTimeRangeMs to tools
- Register tool in AGENT_TOOL_REGISTRY only (Agent-only, excluded from MCP)
- Inject desensitizeMessages (preprocessMessages) in desktop + CLI adapters
- TDD: tool + registry unit tests
Co-authored-by: Cursor <cursoragent@cursor.com>
Add the missing translations for the v8 database migration across the
desktop locales and cover them with a regression assertion.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add shared /_web/ai/semantic-index HTTP routes and wire the service into
CLI web and Electron internal API. Introduce the semantic_search_current_chat
agent tool (AGENT-only, not MCP) with desensitized output and a narrowed
service interface, forward the semantic-search context through the CLI and
Desktop tool adapters, and integrate on-demand semantic search into the
agent pipeline with guidance and a max-result-token evidence budget.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the deprecated always-on RAG system and introduce the new
semantic-index core: parent/child chunker with version/hash derivation,
embedding providers (local + OpenAI-compatible) and profiles, sqlite-vec
vector store, dense+FTS+RRF hybrid retrieval, evidence assembly, serial
warmup job queue and single-session runner, session business-state store,
and the SemanticIndexService that ties them together. Add an independent
config store and a dedicated vector directory via the path providers.
Co-authored-by: Cursor <cursoragent@cursor.com>
- capture worker reference in sendToWorkerWithProgress to match
sendToWorker and avoid stale-closure risk on worker restart
- replace `as any` casts with typed SupportedLocale / BatchSegmentOptions
assertions in debug-executor
- destructure params.params as toolParams to remove unused testId binding
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The desktop worker kept a second analytics result cache in the same
cacheDir/query directory but invalidated it with a fragile scheme:
app-version .cache_version file, a dev-startup wipe, and explicit
invalidateAnalysisCache() calls after import. Replace it with the shared
getOrComputeAnalysisCache, fingerprinting entries by product version plus
the session DB file state, so the worker (still used by AI tools and the
desktop public REST API) and the shared HTTP routes share one cache and
one invalidation model. Fold the product version into the HTTP-route
fingerprint too, preserving the cross-release invalidation that
.cache_version used to provide, and drop the now-dead invalidation code.
Co-authored-by: Cursor <cursoragent@cursor.com>
Analysis pages (private/group chat) are lazy-loaded routes that pull in
heavy deps (echarts, markdown-it, snapdom, vue-virtual, etc.) which Vite's
cold-start scan does not discover. The first navigation triggered an
in-flight dependency re-optimization, invalidating already-loaded chunks
and failing with 504 (Outdated Optimize Dep) on the dynamically imported
page module. This surfaced after a fresh pnpm install wiped the warm
node_modules/.vite cache.
Add optimizeDeps.include so the initial optimize pass already contains
these deps, preventing mid-session re-optimization and the 504.
Co-authored-by: Cursor <cursoragent@cursor.com>
The /_web/sessions route never called getAIChatCountsBySession() to
enrich session DTOs, leaving aiConversationCount always 0 in the
data management UI. Use the existing enrichSession callback and
AIChatManager to fill real counts for both list and detail endpoints.
Co-authored-by: Cursor <cursoragent@cursor.com>
PullEngine gains an onSessionImported hook (hook errors never fail the
pull), wired in both the CLI server and Electron main to silently fill
session owner from the stored platform profile. The chatlab import CLI
command does the same after a successful import.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Overview cache had no self-invalidation: once written it would return
stale lastMessageTs forever if the postImportHook failed silently.
Analysis query cache (17 chart/stats queries) was never cleared on
import, so charts showed stale data until the user triggered a manual
invalidate.
Add MAX(message.id) fingerprint to OverviewCache and introduce
getValidatedOverviewCache(), which recomputes automatically when new
messages are inserted. Update resolveOverview() in the Electron worker
to use this instead of bare getCache().
In both postImportHooks (incrementalImport, streamImport) also call
deleteSessionCache against the query cache directory so chart data is
fresh after every import.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Include assistant messages with tool content blocks in getHistoryForAgent
even when text content is empty, so multi-turn tool results are not lost
- Append Date.now() timestamp to export filenames to prevent silent overwrites
- Pass 600s timeout to exportFilterResultToFile worker call to match the
actual upper bound of large-session exports
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend TokenUsage types across the full data pipeline to include
cacheReadTokens and cacheWriteTokens. The ChatStatusBar tooltip now
shows cache hit information when available. This is a generic
implementation that works with any API provider reporting cache metrics,
not limited to DeepSeek.
Co-authored-by: Cursor <cursoragent@cursor.com>
In explicit chart auto mode, the filter at agent/index.ts removed
render_chart whenever the user message lacked chart keywords. This
caused failures when a user manually selected the built-in chart skill
with a message like "analyze message trends" — the skill prompt
instructed the AI to produce charts but the tool was unavailable.
Add an isExplicitChartSkill guard so the filter is skipped when
skillCtx.skillDef.id === CHART_CAPABILITY_SKILL_ID.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- agent-stream-runner: add fallback allowedBuiltinTools in explicit chart
auto-skill path so unrestricted assistants still load analysis tools when
skill menu advertises skills that require them
- aiChat: guard updatePlanBlockStatus('done') with !hasStreamError in both
SSE and edit-stream handlers so failed plans stay visibly failed instead
of being overwritten by the terminal done event
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>