Commit Graph

63 Commits

Author SHA1 Message Date
Phantom
6ec914cf0f refactor(file-entry): rename trashedAt to deletedAt (#15246)
### What this PR does

Before this PR:

- `file_entry` table used `trashed_at` for the soft-delete timestamp,
diverging from every other soft-deletable table in the schema (`agent`,
`assistant`, `message`, `topic`), which all use `deleted_at`.

After this PR:

- `file_entry.deleted_at` (and BO field `deletedAt`) — naming is
consistent across the entire schema.
- Renamed identifiers:
  - Schema field: `trashedAt` → `deletedAt`
  - SQL column: `trashed_at` → `deleted_at`
  - Index: `fe_trashed_at_idx` → `fe_deleted_at_idx`
  - CHECK constraint: `fe_external_no_trash` → `fe_external_no_delete`
- Updated all source files, tests, and architecture docs (including
`v2-refactor-temp/docs/file-manager/`).
- **Intentionally NOT renamed** (out of scope — these are API surface /
concept names, not the column name): `moveToTrash`, `restoreFromTrash`,
`inTrash` (query flag), `isTrashed`, `batchTrash`, `internalTrash`, and
"Trash" as a concept in comments/docs.

Fixes #

### Why we need it and why it was done in this way

The following tradeoffs were made:

- **Scope discipline**: kept the rename strictly at the
column-identifier layer (4 identifiers). Did not change API names or
concept words — switching the "Trash" concept to "Delete" is a larger
semantic change that deserves its own PR.
- **Migration 0026 contains a manual SQL patch.**
drizzle-orm/drizzle-kit issue
[#3653](https://github.com/drizzle-team/drizzle-orm/issues/3653) causes
the SQLite rebuild-table path to drop the leading `ALTER TABLE … RENAME
COLUMN` statement. The generated `INSERT … SELECT "deleted_at" FROM
file_entry` would fail because the source table still has `trashed_at`.
The migration manually prepends an explicit `ALTER TABLE file_entry
RENAME COLUMN trashed_at TO deleted_at;` before the rebuild. Upstream
fix landed in `drizzle-kit@1.0.0-beta`/`rc` but is not backported to the
`0.31.x` stable line we depend on.
- **Why keeping the manual patch is acceptable**: per `CLAUDE.md` § v2
Refactoring, `migrations/sqlite-drizzle/` is throwaway during v2 — it
will be wiped and regenerated as a single clean initial migration from
the final schemas before release. Mid-development DB drift is explicitly
acceptable, and the manual SQL only needs to survive until that
regeneration.

The following alternatives were considered:

- Selecting `create column` in `drizzle-kit generate` instead of `rename
column`: also produces invalid SQL (same root cause — the rebuild path
puts the new column name in the `SELECT` list regardless of the rename
mapping). Rejected.
- Skipping the `0026` migration entirely and relying on `db:push` / DB
reset during dev: pollutes `_journal.json` divergence and makes the next
schema change confusing. Rejected.
- Upgrading to `drizzle-kit@1.0.0-beta`/`rc` to get the fix: v1 is a
major rewrite with significant breaking changes (alternation engine
rewrite, ORM type system rewrite, migration folder layout change). Out
of scope for this PR. Rejected.

Links to places where the discussion took place: N/A

### Breaking changes

None. Dev-only DB column rename during v2 refactor. No user-visible
behavior change. No public API surface change. v1 data never reaches
this branch except through migrators in `src/main/data/migration/v2/`.

### Special notes for your reviewer

- The single manual edit to drizzle-generated SQL is in
`migrations/sqlite-drizzle/0026_sturdy_aqueduct.sql` — look for the
`MANUAL PATCH` comment block at the top. Without it the migration will
fail to apply.
- "Trash" concept words still appear throughout the file-manager
codebase by design (function names, comments, docs section headings). If
we later want to migrate the whole concept to "Delete", that should be a
follow-up PR.

### Checklist

This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

```release-note
NONE
```

---------

Signed-off-by: icarus <eurfelux@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 23:04:36 +08:00
fullex
4c156c5eea refactor(job): collapse jobs DataApi to read-only and relocate main-only types
- Remove POST /jobs (enqueue) and DELETE /jobs/:id (cancel); Job DataApi
  is GET-only. Business services call JobManager.enqueue/.cancel in main;
  renderer-initiated triggering goes through a dedicated IPC channel.
- Move Trigger / RetryPolicy / CatchUpPolicy / JobScheduleSnapshot /
  Create+Update JobScheduleDto / JobScheduleNameAtomSchema /
  JOB_ERROR_CODES from packages/shared/data/api/schemas/jobs.ts into
  src/main/core/job/{scheduleTypes,errorCodes}.ts. These are
  main-process-only types that never cross IPC.
- shared/jobs.ts retains JobSnapshot, JobProgress, JobError,
  ListJobsQuerySchema, JobSchemas (GET-only) — the actual renderer
  surface useJob/useJobProgress consume via DataApi + cache.
- Update DataApi anti-patterns table and job-and-scheduler docs to
  reference IPC channels for renderer-initiated triggering.

shared/jobs.ts: 316 → 139 lines
handler/jobs.ts: 102 → 43 lines
2026-05-21 02:28:06 -07:00
fullex
5b929d2f87 feat(job): rework schedule lifecycle and startup recovery
Four backbone changes that close known gaps in the schedule subsystem before the next round of business handler work:

* DB-enforced singleton: drop the app-layer Mutex in JobScheduleService and let UNIQUE(type, name) enforce "one singleton per type" via a '' sentinel. rowToSnapshot maps '' back to null so the external snapshot contract stays `string | null`.
* updateJobSchedule public API: writes the DB row and re-arms the in-process cron entry when trigger or enabled changes. Field-presence check avoids JSON.stringify brittleness; the one-turn race is an accepted last-writer-wins limitation.
* Startup recovery gating: move runStartupRecovery + armSchedule from onReady to a new onAllReady behind a 60s delay so business services have a window to register handlers before recovery runs. onStop flips a stop flag for clean teardown; per-step try/catch so one failure does not zero the session.
* Schedule control API tests: cover pause/resume/triggerNow/unregister × by-id/by-name plus updateJobSchedule branch matrix; JobScheduleService gets its own unit suite for singleton/sentinel behavior.

Side effects: add JOB_SCHEDULE_NAME_INVALID code; fix pre-existing arg order on DataApiErrorFactory.conflict at unique handlers (message, then resource); tighten getByTypeAndName signature to (type, name: string); listNamesForType filters the singleton sentinel and returns string[]; sync existing integration/smoke fixtures to await _doAllReady() with fake timers; add "Schedule identity: (type, name) model" section in handler-authoring.md.
2026-05-19 22:49:24 -07:00
fullex
3411252e53 feat(job): add DataApi endpoints + tests (Phase 1 wrap-up)
Phase 1 wrap-up on top of backbone commit 344c58eb8.

DataApi endpoints in src/main/data/api/handlers/jobs.ts:
- GET /jobs with status/queue/type/scheduleId filters + limit/offset
- GET /jobs/:id (404 on miss)
- POST /jobs (enqueue, payload size + type enforced by JobManager)
- DELETE /jobs/:id (cancel with optional reason query)

Reads go through jobService directly; writes through
application.get('JobManager') so AbortControllers, cache pushes, and
dispatch state remain authoritative.

Endpoint schemas (packages/shared/data/api/schemas/jobs.ts):
ListJobsQuerySchema parses comma-separated status values with runtime
validation; CancelJobQueryParams mirrors the body shape; JobSchemas
type is wired into ApiSchemas. EnqueueJobInputSchema refined to
require a parseable ISO timestamp for scheduledAt.

useJob hook now falls back to DataApi when the shared cache misses
(cold mount or post-TTL recall), keeping cache as the primary
realtime source via useQuery's enabled flag.

Tests in src/main/core/job/__tests__/:
- Smoke (5): end-to-end run, progress + state cache publish, in-flight
  cancel, idempotencyKey reuse, list via JobService.
- Integration (6): recovery state transitions for abandon / retry /
  singleton strategies, orphan handler cleanup, graceful shutdown
  abort propagation, 20-queue parallel dispatch without SQLITE_BUSY
  (libsql client-ts issue #288 regression guard).

Test infrastructure: drainTrailingDispatch helper acquires and
immediately releases each per-queue mutex to deterministically wait
for trailing dispatch transactions to commit, replacing fragile
sleep-based waits.
2026-05-19 04:55:10 -07:00
fullex
344c58eb8e feat(job): introduce JobManager + SchedulerService backbone (Phase 1)
cherry-studio v2 had 6+ ad-hoc queue/scheduler implementations (Knowledge,
FileProcessing, agent SchedulerService, TopicQueue, NotificationQueue,
protocol heartbeats) with no shared registry, inconsistent cancel and
progress semantics, and no cross-restart recovery outside agent_task.
This commit lands the unified replacement: JobManager owns Job lifecycle
and SchedulerService owns time-only scheduling, both reusable independently.

Phase 1 ships the backbone only: jobTable + jobScheduleTable, entity
services, 6-state machine with per-handler recovery (abandon/retry/
singleton), catch-up policy (skip-missed/after-startup), retry backoff,
GC, idempotencyKey dedup, useJob renderer hook, and 4 reference docs.
Four-layer lock model addresses libsql client-ts issue #288 (Layer 0
global dispatch mutex serializes all transactions).

croner@^10 is introduced for cron expressions (zero-dep, Electron-friendly).
Application.SHUTDOWN_TIMEOUT_MS is promoted to public for JobManager reuse.
cron-parser stays until Phase 2 agent task migration.

No business migrations in this commit — Knowledge/FileProcessing/agent
SchedulerService remain untouched and migrate in Phase 2-4 per
docs/references/job-and-scheduler/migration-checklist.md.

Follow-ups for Phase 1 completion: DataApi GET /jobs handler, dummy.echo
smoke test, integration tests, migration feasibility report.
2026-05-19 03:57:18 -07:00
jidan745le
e59c7aa7f7 refactor(provider-settings): migrate to v2 data layer and UI (#14631)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: suyao <sy20010504@gmail.com>
2026-05-14 17:01:33 +08:00
Phantom
d2c568e349 feat(file): Add schema and foundation for new file module (#13451)
### What this PR does

Adds the **Phase 1a contract surface** for the file module — types, DB
schema, DataApi + File IPC contracts, FileManager skeleton, and
architecture docs.

**Phase 1b.1 (Read Path & Repository), 1b.2 (Write Path & Lifecycle),
1b.3 (Watcher & DanglingCache), and 1b.4 (OrphanSweep &
FileRefCheckerRegistry) are now all landed on top of 1a in this same
PR.** This is the complete Phase 1b runtime — reviewers see the full
read + write + watcher + orphan-sweep picture in one place.

Design, contracts, and decision rationale live in the architecture docs:

-
[`docs/references/file/architecture.md`](docs/references/file/architecture.md)
— module boundaries, type system, IPC/DataApi contracts, layered
architecture, service lifecycle, mutation propagation
-
[`docs/references/file/file-manager-architecture.md`](docs/references/file/file-manager-architecture.md)
— FileManager internals (storage, version detection, atomic writes,
reference cleanup, DirectoryWatcher, orphan sweep, DanglingCache state
machine, key design decisions)

#### Phase 1a deliverables

- Types (`FileEntry` / `FileInfo` / `FileHandle` /
`CanonicalExternalPath` brand)
- DB schema (`file_entry` + `file_ref`) with per-origin CHECK
constraints
- DataApi schemas + stub handlers
- File IPC contract (polymorphic `FileHandle` dispatch;
`batchGetMetadata` included)
- FileManager skeleton + `internal/*` + `ops/*` + `watcher/` +
`DanglingCache` + `versionCache`
- Mutation propagation design (three typed events + prefix-based
queryKey invalidation)

#### Phase 1b.1 deliverables (read-path runtime)

- Shared utilities: `getFileTypeByExt`, `sanitizeFilename`,
`validateFileName` extracted to `@shared/file/types`
- Path utilities: `canonicalizeExternalPath` (NFC + null-byte guard +
trailing-sep strip), `isPathInside`, `isUnderInternalStorage`,
`canWrite`
- FS read primitives: `stat`, `exists`, `read` (text/base64/binary
overloads), `hash` (initial MD5; swapped to xxhash-h64 in 1b.2)
- Metadata utilities: `getFileType(path)`, `isTextFile`, `mimeToExt`
- Repositories: `FileEntryService` + `FileRefService` read methods
(Drizzle-backed, Zod-branded outputs)
- Pure-function modules: `internal/content/{read,hash}`,
`internal/dispatch.ts` (FileHandle dispatcher)
- `toFileInfo(entry)` projection
- `FileManager` class as `BaseService` (`@Injectable('FileManager')`
`@ServicePhase(WhenReady)`); read methods only
- `DanglingCache` + `VersionCache` minimal viable singletons (full impls
in 1b.3 / 1b.2)
- DataApi `/files/*` read handlers fully implemented (entries / single /
ref-counts / refs-by-source)
- 60+ TDD tests (unit + boundary + setupTestDatabase integration)

#### Phase 1b.2 deliverables (write-path runtime)

- **FS atomic primitives** (open to non-file-module consumers per
architecture §5.3): `atomicWriteFile` (tmp + fsync + rename +
fsync(dir)), `atomicWriteIfUnchanged` (re-stat OCC + content-hash
fallback for second-precision mtime), `createAtomicWriteStream`
(Writable wrapper, abort/destroy unlinks tmp)
- **FS general primitives**: `write` (delegates to atomicWriteFile),
`copy` (atomic dest), `move` (rename + EXDEV → copy+unlink fallback),
`remove` (idempotent ENOENT), `mkdir` / `ensureDir` / `removeDir`,
`download` (fetch → atomic stream)
- **Hash swap**: `hash()` migrated MD5 → `xxhash-wasm` h64 streaming;
legacy `md5` dep retained for KnowledgeService loaders
- **VersionCache LRU**: capacity-bounded (default 2000) with
re-insert-on-touch recency
- **Repository mutations**: `FileEntryService.create/update/delete`
(auto UUIDv7 default id, raw DB CHECK errors propagate);
`FileRefService.create/createMany/cleanupBySource/cleanupBySourceBatch`
(`onConflictDoNothing` for batch upsert)
- **internal/entry/**: `create.createInternal` (4 source variants: bytes
/ base64 / path / url) + `create.ensureExternal` (canonicalize + stat +
idempotent upsert + duplicate-suspect peer warn);
`lifecycle.trash/restore/permanentDelete` + batch variants (DB+FS
decoupled, internal best-effort unlink); `rename` (internal DB-only,
external fs.move + canonical externalPath); `copy` (pipes through
createInternal with rollback)
- **internal/content/write.ts**: `write` / `writeIfUnchanged`
(cache-not-trusted re-stat OCC, `StaleVersionError` rewrap from
`PathStaleVersionError`) / `createWriteStream` / `*ByPath` variants
- **internal/system/**: `shell.open` / `shell.showInFolder` (electron
`shell` wrappers); `tempCopy.withTempCopy` (isolated tmp dir; cleanup on
throw)
- **FileManager facade**: every IFileManager mutation method now
delegates to its `internal/*` counterpart (`createInternalEntry` /
`ensureExternalEntry` / `batchCreate*` / `batchEnsure*` / `write` /
`writeIfUnchanged` / `createWriteStream` / `createReadStream` / `trash`
/ `restore` / `permanentDelete` + batch / `rename` / `copy` /
`withTempCopy` / `open` / `showInFolder`); no method throws
notImplemented anymore
- ~60 new TDD tests (each behavior unit = one RED→GREEN→REFACTOR
commit); end-to-end integration scenarios via `setupTestDatabase` cover
atomic-rollback zero-residue, OCC second-precision-mtime
no-false-positive, trash-external CHECK enforcement, full
create→write→read→trash→restore→permanentDelete round-trip, and external
permanentDelete-leaves-user-file-untouched

#### Phase 1b.3 deliverables (watcher + DanglingCache observability)

- **DanglingCache class** (replaces 1a const-literal skeleton):
`byEntryId: Map<entryId, CachedState>` + `pathToEntryIds:
Map<canonicalPath, Set<entryId>>` reverse index, lazy TTL expiration
(default 30 min per architecture §11.2), `forceRecheck` escape hatch,
`Emitter<DanglingStateChangedEvent>` firing only on genuine state
transitions (same-state observations are silent). Injectable `now` /
`statProbe` / `ttlMs` / `fileEntryService` seams for deterministic
tests.
- **createDirectoryWatcher** chokidar v4 wrapper: `add` / `unlink` /
`change` / `ready` / `error` events; built-in OS-junk basename ignores
(`.DS_Store` / `.localized` / `Thumbs.db` / `desktop.ini`); idempotent
`close()`. Factory auto-wires `add` →
`danglingCache.onFsEvent(path,'present')` and `unlink` → `'missing'`.
(Architecture §8.2's richer `onAddDir`/`onUnlinkDir`/`onRename` events
deferred — no consumer needs them in scope.)
- **Reverse-index maintenance from mutation flows**: `ensureExternal`
calls `addEntry` + `onFsEvent('present','ops')` on insert (no-op on
reuse); `permanentDelete(external)` calls `removeEntry`;
`rename(external)` swaps `removeEntry(oldPath) + addEntry(newPath) +
onFsEvent(newPath,'present','ops')`.
- **FileManager surface**: `getDanglingState({id})` (internal →
'present', external → cache check, unknown id → 'unknown');
`batchGetDanglingStates({ids})` (parallel fan-out, unknown ids mapped to
'unknown'); `subscribeDangling({id}, listener)` (in-process per-entry
filter; renderer fan-out via `file-manager-event` IPC channel deferred
to Phase 2).
- **FileManager.onInit**: awaits `danglingCache.initFromDb()` (populates
reverse index from non-trashed external entries; no startup stat probe
per architecture §10.6); registers `File_GetDanglingState` /
`File_BatchGetDanglingStates` IPC handlers via `this.ipcHandle`
(auto-disposed on stop).
- New `IpcChannel` constants: `File_GetDanglingState`,
`File_BatchGetDanglingStates`.
- ~30 new TDD tests across DanglingCache (18 unit) + watcher (6 real-FS)
+ FileManager integration (INT-7..INT-10).

#### Phase 1b.4 deliverables (orphan sweep + FileRefCheckerRegistry)

- **FileRefCheckerRegistry**: `Record<FileRefSourceType,
SourceTypeChecker<...>>` typed registry forces exhaustive coverage at
compile time — adding a new variant to `FileRefSourceType` without a
checker triggers a TS build error. Phase 1 ships `FileRefSourceType =
'temp_session' | 'knowledge_item'`: real DB-backed checker for
`knowledge_item` (Drizzle `inArray` against `knowledge_item`);
`temp_session` checker treats every sourceId as gone (sessions are
in-memory only). `chat_message` / `painting` / `note` are **deliberately
not in the union yet** — each will be added in lockstep (tuple entry in
`allSourceTypes` + `createRefSchema` variant + `SourceTypeChecker`) by
the PR that migrates the owning domain's DB tables to v2. Stray writes
during the migration window fail fast at `FileRefSchema.parse` rather
than being silently persisted under a no-op stub.
- **OrphanRefScanner** (RFC §6.4): `scanOneType(sourceType)` enumerates
distinct `file_ref.sourceId` per type, asks the checker which are alive,
deletes the rest via `cleanupBySourceBatch`. `scanAll()` aggregates
across every registered sourceType. Backed by new
`FileRefService.listDistinctSourceIds` to keep all SQL inside the repo.
- **Report-only orphan-entry pass** (architecture §7.1 default policy is
"preserve"): `scanOrphanEntries` groups active entries with zero
`file_ref` rows by origin. **No deletion** — surfaced via
`getOrphanReport()` for the cleanup-UI consumer. Backed by new
`FileEntryService.findUnreferenced` LEFT JOIN-based query.
- **Startup file sweep** (architecture §10): `runStartupFileSweep`
snapshots `file_entry.id` (active + trashed) into a `Set` via new
`FileEntryService.listAllIds`, walks `{userData}/files/`, plans unlink
for (a) UUID-named files whose id is not in the snapshot and (b)
`*.tmp-<UUID>` atomic-write residue. Applies the `mtime > 5min`
freshness gate (§10.3) — files newer than that are presumed in-flight
and preserved. Plan-then-execute with the `50% / 20-count-floor /
10MB-floor` safety threshold (§10.4); aborts emit
`abortReason='count-fraction'|'byte-fraction'`. Single structured
`orphan-file-sweep` log per run (info / warn / error per outcome,
§10.5).
- **DB-sweep umbrella + observability** (`runDbSweep`): runs scanAll +
scanOrphanEntries, emits one `orphan-sweep` structured record
summarising both passes; failure path returns `outcome='failed'` +
`errorMessage` so callers don't throw on background fire-and-forget.
- **FileManager integration**: `onInit` schedules a fire-and-forget
`runStartupSweeps` that runs the FS-level + DB-level sweeps in parallel;
failures of either are logged but never block ready. `getOrphanReport()`
exposes the most recent `DbSweepReport` (orphan-ref counts already
cleaned + orphan-entry counts preserved) + `lastRunAt` for the cleanup
UI surface.
- ~30 new TDD tests across registry (14 unit) + orphan sweep (16 unit +
integration) + FileManager integration (INT-11/INT-12) + repo
(`findUnreferenced`, `listAllIds`, `listDistinctSourceIds`).

**Out of scope (deferred to Phase 2)**:
- Architecture §7.2 dangling-external auto-cleanup (external + missing +
0-ref + >30d retention) — narrow extension shipping with the cleanup UI.
- Adding `chat_message` / `painting` / `note` as `FileRefSourceType`
variants (tuple entry + schema + checker added together) — gated on each
domain's v2 batch migration.
- Cleanup-UI surface that consumes `getOrphanReport()` — Phase 2
renderer work.

Renderer-side File IPC bridge for write/dangling methods stays deferred
to Phase 2 alongside the consumer-batch migrations. The Phase 1b runtime
is consumable from main-side business services through
`application.get('FileManager')`.

### Why we need it and why it was done in this way

Contract-first concentrates design review in one place; Phase 1b.x then
becomes pure "honor the contracts". Each 1b.x phase keeps strict TDD
(RED → GREEN → REFACTOR per behavior, ~one commit per cycle); each phase
ends with a verification gate (push → CI green) before the next phase
begins.

Core decisions (origin two-state, `FileEntry`/`FileInfo` split, DataApi
SQL-only, external `permanentDelete` DB-only, TTL `DanglingCache`, OCC
trust boundary, atomic write fsync default, etc.) and their rationale
are recorded in `file-manager-architecture.md §12 Key Design Decisions`
— not duplicated here.

### Breaking changes

None — purely additive (read+write paths are new, no existing callers
replaced yet).

### Special notes for your reviewer

- Review focus: contracts (1a) + read-path runtime (1b.1) + write-path
runtime (1b.2) + watcher/DanglingCache (1b.3) + orphan sweep / registry
(1b.4). Phase 1b is now complete on this branch.
- **Phase 1a contract stability policy** (architecture.md top) is
binding — any 1b.x PR that finds a contract mismatch PRs the doc
revision first.
- Deferred (Phase 2): renderer-side File IPC bridge for
write/dangling/orphan methods (alongside consumer migration); cleanup-UI
surface consuming `getOrphanReport()`; architecture §7.2
dangling-external auto-cleanup (>30d retention); adding `chat_message` /
`painting` / `note` as `FileRefSourceType` variants (each adds tuple
entry + schema + checker in lockstep, gated on the owning domain's v2
batch migration); DanglingCache periodic snapshot logger (architecture
§11.8); `listDirectory` ripgrep wrapper; `compressImage`
(KnowledgeService consumer); FileUploadService + `file_upload` table
(Vercel AI SDK Files API).

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: N/A — purely additive
- [ ] Documentation: Internal architecture docs included
(`docs/references/file/`); no user-facing docs change
- [x] Self-review: I have reviewed my own code before requesting review
from others

### Release note

```release-note
NONE
```

---------

Signed-off-by: icarus <eurfelux@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-05-13 16:06:10 +08:00
jd
3c200793cb feat(library): add v2 resource library page with assistant tag & search APIs (#14442)
<!-- Template from
https://github.com/kubevirt/kubevirt/blob/main/.github/PULL_REQUEST_TEMPLATE.md?-->

### What this PR does

This PR adds the new v2 **Resource Library** page at `/app/library` as a
unified management entry point for **Assistants, Agents, and Skills**.

The page provides a shared navigation and interaction shell, but
resource data is loaded per active resource tab. Assistants, Agents, and
Skills each keep their own adapter/query path and backend ownership
boundary; there is no aggregated cross-resource list endpoint in this
PR.

**Scope by resource**

- **Assistant** — when the Assistant tab is active, the library uses the
Assistant DataApi list/create/duplicate/update/delete paths. Assistant
reads include embedded `tags` and `modelName`, and Assistant list
supports `search` and `tagIds` filtering.
- **Agent** — when the Agent tab is active, the library uses the Agent
DataApi list/create/update/delete paths and the Agent editor for
configuration. Agent list supports the resource-library search/tag
filter shape through the Agent DataApi.
- **Skill** — when the Skill tab is active, the library uses Skill
list/detail/import/uninstall flows. Filesystem-affecting operations stay
on the existing skill IPC service, while tag binding and list filtering
use the v2 tag/skill API paths.

Before this PR:

- Assistant, Agent, and Skill management lived in separate product
surfaces.
- There was no shared v2 Resource Library entry point for browsing these
resource types through one navigation model.
- Resource search and tag filtering were not exposed through a
tab-scoped Resource Library UI.
- Assistant list reads did not embed tag metadata or model display names
for the library cards.

After this PR:

- `/app/library` provides a shared Resource Library shell with
resource-specific tabs.
- Switching tabs changes which resource adapter/query path is active; no
cross-resource aggregate query is introduced.
- Assistant, Agent, and Skill lists can be searched and filtered by tags
within their active tab.
- Assistant reads embed `tags[]` and `modelName`, and Assistant
create/update accepts optional `tagIds` for tag binding.
- Agent configuration can be created and edited from the library editor
flow.
- Skill detail, import/install, uninstall, file preview, and tag binding
are available from the library page.
- The library keeps the current v2 `useDataApi.refetch` contract as a
revalidation/cache helper; this PR does not turn `refetch` into an
imperative data-read API.

<!-- (optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)`
format, will close the issue(s) when PR gets merged)*: -->

Fixes #

### Why we need it and why it was done in this way

The v2 Resource Library is intended to replace fragmented
resource-management entry points with one consistent place to browse and
manage Assistants, Agents, and Skills while keeping each resource type's
data ownership intact.

The implementation keeps the Resource Library as a shared UI surface
while keeping reads and writes resource-scoped. Switching tabs changes
which resource adapter/query path is active, so each resource type keeps
its own backend contract instead of introducing a new aggregated query
layer.

The following tradeoffs were made:

- **Shared shell, resource-scoped data**: the UI frame is shared, but
Assistant, Agent, and Skill keep separate adapters and backend paths.
- **No aggregate Resource Library endpoint**: the page does not
introduce a cross-resource list API. This avoids a new orchestration
layer and keeps pagination/filtering behavior owned by each resource
service.
- **Tag filtering uses OR semantics**: matching any selected tag is
enough for inclusion. AND semantics can be added later as a separate
query shape if needed.
- **Filesystem work stays outside DataApi**: Skill install/uninstall
still use the skill IPC service because those operations touch local
directories, archives, repositories, and symlinks.
- **`refetch` remains a revalidation trigger**: direct cache control or
imperative reads should continue to use SWR/DataApi `mutate` or explicit
requests rather than relying on `refetch` return values.

The following alternatives were considered:

- A single aggregated `/library/resources` style endpoint — rejected
because it would duplicate resource-specific filtering logic and blur
service ownership.
- Client-only filtering across all resource types — rejected because
search/tag filtering should use the resource service's current query
contract where available.
- Moving Skill install/uninstall into DataApi — rejected because
filesystem mutation is outside the SQLite-backed DataApi boundary.

Links to places where the discussion took place: N/A

### Breaking changes

None.

The API/schema changes are additive:

- Assistant responses include embedded `tags` and `modelName`.
- Assistant create/update accepts optional `tagIds`.
- Resource list paths support tab-scoped search/tag filtering where
applicable.

Existing callers that do not use the new fields or query params should
continue to work.

### Special notes for your reviewer

Base branch is `v2`. This PR is still a draft while review feedback is
being addressed.

Suggested review entry points:

- Renderer library shell:
`src/renderer/src/pages/library/LibraryPage.tsx`
- Resource list/grid: `src/renderer/src/pages/library/list/`
- Assistant adapter/editor:
`src/renderer/src/pages/library/adapters/assistantAdapter.ts`,
`src/renderer/src/pages/library/editor/assistant/`
- Agent adapter/editor:
`src/renderer/src/pages/library/adapters/agentAdapter.ts`,
`src/renderer/src/pages/library/editor/agent/`
- Skill adapter/detail/import:
`src/renderer/src/pages/library/adapters/skillAdapter.ts`,
`src/renderer/src/pages/library/detail/skill/`,
`src/renderer/src/pages/library/list/ImportSkillDialog.tsx`
- Backend services: `AssistantService`, `AgentService`, `TagService`,
and skill service integration paths.

Known follow-ups:

1. Continue UI polish on Resource Library spacing and detail/editor
interactions.
2. Continue component-level i18n cleanup for any remaining literals
found during review.
3. Keep model-picker related v2 LLM migration work separate from this PR
unless required by this library flow.

### Checklist

This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [x] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

<!--  Write your release note:
1. Enter your extended release note in the below block. If the PR
requires additional action from users switching to the new release,
include the string "action required".
2. If no release note is required, just write "NONE".
3. Only include user-facing changes (new features, bug fixes visible to
users, UI changes, behavior changes). For CI, maintenance, internal
refactoring, build tooling, or other non-user-facing work, write "NONE".
-->

```release-note
Add a new v2 Resource Library page under /app/library for managing Assistants, Agents, and Skills through resource-specific tabs, with search, tag filtering, editors/details, assistant import/export, and skill import/uninstall flows.
```

---------

Signed-off-by: jdzhang <625013594@qq.com>
Signed-off-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-05-10 20:14:45 +08:00
Phantom
88308d0b15 refactor(translate): migrate renderer translate module from Redux/Dexie to v2 data APIs (#13871)
### What this PR does

Before this PR:
The renderer-side translate module (`TranslatePage`, `TranslateHistory`,
`TranslateSettings`, `ActionTranslate`, etc.) relied on Redux store and
Dexie (IndexedDB) for state management, language data, and history
persistence. A monolithic `useTranslate` hook bundled all
translate-related logic together.

After this PR:
- The monolithic `useTranslate` hook is replaced with **9 granular
hooks** (`useAddHistory`, `useDeleteHistory`, `useClearHistory`,
`useAddLanguage`, `useDeleteLanguage`, `useDetectLang`, `useLanguages`,
`useUpdateHistory`, `useUpdateLanguage`) backed by `usePreference`,
`useCache`, and `DataApi`.
- `TranslatePage`, `TranslateHistory`, `TranslateSettings`, and
`ActionTranslate` are migrated to the v2 Cache/Preference/DataApi
architecture.
- `TranslateService` is refactored to remove direct Redux/Dexie
dependencies and use `dataApiService` for language lookups.
- `TranslateHistory` component is split into
`TranslateHistory/index.tsx` and `TranslateHistoryItem.tsx` for better
separation of concerns.
- `CustomLanguageSettings` is renamed to `TranslateLanguageSettings`,
and `CustomLanguageModal` to `TranslateLanguagesModal`.
- Preference schemas and migration mappings are updated accordingly.

### Why we need it and why it was done in this way

This is part of the v2 data layer migration effort to remove Redux and
Dexie from the renderer process. The translate module is migrated to use
the new unified data architecture (Cache for transient UI state,
Preference for user settings, DataApi for persistent business data).

The following tradeoffs were made:
- Granular hooks increase the number of files but improve tree-shaking,
testability, and make each hook's responsibility clear.
- The `ActionTranslate` (selection window) component was significantly
refactored to use the new hooks while preserving the smart language
detection and bidirectional translation UX.

The following alternatives were considered:
- Keeping a single `useTranslate` hook wrapper was considered but
rejected in favor of composability and alignment with the v2 hook
patterns used elsewhere.

### Breaking changes

None. This is an internal refactoring with no user-facing behavior
changes.

### Special notes for your reviewer

- `target-key-definitions.json` has new preference keys added for
translate feature settings.

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [ ] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

```release-note
NONE
```

---------

Signed-off-by: icarus <eurfelux@gmail.com>
Signed-off-by: jdzhang <625013594@qq.com>
Signed-off-by: kangfenmao <kangfenmao@qq.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: jdzhang <625013594@qq.com>
Co-authored-by: kangfenmao <kangfenmao@qq.com>
2026-05-10 18:19:28 +08:00
槑囿脑袋
01e7e31a8e feat(v2): add main-side file processing backend (#13968)
### What this PR does

Before this PR:

File processing on the `v2` branch was still described and wired around
split OCR / markdown APIs, legacy feature names, and feature-first
provider structure. OCR-like image text extraction and
document-to-markdown conversion did not share one task contract, and
provider task ids / polling details were harder to keep behind the
Main-process boundary.

After this PR:

`v2` file processing follows
`v2-refactor-temp/docs/fileProcessing/file-processing-service.md` as the
design baseline:

- exposes one Main-side task API: `startTask`, `getTask`, and
`cancelTask`
- replaces split file-processing IPC with `file-processing:start-task`,
`file-processing:get-task`, and `file-processing:cancel-task`
- renames features and preference keys to `image_to_text` and
`document_to_markdown`
- adds `FileProcessingTaskService` as the in-memory source of truth for
task ids, task state, progress, cancellation, TTL pruning, remote-poll
dedupe, and task change events
- keeps provider task ids, remote context, query context, abort
controllers, and in-flight polling inside Main-process task records
- maps completed results to artifacts: inline `text/plain` for
`image_to_text`, and persisted markdown file artifacts for
`document_to_markdown`
- reorganizes providers into processor-first handlers under
`src/main/services/fileProcessing/processors`
- moves Tesseract worker ownership under `processors/tesseract/runtime`
- removes the new file-processing module's old `ocr/` and `markdown/`
split directories after migrating their logic
- updates shared schemas, presets, preference generation, migration
mappings, and tests for the renamed feature model

The public file-processing contract is now:

```ts
await window.api.fileProcessing.startTask({
  feature: 'image_to_text',
  file,
  processorId: 'tesseract'
})

await window.api.fileProcessing.getTask({ taskId })
await window.api.fileProcessing.cancelTask({ taskId })
```

Architecture overview:

```text
Renderer / upper-layer caller
        |
        | startTask / getTask / cancelTask
        v
FileProcessingOrchestrationService
        |
        | Zod validation + delegation
        v
FileProcessingTaskService
        |
        | taskId, task store, TTL, cancellation,
        | background execution, remote polling, artifacts
        v
processorRegistry[processorId].capabilities[feature]
        |
        +--> image-to-text handlers
        |       -> text/plain artifact
        |
        +--> document-to-markdown handlers
                -> feature.files.data/fileId/file-processing/taskId/output.md
```

Notes:

- The new file-processing API does not keep facades for
`file-processing:extract-text`,
`file-processing:start-markdown-conversion-task`, or
`file-processing:get-markdown-conversion-task-result`.
- `FileProcessingOrchestrationService` is intentionally only the IPC
validation and delegation layer.
- Task state is Main-process runtime coordination state, not DataApi or
Cache state.
- Renderer task subscriptions, a global UI task center, and full
renderer business-flow migration are intentionally out of scope for this
PR.
- The legacy standalone OCR path outside the new file-processing module
can coexist during the v2 transition, but the new file-processing
interface is not polluted by those split-API types.

Fixes #N/A

### Why we need it and why it was done in this way

This PR makes OCR-style image text extraction and document-to-markdown
conversion use the same Main-process task model before renderer-side
adoption. The unified contract gives upper layers one way to start work,
query progress, handle failure, cancel work, and consume completed
artifacts without learning provider-specific polling details.

The following tradeoffs were made:

- Fast OCR now also goes through a task API, so callers need start/query
behavior instead of a direct `extractText -> text` call.
- Task state remains session-scoped in memory; completed artifacts are
persisted, but task snapshots are not restored after app restart.
- Remote-provider cancellation is best-effort: local polling and state
transition stop immediately, but third-party provider-side cancellation
is not guaranteed.
- Renderer integration is intentionally compile-safe and minimal in this
PR; full UX migration should happen in follow-up changes.
- Tesseract keeps a processor-owned runtime service, while other
processors stay as handlers/utilities until they need lifecycle-managed
resources.

The following alternatives were considered:

- Keeping separate OCR and markdown conversion APIs, which would
preserve the current split but continue duplicating task, progress,
cancellation, and result semantics.
- Adding a DataApi task table or Cache mirror for file-processing task
state, which would create a second source of truth for runtime
coordination state.
- Adding renderer push subscriptions in this PR, which would expand the
scope beyond the Main-side task contract.
- Introducing a generic process manager for all processors, which is
premature while only Tesseract currently owns reusable lifecycle
resources.

Links to places where the discussion took place:
`v2-refactor-temp/docs/fileProcessing/file-processing-service.md`

### Breaking changes

None for released user-facing behavior.

If this PR introduces breaking changes, please describe the changes and
the impact on users.

For the in-progress `v2` file-processing integration, this replaces the
split file-processing IPC/preload shape with the unified
`startTask/getTask/cancelTask` contract. It also renames file-processing
feature and preference keys from the old `text_extraction` /
`markdown_conversion` model to `image_to_text` / `document_to_markdown`.

### Special notes for your reviewer

- This PR targets `v2`, not `main`.
- Review this against
`v2-refactor-temp/docs/fileProcessing/file-processing-service.md`; that
document is the source of truth for the module boundary.
- Main review points: unified task API, artifact model, cancellation
semantics, processor-first registry/handlers, hidden provider runtime
state, and no DataApi/Cache task storage.
- `document_to_markdown` artifacts are persisted under
`application.getPath('feature.files.data')/fileId/file-processing/taskId/output.md`.
- `image_to_text` artifacts are returned inline as plain text artifacts
and are not persisted.
- Current local verification status:
  - `pnpm format`: passed
  - `pnpm build:check`: passed
- Vitest inside `build:check`: `432` test files passed, `7171` tests
passed, `72` skipped

### Checklist

This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

```release-note
NONE
```

---------

Signed-off-by: eeee0717 <chentao020717Work@outlook.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-05-08 21:25:03 +08:00
hello_world
3a508c987b refactor(miniapp): migrate to v2 data layer (#14049)
### What this PR does

Migrates the MiniApp feature from v1 (Redux + sidecar
`custom-minapps.json`) to the v2 data architecture (DataApi + Preference
+ Cache), and integrates it into the v2 AppShell tab system.

**Before this PR**
- App lists lived in three Redux arrays (`enabled` / `disabled` /
`pinned`); custom-app logos were stripped before persistence and
recovered at runtime from `{userData}/Data/Files/custom-minapps.json`.
- Settings (`region`, `max_keep_alive`, `open_link_external`,
`show_opened_in_sidebar`) lived in legacy redux/electron-store.
- Runtime keep-alive used a module-level `lru-cache` singleton, mirrored
into v2 cache via `onInsert` / `disposeAfter` (two sources of truth —
already a known race).
- Routes were `/app/minapp/*`; sidebar icon literal was `'minapp'`.
- Sidebar mode used the legacy popup container; top-navbar mode was
non-functional.

**After this PR**
- A single `mini_app` SQLite table owns every row (preset + custom).
Preset rows are seeded by `MiniAppSeeder` from `PRESETS_MINI_APPS` on
every boot; custom rows come in via `POST /mini-apps`. The seeder uses
`setWhere isNotNull(presetMiniappId)` so refreshing preset display
fields can never overwrite a custom row whose `appId` happens to collide
with a preset.
- `MiniAppMigrator` imports v1 Redux state and reads
`custom-minapps.json` (path resolved through
`MigrationPaths.customMiniAppsFile`) to recover stripped logos.
- Settings live under typed Preference keys
(`feature.mini_app.{region,max_keep_alive,open_link_external}`); sidebar
icon literal renamed `'minapp'` → `'mini_app'` with a complex preference
transform that rewrites existing user arrays in-place.
- API: `GET/POST/PATCH/DELETE /mini-apps` + `POST
/mini-apps/order:batch`, Zod-validated, fractional-indexing ordering
scoped by `status` (cross-status batches are rejected with
`VALIDATION_ERROR` per the data-ordering-guide contract). Status
transitions reassign `orderKey` to the tail of the target partition
inside a transaction.
- Renderer hook `useMiniApps` exposes **command-style** writes only:
`updateAppStatus(id, status)` and `setAppStatusBulk([{id, status}])`.
The legacy declarative `updateMiniApps(list)` /
`updateDisabledMiniApps(list)` / `updatePinnedMiniApps(list)` are gone —
they took region-filtered subsets and silently disabled rows the caller
never saw.
- Keep-alive list is stored solely in
`useCache('mini_app.opened_keep_alive')`. Cap eviction respects AppShell
pin status: `useMiniAppPopup` reads pinned mini-app routes from
`useTabs` and skips them in eviction. `MiniAppTabsPool` renders webviews
in a stable `appId`-sorted order so LRU reorders never move `<webview>`
DOM nodes (Electron `<webview>` loses its guest WebContents on
detach/reattach).
- **Unified launch path**: clicking any miniapp (from the launcher grid
or a top tab bar entry) calls `openTab('/app/mini-app/<id>', { title,
icon: app.logo })`. A globally-mounted `<MiniAppTabsPool>` in `AppShell`
keeps a `<webview>` alive per opened app, regardless of sidebar vs
top-navbar layout.
- Settings UI rewritten as a `PageSidePanel` drawer composed of
`MiniAppListPair` (visible / hidden columns with drag-drop) and
`MiniAppDisplaySettings` (region / cache slider). New custom-app form is
a separate `NewMiniAppPanel` drawer.
- Sidebar's running-mini-apps strip removed — opened apps live
exclusively in the top tab bar (per #3198804265). Companion preference
`feature.mini_app.show_opened_in_sidebar` deleted from the schema.

### Why we need it and why it was done in this way

Part of the broader v2 data-layer migration (Redux/Dexie/ElectronStore →
DataApi + Preference + Cache).

**Architecture**
- DataApi for entity rows (preserves user content); Preference for
atomic settings; Cache (Memory tier) for runtime ephemera.
- Layered preset pattern (`best-practice-layered-preset-pattern.md`):
preset and custom rows share the same table, discriminated by
`presetMiniappId`. Seeder refreshes preset display fields on re-run;
custom rows are immutable to the seeder.
- Region filtering is a **view-only** concern (read path); the write
path is command-style and never references region. This eliminated a
class of bugs where editing the visible (filtered) list caused
region-hidden rows to drift.
- AppShell tab pinning is the canonical "keep this loaded" signal. The
keep-alive cap respects it; pinned mini-app tabs never get evicted
regardless of cap. Render-order independence in `MiniAppTabsPool`
ensures LRU touches don't move `<webview>` nodes around.
- Per-app icon resolution: `app.logo` is a `CompoundIcon` id (e.g.
`"Moonshot"`) for presets and a URL for custom apps. UI consumers (tab
bar, sidebar entry, settings list) call `getMiniAppsLogo` to resolve the
id to a `CompoundIcon` before rendering, with `<img>` fallback for URL
strings.
- Per-entity tab icons are cleared on internal navigation, sidebar
reuse, and the top-bar settings button — three call sites that all flip
the active tab's URL now consistently reset `icon: undefined` so a
mini-app logo never sticks onto an unrelated route.

**Tradeoffs**
- `useMiniApps` still exposes `miniapps` (region-filtered
enabled+pinned) and `disabled` (region-filtered). These are display-only
views. Renamed/typed wrappers were considered but deferred — the
refactor to command-style writes already eliminated the bug class that
motivated the rename.
- The `applyReorderedList` integration test for
`reorderMiniAppsByStatus` was dropped — `MockUseDataApiUtils` doesn't
fill the SWR cache that `useReorder.readCurrent` reads. Splice logic is
straightforward and the server-side `applyScopedMoves` test covers the
contract.
- Sidebar primitives in `@cherrystudio/ui`-adjacent layout still accept
`miniAppTabs` / `onMiniAppTabClick` props (defensive defaults — render
nothing without a producer). Removing these from the primitive's API is
a separate refactor not in scope.

### Breaking changes

User-visible changes are auto-migrated by the v2 migration framework —
no manual user action required:
- Sidebar icon literal `'minapp'` → `'mini_app'` (rewritten by the
`sidebar_icons_rename` complex preference transform)
- Preference key rename `feature.minapp.*` → `feature.mini_app.*`
(auto-migrated via `classification.json`)
- Custom-app logos stripped from v1 Redux are recovered from
`custom-minapps.json` during migration

One product-shape change is documented under
`v2-refactor-temp/docs/breaking-changes/`:
- `2026-05-07-miniapp-sidebar-running-list-removed.md` — the sidebar no
longer surfaces opened mini-apps under the mini-app entry. Open apps are
accessed exclusively via the top tab bar; pin a tab to keep its state
across switches.

The legacy v1 preference `showOpenedMinappsInSidebar` is reclassified as
`status: deleted` in the migration pipeline; v1 values are dropped
during v1→v2 migration with no v2 destination.

### Special notes for your reviewer

**Verified end-to-end on a real dev profile**: v1 Redux state +
`custom-minapps.json` → v2 SQLite, including pinned-app cross-group
dedup (a v1 pinned app appears in both `pinned` and `enabled` Redux
arrays; the migrator counts duplicates as skipped so the engine's
`targetCount >= sourceCount - skippedCount` invariant holds — without
this, any user with pinned miniapps was blocked from migrating).

**Drizzle migrations** are throwaway in dev per `CLAUDE.md`.
`migrations/sqlite-drizzle/0020_even_hulk.sql` is the single regenerated
migration; it will be wiped to a clean initial migration before release.

**Review history**: 28 line-comments across multiple formal review
rounds. All resolved. The most consequential fixes:
- `applyScopedMoves` in `MiniAppService.reorder` — rejects cross-status
batches with `VALIDATION_ERROR` instead of silently splitting them.
- `update()` reassigns `orderKey` to a fresh tail in the target
partition on status change.
- Empty-string substitution in migrator mappings is now caught by the
post-transform validity check; bad rows are skipped + warned, never
inserted.
- Migrator validation switched from `limit(5)` sample to full `count(*)
WHERE empty-fields` — bad rows can no longer pass validation by virtue
of being beyond the sample window.
- Keep-alive cap exempts pinned tabs (#3198809321 + the kangfenmao
keepalive review); render order in `MiniAppTabsPool` is `appId`-stable
so LRU touches don't move `<webview>` nodes (this was the root cause of
"switching tabs reloads the webview").

**Out of scope**:
- The remaining `@renderer/store/tabs` import in
`PaintingsRoutePage.tsx` is pre-existing v1 residual (not introduced or
touched by this PR).

### Checklist

- [x] PR: description rewritten to reflect the final architecture +
integration with the AppShell tab system
- [x] Code: command-style writes (`updateAppStatus` /
`setAppStatusBulk`); see `useMiniApps`, `MiniAppService`,
`MiniAppMigrator`, `MiniAppTabsPool`, `useMiniAppPopup` for the main
entry points
- [x] Refactor: ~1500 lines of dead/legacy code removed
(`Tab/TabContainer`, `TabsService`, `MiniAppPopupContainer`,
`TopViewMiniAppContainer`, legacy LRU singleton, `PinnedMiniApps`, dead
`userOverrides` / `MiniAppRegistryService`, unused `Signal.ts`)
- [x] Upgrade: v1 → v2 migration verified end-to-end on a real dev
instance
- [x] Documentation: architecture covered by `docs/references/data/`;
one user-visible behavior change documented in
`v2-refactor-temp/docs/breaking-changes/`
- [x] Self-review: multi-agent review via `/gh-pr-review` (twice); all
28 review comments resolved

### Release note

```release-note
NONE - Internal v2 data refactor. User-facing renames (route, sidebar icon, preference keys) are auto-migrated. The sidebar no longer shows a running-mini-apps strip; opened apps live in the top tab bar.
```

---------

Signed-off-by: suyao <sy20010504@gmail.com>
Signed-off-by: chengcheng84 <hello_world0000@outlook.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
2026-05-07 20:45:20 +08:00
jd
bfa25bc83c refactor(prompt-management): simplify prompt management (#13430)
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-05-07 19:43:48 +08:00
LiuVaayne
28df7e872b refactor(agent-schemas): migrate agent/session/task IDs to UUID v4 and remove builtin-agent special logic (#14669)
Co-authored-by: SuYao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:34:09 +08:00
槑囿脑袋
434d4a938f refactor(knowledge-data): adjust knowledge v2 data and service (#14719)
Co-authored-by: fullex <0xfullex@gmail.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-05-01 19:24:48 +08:00
LiuVaayne
8d3ce3bfb1 refactor(agents): migrate renderer agent hooks from HTTP to DataApi (#14431)
Co-authored-by: SuYao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:13:36 +08:00
SuYao
1ccb306b30 feat(topics): migrate ordering + pin to canonical fractional-indexing pattern (#14627)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-30 21:18:25 +08:00
fullex
5677ab62bd refactor(data-api): tighten R1/R3 violations in agent/topic/message data
Apply NOT NULL constraints where NULL has no domain meaning:
- agent / agentSession: description, instructions, mcps, allowedTools,
  configuration, accessiblePaths, slashCommands (session only)
- agentGlobalSkill.tags
- message.searchableText, message.siblingsGroupId
- topic.name, topic.{isNameManuallyEdited, sortOrder, isPinned, pinnedOrder}
- miniapp.sortOrder

Drop rowMapper "?? fallback" patterns; preserve genuine T|null contracts
(agentSessionMessage.agentSessionId now passes NULL through, with the Zod
entity tightened to .nullable() to match).

Migrate product-chosen DB DEFAULTs to the service layer:
- agentTask.status DB DEFAULT removed; service was already supplying 'active'
- agentGlobalSkill.isEnabled DB DEFAULT flipped from true to false to match
  SkillService.install behavior

Drop Zod .default([]) from CreateAgentSchema.accessiblePaths so the
service-layer computeWorkspacePaths() is the single runtime default source.

Update FTS5 triggers to COALESCE the group_concat result to '' so
messages with no main_text blocks don't violate the new NOT NULL on
searchable_text.

Refs: docs/references/data/best-practice-default-values-and-nullability.md
2026-04-29 08:35:46 -07:00
jd
2e0f7579a7 fix(assistant-api): align patch defaults with entity schema (#14689)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-29 20:19:03 +08:00
LiuVaayne
26e2d4e832 ♻️ refactor(agents-data-api): migrate agents domain to DataApi — remove BaseService, database/ shims, SkillRepositories (#14428)
Co-authored-by: Vaayne <vaayne@mbp14.local>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-24 18:23:17 +08:00
fullex
3dbe907448 refactor(data-api-handlers): extract HandlersFor<> helper
All 14 per-module handler files used the same 7-line mapped type.
Extract it into a single HandlersFor<Schemas> helper in apiTypes and
migrate each file to a one-line annotation (net -119 lines).

The helper is defined as Pick<ApiImplementation, Extract<keyof Schemas,
keyof ApiImplementation>> rather than re-applying ApiHandler<Path, Method>
over generic parameters -- the latter triggers TS2590 (union too complex)
because ApiHandler nests several conditional types that must resolve
symbolically when Path is a free type variable. Indexing the
already-evaluated ApiImplementation sidesteps that.

Also elevate the annotation rule to a dedicated "Handler Type Annotation"
subsection in the data-api-in-main doc and add a type-level regression
matrix under handlers/__tests__.
2026-04-23 08:44:23 -07:00
fullex
e0e141d63c refactor(data-api): adopt Zod schema conventions across remaining schemas
Apply rules A-D from the new Zod Schema & DTO Conventions across every
DataApi schema outside the providers module:

- A. Convert every XxxSchemas route table from interface to type alias
- B. Drop Dto suffix from Zod schema constants (CreateGroupDtoSchema →
  CreateGroupSchema, and likewise for Pin / Model / EnrichModels);
  keep Dto on the TypeScript type names
- C. Derive DTOs via EntitySchema.pick({...}) whitelist with field-level
  atoms (TagColorSchema, ASSISTANT_MUTABLE_FIELDS, MCP_SERVER_MUTABLE_FIELDS);
  upgrade every entity and DTO to z.strictObject; drop the AutoFields
  shorthand (types/index.ts removed)
- D. Migrate topics / messages from pure TS interface DTOs to handwritten
  Zod schemas; add .parse() validation in the corresponding handlers

Also move EntityIdSchema from types/tag.ts to the shared types/entityType.ts
so Pin and Tag schemas refer to a single canonical polymorphic-id atom.
2026-04-22 05:15:20 -07:00
fullex
b414dc52dc refactor(data-providers): migrate to handwritten Zod schema and remove drizzle-zod
- Replace userProviderInsertSchema (drizzle-zod generated) with a
  handwritten ProviderSchema + CreateProviderSchema / UpdateProviderSchema
  in api/schemas/providers.ts
- Update providers handler to .parse() through the new schemas
- Strip drizzle-zod generator blocks from userProvider.ts and the dead
  userModelInsertSchema / userModelSelectSchema from userModel.ts
- Drop drizzle-zod dependency; drizzle-zod is being deprecated in
  drizzle v1 and its .pick()/.omit() TS output conflicts with the
  new whitelist derivation convention
2026-04-22 05:14:56 -07:00
fullex
12e4e60005 feat(data-api): add group and pin resources with polymorphic pin table
Two sibling resources land together because their migration SQL is
generated as one unit and their API-schema / handler wiring has to go
in the same commit to keep the repo compiling.

group: upgrade the existing group table from `sort_order INT` to
`order_key TEXT` (`scopedOrderKeyIndex('group', 'entityType')`) and
expose it as a first-class resource under /groups. Each entityType
owns an independent orderKey sequence. Reorder delegates to the new
applyScopedMoves helper.

pin: brand-new polymorphic table `(id, entityType, entityId, orderKey,
timestamps)` with UNIQUE(entityType, entityId) enforcing idempotency
at the DB layer. One table serves arbitrarily many consumers — same
precedent as entity_tag. No FK to consumer tables; every consumer
service's delete path must call `pinService.purgeForEntity(tx,
entityType, entityId)` to keep the two tables in sync (signature is
tx-first, the mainstream ORM convention; tagService.removeEntityTags
is the project's historical tx-last outlier and is left as-is).

PinService.pin is idempotent and concurrent-safe: a fast-path SELECT
returns existing rows, and a UNIQUE collision under concurrent INSERT
is caught, classified, and re-SELECTed so the caller never sees a
constraint error.

Handler layer is a thin Zod-parse shell — all scope inference, row
lookup, and orderKey computation live in the services.
2026-04-21 23:28:14 -07:00
fullex
5fc14e4738 refactor(data-types): extract shared EntityType enum from tag module
Move the entity type Zod enum ('assistant'|'topic'|'session') out of
tag.ts into a standalone packages/shared/data/types/entityType.ts so
upcoming group and pin resources can reuse the same source of truth
instead of each carrying its own local copy of the literal list.

All existing TaggableEntityType references in the tag API schema,
handler, and service are renamed to EntityType / EntityTypeSchema
mechanically — no behavior change, no alias kept.
2026-04-21 23:26:37 -07:00
jidan745le
2c35951356 feat(data): add domain hooks for models/providers and batch model API (#14269)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
Co-authored-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Co-authored-by: SuYao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: MyPrototypeWhat <daoquqiexing@gmail.com>
2026-04-21 19:45:15 +08:00
fullex
572202ae54 feat(data-ordering): order-key infrastructure for sortable resources 2026-04-21 03:21:05 -07:00
fullex
686bd15290 feat(data-api): support template paths, function refresh, and /* prefix matching
Extend the renderer data hooks to cover three mutation shapes that
previously had to drop to imperative dataApiService calls:

- Template paths (e.g. `/providers/:providerId`) with a runtime `params`
  option on useQuery / useMutation / useInfiniteQuery / usePaginatedQuery,
  so a single hook instance can operate on ids chosen at call time.
  ParamsForPath derives types directly from the schema's existing
  `params: {...}` declarations (no template-string parsing).
- Function-form `refresh: ({ args, result }) => ConcreteApiPaths[]` for
  invalidation keys that depend on trigger input or server response. Args
  are closure-captured at trigger entry to avoid races between concurrent
  calls.
- Explicit `/*` suffix for path-segment prefix matching on refresh and
  invalidate patterns, preserving the trailing slash so `/providers/*`
  doesn't match siblings like `/providers-archived`.

A single `resolveTemplate` function is the canonical path-replacement
point, so `useQuery('/providers/:id', { params: { id: 'abc' } })` and
`useQuery('/providers/abc')` produce byte-for-byte identical cache keys.

Dev-mode assertions flag invalid `/*` patterns (bare wildcard or missing
trailing slash) and warn on concurrent triggers against the same template
hook instance, which would share SWR mutation state.

Fully backward compatible: existing `refresh: ['/topics']` and
concrete-path hook calls compile and behave identically.
2026-04-20 09:02:57 -07:00
SuYao
b78f447e6f refactor(data-api): use greedy :uniqueModelId* for model route (#14359)
### What this PR does

Before this PR:

- The model item endpoint was keyed as `/models/:providerId/:modelId`.
This shape cannot address models whose `modelId` contains `/` (e.g.
`qwen/qwen3-vl`, `accounts/fireworks/models/deepseek-v3p2`) — real IDs
from OpenRouter/Fireworks/Qwen — because the router would split them
across the two params.
- `src/main/data/api/handlers/__tests__/models.test.ts` did not exist;
the models handler had no unit-test coverage.

After this PR:

- Route is now `/models/:uniqueModelId*`, the greedy form prescribed by
`docs/references/data/api-design-guidelines.md:48-98`. The path param is
typed `UniqueModelId`.
- The handler parses the single greedy param via `parseUniqueModelId` at
the transport boundary and delegates to the existing
`ModelService.getByKey/update/delete(providerId, modelId)` methods —
service signatures are preserved; only the handler layer is aware of the
composite id.
- New `models.test.ts` mirrors the existing `tags.test.ts` /
`fileProcessing.test.ts` patterns (mocked service,
`toHaveBeenCalledWith` + return-value pairing, error-propagation case).

Fixes #

### Why we need it and why it was done in this way

The greedy-param feature was added in `a2adc8fcc` specifically for
composite identifiers whose component can contain `/`. `UniqueModelId`
is exactly that shape (`providerId::modelId`), and the schema at
`src/main/data/db/schemas/userModel.ts` has already been migrated to a
single PK `id = "providerId::modelId"`. Aligning the API route with the
storage identity and the documented greedy pattern is the minimal,
idiomatic fix.

The following tradeoffs were made:

- Parsing stays at the handler boundary rather than being pushed into
`ModelService`. Drizzle still indexes the table on `providerId` +
`modelId` columns, and keeping the service signature unchanged limits
the blast radius of this change to one file on each side of the
transport.
- Malformed ids (missing `::`) surface as a thrown `Error` from
`parseUniqueModelId` — serialized by the API server's existing error
middleware. No bespoke 422 wrapping was added; the router itself is the
pre-validator.

The following alternatives were considered:

- Adding a `getById(uniqueModelId)` method on `ModelService` that parses
internally. Rejected — the service doesn't need to care about the
transport id shape, and the DB columns remain `providerId` + `modelId`.
- Keeping the two-param shape and URL-encoding `/`. Rejected — the
project's router does not decode params, per the guidelines.

Links to places where the discussion took place:

### Breaking changes

None user-visible. The renderer consumes this endpoint through the typed
DataApi client; the route-key change propagates via `ModelSchemas` type
inference. A repo-wide search found no template-literal call sites
constructing `/models/<providerId>/<modelId>` paths.

### Special notes for your reviewer

- `src/main/data/api/core/__tests__/ApiServer.test.ts` still references
`'/models/:providerId/:modelId'` as a generic example of composite-param
routing. Those assertions are about the router, not this endpoint —
intentionally left untouched.
- Verified locally: `pnpm test:main` (2266 pass), `pnpm typecheck`
(clean), `pnpm lint` (clean).

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: You have left the code cleaner than you found it (Boy
Scout Rule)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A user-guide update was considered and is present
(link) or not required. Check this only when the PR introduces or
changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code before requesting review
from others

### Release note

```release-note
NONE
```

---------

Signed-off-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:15:02 +08:00
SuYao
bd9e769b1a feat(data): add Tag entity DataApi with CRUD and entity-tag associations (#14234)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-17 18:11:35 +08:00
SuYao
0c6e62181b refactor(data): unify legacy model ID conversion and add FK references to user_model (#14257)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 21:50:48 +08:00
fullex
4ac451e292 feat(data-api): add temporary chat infrastructure
Introduce /temporary/* endpoints backed by an in-memory store so users
can draft chats without touching SQLite until they explicitly persist
or destroy the session. The persist path reuses the same topic id and
linearizes messages into the existing adjacency-list tree, so a
persisted temporary chat is indistinguishable from one created via the
persistent path (activeNodeId, FTS5 indexing, all fields aligned).

Exposes 5 endpoints: POST /temporary/topics, DELETE
/temporary/topics/:id, POST + GET /temporary/topics/:topicId/messages,
POST /temporary/topics/:id/persist. Schema types fully reuse the
persistent Topic / Message / CreateTopicDto / CreateMessageDto
definitions; unsupported fields (parentId, siblingsGroupId,
setAsActive, sourceNodeId, status='pending') are rejected at the
service boundary. Timestamps stored as ms numbers internally and
converted to ISO at the boundary to match the DB's integer columns.

Testing: unit tests cover DTO narrow, return shape, deep-clone
isolation, and persist (happy path / rollback / empty session);
handler mock tests verify parameter routing; a file-backed integration
test exercises the full handler -> persist -> messageService.getTree
readback and asserts FTS5 searchable_text auto-population.
2026-04-15 06:11:29 -07:00
SuYao
13b333e9b3 feat(v2): decouple assistant from topic with dedicated table and migration (#13851)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-13 12:55:06 +08:00
槑囿脑袋
798a15e919 feat(v2): knowledge service backend (#14090)
Co-authored-by: SuYao <sy20010504@gmail.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-10 21:24:06 +08:00
jidan745le
780a884c67 feat(data): provider/model data migration and registry service (backend only) (#14115)
### What this PR does

Before this PR:
- v2 migration did not include provider/model data migration from legacy
`llm` state.
- Provider/model data APIs and handlers were incomplete.
- `@cherrystudio/provider-registry` (formerly provider-catalog) package
was not integrated into the data layer.

After this PR:
- Add provider/model migration path (`ProviderModelMigrator` + mappings)
and register it in v2 migrator flow.
- Add `@cherrystudio/provider-registry` package with JSON-based registry
data, Zod-validated schemas, and lifecycle-managed
`ProviderRegistryService`.
- Complete provider/model schemas, services, handlers, shared API
schemas/types, and model merger utility.
- Complete provider API endpoints (`registry-models`, `auth-config`,
`api-keys`) aligned with lifecycle DI patterns.

**Note:** This PR is intentionally scoped to backend/data-layer only.
Renderer consumer migration will be submitted in a separate PR to
maintain domain separation.

Fixes #

N/A

### Why we need it and why it was done in this way

The following tradeoffs were made:
- Kept migration and data API implementation within current v2
architecture (handler -> service -> db schema) instead of adding
temporary compatibility layers.
- Replaced protobuf toolchain with JSON + Zod validation for simpler
data pipeline and better debuggability.
- Converted all numeric enums to string-valued `as-const` objects
(EndpointType, ModelCapability, Modality, etc.) for runtime
debuggability.
- Unified separate `baseUrls`, `modelsApiUrls`, `reasoningFormatTypes`
fields into a single `endpointConfigs` map keyed by EndpointType.

The following alternatives were considered:
- Keep protobuf-based registry data; rejected due to complexity of proto
toolchain and poor debuggability of binary data.
- Include renderer consumer migration in same PR; deferred to separate
PR for cleaner domain boundaries.

Links to places where the discussion took place:
- Original combined PR: #14034

### Breaking changes

None.

### Special notes for your reviewer

- This is a backend-only extraction from #14034, which contained both
backend and renderer consumer code. The renderer migration will follow
in a separate PR.
- Please focus review on migration flow (`ProviderModelMigrator`),
provider/model service contracts, and the registry package design.
- The `@cherrystudio/provider-registry` package was renamed from
`provider-catalog` and uses JSON data files instead of protobuf.

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: Not required (internal data layer, no user-facing
changes)
- [x] Self-review: I have reviewed my own code

### Release note

```release-note
NONE
```

---------

Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: suyao <sy20010504@gmail.com>
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-10 19:12:33 +08:00
亢奋猫
a83f98fd24 docs: consolidate bilingual docs, add link checker and architecture overview (#14138)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-09 16:01:40 +08:00
fullex
4832ab7742 refactor(data-api): remove temporary test endpoints
The /test/* namespace served as scaffolding to validate the DataApi
pipeline before real business endpoints landed. Real endpoints
(topics, messages, translate, knowledges, mcpServers, miniapps,
fileProcessing) are now registered, so the scaffolding is no longer
needed and is removed to cut noise and avoid being mistaken for a
reference implementation.

- Delete handlers/test.ts, services/TestService.ts, schemas/test.ts
- Remove TestSchemas from the ApiSchemas intersection and drop the
  related handler spread and type re-exports
- Update JSDoc and api-types.md examples to reference real schemas

Signed-off-by: fullex <0xfullex@gmail.com>
2026-04-08 02:46:55 -07:00
hello_world
2851f4e68c rerefactor(miniapp): Miniapp V2 (#13468)
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-04-04 16:19:58 +08:00
槑囿脑袋
e08016c5ef Refactor(v2): add knowledge db schema (#13640)
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
2026-03-30 16:47:39 +08:00
SuYao
24dc1ce663 feat(v2): add MCP Server data API service and migrate renderer to v2 hooks (#13734)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 23:08:05 +08:00
Phantom
02945ec2b4 refactor(data): add type-safe return types to renderer DataApiService (#13748)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:57:18 +08:00
槑囿脑袋
72c5c1903a feat: v2 file processing db schema (#13328)
Co-authored-by: suyao <sy20010504@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:40:58 +08:00
Phantom
4ca6f56ec9 feat(data): add translate history and language backend API with langCode PK (#13739)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:29:14 +08:00
fullex
b8789a0ee8 feat(apiErrors): add CONFLICT error code and details for resource conflicts
- Introduced a new error code `CONFLICT` (409) to handle resource conflicts, such as duplicate names or unique constraint violations.
- Updated the `ERROR_STATUS_MAP` and `ERROR_MESSAGES` to include the new `CONFLICT` error.
- Added `ConflictErrorDetails` interface to provide additional context for conflict errors.
- Implemented a `conflict` method in `DataApiErrorFactory` to create conflict errors with relevant details.

This enhancement improves error handling for scenarios where resource conflicts occur.
2026-03-23 05:11:37 -07:00
fullex
12e62782b1 feat(api): introduce success status constants and enhance handler response behavior
- Added `SuccessStatus` constants to standardize success status codes (200, 201, 202, 204) and improve type safety.
- Updated API handler to support custom status codes by returning `{ data, status }` format.
- Enhanced automatic status code inference based on HTTP methods in the API server.
- Updated documentation to reflect new status handling guidelines and examples.
2026-01-14 14:38:07 +08:00
fullex
7cac5b55f6 feat: enhance cursor-based pagination in API documentation and types
- Added detailed explanations and examples for cursor semantics in `api-types.md`, clarifying the exclusive nature of cursors in pagination.
- Updated `CursorPaginationParams` interface to emphasize the cursor's role as an exclusive boundary in responses.
- Refactored `BranchMessagesQueryParams` to extend `CursorPaginationParams`, aligning with the new pagination logic.
- Modified `MessageService` to implement cursor-based pagination semantics, ensuring accurate message retrieval and response structure.
- Enhanced documentation throughout to provide clearer guidance on pagination behavior and usage patterns.
2026-01-04 22:31:15 +08:00
fullex
81bb8e7981 feat: implement new pagination types and enhance API documentation
- Introduced `OffsetPaginationParams`, `CursorPaginationParams`, and their corresponding response types to standardize pagination handling across the API.
- Updated existing API types and hooks to support both offset and cursor-based pagination, improving data fetching capabilities.
- Enhanced documentation with detailed usage examples for pagination, including request parameters and response structures, to aid developers in implementing pagination effectively.
- Refactored related components to utilize the new pagination types, ensuring consistency and clarity in data management.
2026-01-04 21:12:41 +08:00
fullex
b01113aae6 feat: enhance pagination support in API types and hooks
- Introduced new pagination types and interfaces, including `PaginationMode`, `BasePaginatedResponse`, `OffsetPaginatedResponse`, and `CursorPaginatedResponse`, to standardize pagination handling.
- Updated `useDataApi` hook to support both offset and cursor-based pagination, improving data fetching capabilities.
- Added `useInfiniteQuery` and `usePaginatedQuery` hooks for better management of paginated data, including loading states and pagination controls.
- Refactored existing pagination logic to improve clarity and maintainability, ensuring consistent handling of pagination across the application.
2026-01-04 15:52:18 +08:00
fullex
f1b9ab4250 feat: enhance CreateMessageDto and MessageService for improved parentId handling
- Updated CreateMessageDto to include detailed behavior for the parentId field, allowing for auto-resolution based on topic state, explicit root creation, or attachment to a specified parent message.
- Refactored MessageService to implement the new parentId logic, ensuring proper validation and error handling for message creation based on the topic's current state and existing messages.
- Enhanced transaction safety and clarity in the message insertion process by resolving parentId before inserting new messages.
2026-01-03 22:47:44 +08:00
fullex
01d8888601 feat: extend UpdateMessageDto with traceId and stats fields
- Added optional fields `traceId` and `stats` to the `UpdateMessageDto` interface for enhanced message tracking and statistics.
- Updated `MessageService` to handle the new fields during message updates, ensuring they are correctly processed in the database.
2026-01-03 18:52:11 +08:00
fullex
819c209821 docs(data): update README and remove outdated API design guidelines
- Revised the README files for shared data and main data layers to improve clarity and structure.
- Consolidated documentation on shared data types and API types, removing the now-deleted `api-design-guidelines.md`.
- Streamlined directory structure descriptions and updated links to relevant documentation.
- Enhanced quick reference sections for better usability and understanding of the data architecture.
2025-12-29 17:15:06 +08:00