Commit Graph
74 Commits
Author SHA1 Message Date
CEQ151andClaude Opus 4.8 185e88ba3e fix(import): refresh sidebar message count after incremental import
After incremental import via Electron IPC, the sidebar session list
showed stale message counts. Three contributing gaps:

1. The chat:incrementalImport IPC handler did not notify the renderer
   to refresh the session list (unlike the API route which calls
   notifySessionListChanged). Added win.webContents.send('api:importCompleted')
   to trigger the Sidebar's existing onImportCompleted listener.

2. The postImportHook in worker adapters was async (due to dynamic
   import()) but the caller did not await it, causing a race condition
   where loadSessions() could read stale overview cache before
   computeAndSetOverviewCache() finished. Converted to static import
   making the hook synchronous, and updated the type to void | Promise<void>
   with await at call sites in both incremental-importer and
   streaming-importer.

3. The @imported handlers on group-chat and private-chat pages only
   refreshed local analysis data without calling sessionStore.loadSessions().
   Added the call so the sidebar updates immediately on the client side.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 10:20:28 +08:00
digua 6e016837bc fix(data): harden directory and database migrations 2026-06-03 00:46:34 +08:00
digua 42837278fa fix(data): migrate legacy chat database columns before reads 2026-06-03 00:46:34 +08:00
digua e68ce77266 feat(data): support CLI web data directory migration 2026-06-03 00:46:34 +08:00
diguaandClaude Opus 4.8 2f8591fb8c perf(build): minify main process and lazy-load tiktoken rank table
Enable esbuild minification for main/preload (was renderer-only by default),
reducing main process bundle by ~55%. Extract cl100k_base BPE rank table out
of the synchronous startup path via dynamic import — it now lands in its own
chunk and is loaded on first agent run instead of at app startup.

Also fix Windows CI step to use PowerShell syntax for version injection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 00:46:34 +08:00
diguaandCursor ae90db63a5 feat(merge): migrate merge routes from IPC to shared HTTP package
Unify the merge workflow (parse/conflicts/execute/clear/export-for-merge)
across CLI, Electron, and web-serve into a single set of shared routes in
@openchatlab/http-routes.

Key changes:
- Move MergeSessionCache from CLI to node-runtime shared package
- Add dual-mode parse route (multipart upload for web, JSON filePath for Electron)
- Integrate merge routes into Electron internal API server with @fastify/multipart
- Create installMergeShims() with filePath-to-handle mapping for frontend
- Remove Electron merge IPC handlers, merger module, and preload bridges (~790 lines deleted)
- Address CodeX review: CHAT_DB_TABLES in openDatabase, no chatApi patching,
  outputName sanitization, resp.ok checks, @fastify/multipart in desktop deps

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandCursor 3ab162162b feat(ai): migrate AI CRUD routes to shared package and establish frontend service layer
Extract LLM config, assistant, skill, conversation and summary CRUD
routes from CLI-specific ai.ts into @openchatlab/http-routes, enabling
Electron Internal Server to serve AI endpoints via shared routes.

Frontend service layer:
- Create src/services/{llm,assistant,skill}/ with typed adapters
- Migrate all window.llmApi/assistantApi/skillApi calls to service layer
- Clean up Electron preload: remove CRUD bridges, keep only streaming IPC

Shared AI routes (packages/http-routes):
- ai-llm: config CRUD, provider registry, model catalog, custom store
- ai-assistants: CRUD, import/reimport, tool catalog
- ai-skills: CRUD, import/reimport, builtin catalog
- ai-conversations: conversation/message/debug CRUD
- ai-summaries: summary generation with LLM config injection
- Add requireAi fail-fast option to registerSharedRoutes

Backend improvements:
- Extract CustomProviderStore/CustomModelStore to node-runtime
- Fix authProfile persistence (onApiKeyCreated returns profileName)
- Reuse AI manager singletons in Electron (avoid dual instances)
- Prevent plaintext API key leakage in addConfig response
- Add authProfile regression tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:41:21 +08:00
diguaandClaude Sonnet 4.6 0a916e4b17 fix(types): use AIMessageRole type for message role params & strengthen conversation test assertion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:56:08 +08:00
diguaandClaude Sonnet 4.6 334544880f fix(ai): enable thinking for effort-based models when 'auto' is selected
When the user selects 'auto' thinking level for an effort-based reasoning
model (Kimi, Doubao) that has thinkingLevelMap but no thinkingFormat,
the previous code fell through to `return undefined`, causing pi-agent-core
to treat it as 'off' and send reasoning_effort:'none' to the API —
silently disabling thinking.

pi-ai's clampThinkingLevel only covers EXTENDED_THINKING_LEVELS (no 'auto'),
so 'auto' cannot be forwarded verbatim. Return 'high' instead, matching
the behavior for thinkingFormat models, to at least enable reasoning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandClaude Sonnet 4.6 7558eed5a5 fix(ai): fall back to heuristic for non-builtin custom models in inferReasoning
Custom models auto-saved by ensureCustomProvidersAndModels carry only
capabilities:['chat'], so inferReasoning was returning reasoning=false
even for models like qwen3:8b whose names match the reasoning heuristic.
The UI still showed thinking levels via getSupportedThinkingLevels, but
selections were silently ignored by the backend.

Fix: for non-builtin (builtin=false) model definitions, also apply the
name/provider heuristic as a fallback alongside the capabilities check.
Builtin catalog models remain authoritative.

Adds a regression test covering the exact findModelFn shape produced by
ensureCustomProvidersAndModels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 9bc0c4279d refactor(ui): simplify model button and optimize session index loading
- StatusBar model button: show model name instead of provider, click opens
  settings directly (scrolls to default model section), remove dropdown
- SessionIndexSection: replace N serial pluginQuery calls with single batch
  API (GET /_web/sessions/index-stats), add IntersectionObserver lazy loading
- Full-stack implementation: CLI route, Electron IPC/Worker, frontend adapters

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandCursor 783d61f742 feat(ai): upgrade thinking level control with default/auto options and broader model coverage
- Add 'default' option (no reasoning params sent, model uses native behavior)
- Add 'auto' option for models that natively support it (deepseek_hybrid, kimi, doubao)
- Expand model recognition with regex coverage for 15+ model families
- Add Gemini 2.5+ thinking level support via native Google provider
- Simplify deepseek_hybrid options to ['default', 'off', 'auto'] aligned with Cherry Studio
- Use primary theme color for thinking selector instead of hardcoded blue
- Update docs with thinking control architecture section

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-31 10:28:29 +08:00
diguaandClaude Opus 4.8 a31c672474 feat(ai): add per-model thinking level selector in chat status bar
Adds a lightbulb button next to the model switcher in ChatStatusBar
that lets users choose the thinking intensity for each reasoning model,
with the choice remembered per model slot (configId:modelId).

Key changes:
- packages/core/src/ai/thinking.ts (new): per-model-type thinking level
  table inspired by cherry-studio's MODEL_SUPPORTED_REASONING_EFFORT.
  Covers Qwen/GLM (on/off), DeepSeek V4 (high/max), o-series
  (low/medium/high), gpt-5.x (minimal–xhigh), Kimi/Doubao/Grok and a
  default bucket. Exports getSupportedThinkingLevels, isReasoningModel,
  getThinkingCompat.
- packages/node-runtime/src/ai/llm-builder.ts: inferReasoning now calls
  getThinkingCompat() which sets compat.supportsReasoningEffort and
  compat.thinkingLevelMap so pi-ai can inject the correct request param
  (reasoning_effort for OpenAI/DeepSeek, enable_thinking for Qwen/GLM).
- packages/node-runtime/src/ai/agent/types.ts + core.ts: AgentCoreOptions
  gains an optional thinkingLevel; core.ts:93 uses clampThinkingLevel()
  (from pi-ai) to honour it safely.
- Full transparent pass-through: desktop Agent → IPC handler → preload
  → agentApi.runStream; CLI HTTP route → runServerAgent → runAgentCore.
- src/stores/prompt.ts: thinkingLevels Record<configId:modelId,
  ThinkingLevel> persisted in backendPersist; getThinkingLevel/
  setThinkingLevel helpers.
- src/stores/aiChat.ts: reads current model slot and passes remembered
  level to both sendMessage and editCurrentRoundOnly runStream calls.
- ChatStatusBar.vue: UPopover thinking selector appears only for
  reasoning models, shows only the levels that model supports, highlights
  current choice, hides for non-reasoning models.
- 46 tests passing (26 new in thinking.test.ts + 20 in llm-builder).

Scope: openai-completions path only (Qwen, DeepSeek, OpenAI, xAI, Kimi,
Doubao, SiliconFlow, OpenRouter…). Anthropic/Gemini native thinking is
out of scope for this version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandClaude Opus 4.8 1716cf392f refactor(ai): replace manual reasoning switches with auto-inference
Remove the "Reasoning Model" and "Disable Thinking Mode" toggles from
the model config dialog. These switches were injecting `enable_thinking`
(a Qwen/DashScope-specific request parameter) into all providers,
causing 400 errors on OpenAI, Anthropic, Gemini, and other official
services.

Replace with automatic inference in buildPiModel:
- reasoning: true when the model's catalog capabilities include
  'reasoning'; falls back to a model-name heuristic for unlisted
  custom/self-hosted models (qwen3, qwq, deepseek-r, o1/o3, etc.).
- compat.thinkingFormat 'qwen': only set when reasoning is true AND
  the model is from the qwen provider or the model id contains
  "qwen"/"qwq". All other providers get compat: undefined and will
  never receive enable_thinking.

This means official reasoning models (o3, deepseek-reasoner, etc.) now
automatically get thinkingLevel:'medium', and self-hosted Qwen3
models continue to work as before — without any manual toggle.

Behavior change: models with 'reasoning' in their catalog capabilities
now default to thinkingLevel:'medium' (previously always 'off' unless
the manual switch was enabled).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:28:29 +08:00
diguaandCursor b3c2b20a9f fix(ai): make message editing safe against data loss and stale state
- insertMessageAfter: update active_message_id when appending to tail
  so the new reply is on the active path after reload
- editAndOverwriteAll: add hasConfig + abort checks before
  deleteMessagesFrom to prevent data loss when LLM is unconfigured or
  a concurrent request starts
- editCurrentRoundOnly: defer all DB mutations until after stream
  completes; on abort/error only in-memory state is restored
- sync in-memory parentId after relinking so follow-up edits send the
  correct historyLeafMessageId

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
digua e78c8f9368 feat(ai): add fork conversation UI button on AI replies 2026-05-30 14:19:42 +08:00
diguaandCursor 6224ca996e refactor(ai): replace branching with edit-and-regenerate model
Remove the message branching/tree system in favor of a simpler editing model:
- Default: edit a message and only regenerate the current round's AI response
- Optional: overwrite all subsequent messages when editing

Key changes:
- Backend: add updateMessageContent, deleteAndRelinkMessage, insertMessageAfter,
  deleteMessagesFrom, forkConversation; remove createMessageBranch, switchMessageBranch
- Platform layer: add IPC/HTTP handlers for new methods across Electron and CLI
- Frontend store: refactor editMessageAndRegenerate with two modes
- UI: replace branch navigation with "overwrite subsequent" checkbox,
  auto-resizing edit textarea
- Fix insertMessageAfter missing debug_context from pendingDebugContextMap
- Update tests to cover new editing methods

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 14:19:42 +08:00
CEQ151 d3c62c4f9d feat(ai): support editable message branches 2026-05-30 14:19:42 +08:00
diguaandCursor 88ab0ae172 fix(ai): correct apiKeySet detection and prevent stale key reuse
- Fix apiKeySet reporting false positives for local no-key configs by
  resolving the actual key via resolveApiKey and excluding placeholders
- Prevent editing a config from reusing an incompatible API key when
  provider or connection mode has changed
- Pass summary strategy to single-session generation for consistency

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor 6727ff609c feat(ai): add summary strategy with brief and standard detail levels
Support two summary strategies (brief/standard) for AI-generated session
summaries. Users can choose their preferred detail level in Settings > AI >
Session Index. Standard (default) produces richer summaries covering people,
events, and key details.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor eaff16d555 fix(cli): wire up batch summary generation in CLI Web to fix page freeze
- Implement generateSummary/checkCanGenerateSummary in FetchSessionIndexAdapter
  via existing HTTP endpoints instead of stubs that returned instantly
- Add checkCanGenerate service function in summary-service.ts
- Add POST /_web/sessions/:id/summaries/check-can-generate route

The page froze because stub methods returned synchronously, causing a tight
loop of hundreds of Vue reactive updates without any network delay.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:47:27 +08:00
diguaandCursor 6c3d36e7df feat(ai): upgrade pi-ai from @mariozechner 0.54 to @earendil-works 0.74
- Replace @mariozechner/pi-ai and pi-agent-core with @earendil-works scope
- Adapt to AgentTool.execute() params type change (Record → unknown)
- Migrate Agent constructor to use initialState for systemPrompt/tools/messages
- Update onPayload callback signature to include model parameter
- Filter finalMessages with isPiMessage() for new AgentMessage union type
- Use state.errorMessage instead of deprecated state.error

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 23:19:47 +08:00
diguaandCursor 0ba9ae04a6 chore: migrate workspace packages to ESM
- Add "type": "module" to all workspace package.json files
- Replace __dirname with import.meta.url-based resolveCliPath() helper
- Convert stream-json/stream-chain CJS named imports to default + destructure
  for ESM compatibility
- Use createRequire() for @node-rs/jieba native module loading in ESM context

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 23:19:47 +08:00
digua a5bbff34e4 feat(sync): use incremental session index after pull sync
After pull-sync imports new messages, generate session index incrementally
instead of full regeneration. This preserves existing sessions and their
summaries, only processing newly imported (unindexed) messages.

Adds generateIncremental method across the full stack:
- core: already had generateIncrementalSessionIndex
- node-runtime: expose generateIncrementalIndex
- CLI: add POST /_web/sessions/:id/generate-incremental-index route
- Electron: add session:generateIncremental IPC handler
- Frontend: add generateIncremental to SessionIndexAdapter interface
2026-05-23 16:28:50 +08:00
digua 1e7325197c fix(web): preserve session not-found and member history behavior 2026-05-22 10:20:39 +08:00
diguaandCursor dd3cb10414 refactor(services): unify CLI Web and Electron service layer
Extract shared business logic from monolithic web.ts into reusable
services in @openchatlab/node-runtime (session, member, index, summary,
export), using SessionRuntimeAdapter to abstract platform differences.
Split web.ts into 12 domain-specific route modules under routes/web/.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 10:20:39 +08:00
diguaandCursor 808b9026f2 fix(ai): parse MiniMax streaming <think> tags as thinking events
MiniMax models embed thinking content as <think> tags in the content
field rather than using a separate reasoning field. Add a streaming
think-tag parser that detects these tags in real-time during streaming
and routes them to the thinking UI instead of displaying raw tags.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 10:20:39 +08:00
digua 08260499f8 feat: migrate localStorage to backend storage with declarative persist plugin
- Add backendPersist Pinia plugin for declarative preferences.json persistence
- Move Preferences types to @openchatlab/shared-types (single source of truth)
- Migrate sessionGapThreshold from localStorage to config.toml [ui]
- Migrate chatlab_filter_history from localStorage to preferences.json
- Fix stale localStorage locale read in i18n/index.ts
- Simplify usePreferencesSync (172 → 75 lines) by delegating to plugin

Adding a new backend-synced preference now only requires 3 changes:
1. shared-types interface  2. node-runtime DEFAULTS  3. store backendPersist.pick
2026-05-19 22:42:00 +08:00
digua 05394c2155 feat(cli): auto-detect and migrate Electron desktop data on first CLI run
When a desktop app user installs the CLI, automatically detect existing
Electron data directory (including custom paths via storage.json),
repoint config.toml, and migrate system data (ai, settings, cache, etc.)
to ~/.chatlab/. Block CLI execution with actionable instructions when
Electron was used but databases cannot be located.
2026-05-19 22:19:00 +08:00
digua b12c07dc32 refactor: extract Electron shell to apps/desktop/
Move Electron-specific code (main, preload, shared) and configs
(electron.vite, electron-builder) into apps/desktop/ to prepare
for multi-platform support (Web Browser standalone).

- Create apps/desktop/ with dedicated package.json and tsconfig
- Split Electron deps (electron, electron-updater, better-sqlite3,
  etc.) from shared frontend deps in root package.json
- Declare better-sqlite3 and @node-rs/jieba in packages/node-runtime
- Add stream-json to packages/parser where it belongs
- Update all path aliases (@electron/* → apps/desktop/*) in tsconfig,
  vite configs, and relative imports in preload/main
- Keep slim root tsconfig.node.json as shared base for packages
- Update CI/CD release workflow for new directory layout
- Fix pre-existing type errors (pi-ai Model generic, SQLLabTab
  LLMChatStreamChunk, filter.test.ts empty methods)
2026-05-19 00:31:00 +08:00
digua 31359712b3 refactor(core): extract remaining inline SQL from electron adapters
- Extract getPrivateChatMemberAvatar to @openchatlab/core
- Extract getExportSessionData (meta/members/messages SQL) to @openchatlab/core
- Extract loadSessionMessages for summary generation to @openchatlab/core
- Replace inline SQL in summary buildDeps with shared core query functions
- Extract createCompressionLlmAdapter factory to @openchatlab/node-runtime
- Simplify server and electron compression adapter creation via shared factory
2026-05-18 23:36:42 +08:00
digua 53fa23f488 refactor(ai): unify formatAIError and extract FTS search SQL to core
- Extract formatAIError to @openchatlab/node-runtime, eliminate duplicate in Electron and Server
- Extract stripAvatarFields to @openchatlab/core
- Extract FTS message search SQL to core (searchMessagesWithFtsAsync)
- Remove redundant sync searchMessagesWithLike from Electron worker
2026-05-18 23:28:39 +08:00
digua cdb2bfea7c feat: unify LLM streaming with thinking display and Web/cache API shims
- Extract runSimpleLlmStream to @openchatlab/node-runtime for shared
  Electron/Server streaming with thinking_start/delta/end event handling
- Simplify Electron IPC ai.ts by delegating to shared stream function
- Add thinking/thinkingDone fields to LlmStreamChunk and preload types
- Add collapsible thinking process display in SQL LAB with auto-scroll
- Implement Web chatStream via SSE with proper error propagation
- Add /_web/cache/save-to-downloads and show-in-folder server routes
- Add cacheApi shim in Web registry for server-side file operations
- Increase SQL LAB maxTokens to 4096 to accommodate reasoning models
- Detect finishReason:length and show token limit error message
- Add i18n keys for thinking/thinkingProcess/errorTokenLimit (4 locales)
2026-05-18 22:32:00 +08:00
digua 7190606ca7 refactor: extract AI translations to shared i18n module in node-runtime
Move AI-related translations (tools, agent prompts, LLM, summary) from
Electron-specific locale files into @openchatlab/node-runtime, enabling
single-source maintenance across Electron and Server.

- Add packages/node-runtime/src/ai/i18n/ with createAiTranslate() and
  bundled locale data (zh-CN, en-US, ja-JP, zh-TW)
- Electron locale files now compose: Electron-specific keys + shared AI
  translations from node-runtime
- Server agent.ts switches to shared buildSystemPrompt with evidence
  policy, data snapshot injection, ownerInfo and mentionedMembers support
- Server route fetches dataSnapshot from getChatOverview before agent run
2026-05-18 22:04:01 +08:00
digua a3a1d289ba feat(node-runtime): extract Markdown export engine and add server export route
- Extract exportFilterResultToMarkdown to node-runtime/export with writer abstraction
- Electron export.ts becomes thin wrapper (fs.createWriteStream + worker IPC progress)
- Server adds POST /_web/sessions/:id/export/markdown returning downloadable Markdown
2026-05-18 21:01:27 +08:00
digua 9ee3060377 feat(node-runtime): extract session cache to shared package
- Extract JSON cache CRUD + overview/members compute to node-runtime/cache
- Functions now accept DatabaseAdapter instead of better-sqlite3 Database
- Electron sessionCache.ts becomes pure re-export
- Updated all Electron callers to wrap DB with BetterSqliteAdapter
2026-05-18 20:41:48 +08:00
digua 064f3ce144 feat(node-runtime): extract chat DB migrations and add auto-migration on writable open
- Extract migration definitions (v1-v4) to shared getChatDbMigrations() with DI for tokenizer
- DatabaseManager.openWritable() auto-runs pending migrations
- Electron migrations.ts becomes thin wrapper delegating to shared definitions
2026-05-18 20:38:38 +08:00
digua 8d430249c9 feat(node-runtime): extract TempDbWriter/Reader and session export
Platform-agnostic temp DB management for merge operations using
DatabaseAdapter. Includes TempDbWriter (streaming write), TempDbReader
(streaming read + MergerDataSource adapter), exportSessionToJson,
and cleanup helpers.
2026-05-18 20:00:59 +08:00
digua 2e564e8063 feat(node-runtime): extract IncrementalImporter from Electron worker
Platform-agnostic incremental import with dual-path dedup
(platformMessageId + content hash), member upsert, meta patching,
FTS sync, and injectable dependencies (IncrementalImportDeps).
2026-05-18 19:58:25 +08:00
digua bf91c4b7df feat(node-runtime): extract StreamingImporter from Electron worker
Platform-agnostic streaming import with batched transactions, deferred
indexes, nickname history tracking, FTS indexing, and format fallback.
All Electron-specific dependencies replaced with injectable interfaces
(StreamImportDeps, ImportLogger, ImportProgressCallback).
2026-05-18 19:56:27 +08:00
digua 249df9c8e3 feat(node-runtime): extract RAG subsystem to shared package
Move the entire RAG module (~2458 lines) from electron/main/ai/rag/ to
@openchatlab/node-runtime. Includes chunking, embedding, vector store,
and semantic pipeline.

Key changes:
- Config operations use injected aiDataDir instead of getAiDataDir()
- Logger uses injectable RagLogger interface
- LLM config provided via getLLMConfig/getAssistantConfig callbacks
- Deduplicated cosineSimilarity into shared utils.ts
- Electron rag/index.ts is now a thin wrapper (~128 lines)
2026-05-18 19:06:01 +08:00
digua 1796731535 feat(node-runtime): extract import perf logger to shared package
Move performance logging from electron/main/worker/core/perfLogger.ts to
@openchatlab/node-runtime. Log directory is now caller-provided instead
of derived from Electron paths. Electron wrapper provides the path.

Reduces Electron perfLogger from ~181 lines to ~28 lines.
2026-05-18 18:50:30 +08:00
digua 0017dcbf9e feat(node-runtime): extract FTS5 index operations to shared package
Move core FTS operations (create, build, rebuild, insert, search) to
@openchatlab/node-runtime working with DatabaseAdapter. Electron fts.ts
becomes a thin adapter that adds session-level DB connection management.

Reduces Electron fts.ts from ~207 lines to ~90 lines of pure wrappers.
2026-05-18 18:49:14 +08:00
digua 1f11f94212 feat(node-runtime): extract writeParseResultToDb to shared import module
Move the core data writing logic (meta/member/message insertion with
member_name_history tracking) from electron/main/database/core.ts to
@openchatlab/node-runtime. Electron importData() now delegates to the
shared function via BetterSqliteAdapter, reducing ~130 lines to ~10.

This enables both Electron and Server to share the same import logic
including name history tracking.
2026-05-18 18:45:40 +08:00
CEQ151 3583548f1f fix: strengthen agent evidence retrieval 2026-05-18 17:31:54 +08:00
diguaandCursor 8412180470 feat(node-runtime): extract SkillManagerCore class with abstract FS
Platform-agnostic skill CRUD manager with dependency injection for file
system ops, builtin skill resources, and content hashing. Supports init,
CRUD, builtin import/reimport, cloud markdown import, and AI skill menu
generation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:14:51 +08:00
diguaandCursor cb9849c164 feat(node-runtime): extract AssistantManager class with abstract FS
Platform-agnostic AssistantManager with dependency injection for file
system ops, builtin configs, and ID generation. Supports init, CRUD,
builtin import/reimport/reset, and cloud markdown import.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:10:52 +08:00
diguaandCursor 7feab45447 feat(node-runtime): extract LLM config CRUD to shared LLMConfigStore class
Introduce ConfigStorage abstraction and LLMConfigStore class with
dependency injection for i18n, UUID generation, and auth profile hooks.
All CRUD operations (add/update/delete/slots) are platform-agnostic.
Electron can implement ConfigStorage with fs + getAiDataDir.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:07:28 +08:00
diguaandCursor 640d16c6ec feat(node-runtime): extract merger orchestration to @openchatlab/node-runtime
Move merge orchestration (data source reading, conflict checking,
ChatLab output assembly, JSONL serialization) to shared package with
abstract MergerDataSource interface. Electron merger becomes thin adapter
wrapping TempDbReader and handling file I/O.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 00:02:20 +08:00
diguaandCursor 03cb8aa196 feat(core): extract merger pure algorithms to @openchatlab/core
Move platform ID collision detection, normalization, conflict detection,
member merge, and message dedup-sort from electron/main/merger to a
shared package with zero Node.js dependencies.

Also fix pre-existing unused-variable TS errors in summary test.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 23:54:07 +08:00