26 Commits

Author SHA1 Message Date
程序员阿江-Relakkes 8d1548e62c feat(desktop): per-format file icons, and fixes for workspace open, web images and xlsx widths (#1419)
* feat(desktop): show per-format file icons on chat file cards

Generated-file cards, the turn change card and message attachments used
one grey Material glyph for every file. They now render a folded-corner
document icon with a colored body and the extension label (PDF red,
Word blue, Markdown blue, Excel green, PowerPoint orange, archives
amber, code purple, ...), built on react-file-icon instead of
hand-drawn art. Extensions the library does not know are mapped to a
close sibling or to a category color, and jsonl now counts as code.

Brand colors live in lib/fileTypePalette.ts because react-file-icon
writes them into SVG attributes, where CSS variables are not reliable.

* fix(desktop): open workspace documents written through a symlinked path

Clicking an output card for /tmp/app/report.pdf opened the system app
instead of the workspace preview when the session's canonical workdir is
/private/tmp/app. The gate compared path strings, so a symlinked form,
a workdir that had not loaded yet, or a registered access root all
looked like "outside the workspace".

The string check stays as the fast path. When it says "outside", ask the
server through getWorkspaceFile, which resolves real paths: an accepted
document opens in the workspace, a 403 still goes to the system app.

* fix(desktop): load local images in the web UI and H5

A bare <img src> cannot send Authorization, and the server refuses a
credential-less cross-site subresource load, so the browser blocked the
response (net::ERR_BLOCKED_BY_ORB) and chat showed "unable to load
image". Only the Electron shell worked, because its main process injects
the credential for an allowlist of media routes.

When an <img> fails, retry once through the credentialed client and show
the result as a blob: URL; the failure notice appears only if that also
fails. Covers the inline image gallery, the lightbox, image generation
slots and Markdown images. The credential is only ever sent to the local
server's own origin.

* fix(desktop): keep spreadsheet numbers whole in the workspace preview

Columns without a stored width fell back to a fixed 72px, and stored
widths were chosen for Excel's font, which is narrower than the
preview's. Values such as 12,000.00 were clipped to "12,000...".

A column the file gives no width now fits its widest cell, and a number
column never ends up narrower than its numbers. Text in a column whose
width the file sets is still clipped, as Excel clips it, and merged
headings that spill over their span do not widen a column.
2026-10-01 15:22:13 +08:00
程序员阿江(Relakkes) 6bab6fbe97 feat(desktop): preview documents in the workspace and images in chat
Documents the agent writes open in the workspace panel instead of another
application, and local images the agent mentions show up in the conversation.

Workspace preview
- PDF (pdf.js with its own layout and text layer), Word (docx-preview inside a
  scripts-disabled sandboxed iframe) and Excel (SheetJS; .xlsx, .xlsm, .xls) open
  in the side panel with zoom and fit, per-file scroll/zoom/sheet memory, and a
  refresh when the agent rewrites the file. The engines load lazily.
- Bytes come from a new GET /api/sessions/:id/workspace/raw route, with an
  extension allowlist, size caps, the workspace boundary and canonical-path
  checks. The file endpoint returns metadata and a version for documents. The
  client fetches with the bearer credential, so it works in Electron, LAN H5 and
  remote access alike.
- Chat links, output cards and the change card open pdf/docx/xlsx in the
  workspace; documents outside the workdir still go to the system application.
- Image viewer with fit, zoom and pan, and "open in system app".

Chat images
- Markdown images outside the workdir, at ~/, C:\ and file:// paths render, open
  in the viewer, and offer "open original" (pictures only).
- Images returned by tools such as Read appear as thumbnails under the call.

Hardening found in review
- previewFsUrl escapes each path segment; a double-escaped %2e%2e used to leave
  /preview-fs/<session>/.
- The CORS, API timing and remote-access header decorators set headers in place.
  Rebuilding the response buffered whole files in memory and dropped
  Content-Length.
- The engine owns the pdf.js worker, so closing one document no longer fails the
  next open.
- Office archives are inflated in steps to check their real sizes, not the sizes
  they declare.
- A viewer that fails to load stays in its panel instead of taking the window down.

Adds pdfjs-dist, docx-preview, xlsx (SheetJS 0.20.3 tarball) and fflate as
renderer dev dependencies; Vite bundles them.

Refs #1397
2026-09-30 01:53:47 +08:00
程序员阿江(Relakkes) 9fce822df3 feat: add secure ngrok remote access with device pairing 2026-09-13 23:28:30 +08:00
程序员阿江(Relakkes) 57feabde05 fix(desktop): align terminal themes and streamline workspace controls 2026-09-13 22:10:30 +08:00
vzionv 4b181facc4 fix: preserve tool result media across provider and MCP paths 2026-09-06 22:33:53 +08:00
程序员阿江(Relakkes) a554622086 Merge main into worktree-20260803001-qa-reactor
Two real conflicts, one of them structural.

desktop/src/pages/Settings.tsx — git offered the whole 4128-line pre-split file
as "theirs" against the 183-line shell, which is not a merge anyone can review.
Resolved by keeping the split and porting main's nine hunks to where that code
now lives: the rail width, its comment and TabButton's padding stay in
Settings.tsx; the ModelIdCombobox import and the five ProviderFormModal changes
(the canFetchModels split into hasModelsBaseUrl/hasModelsApiKey, modelPickerItems
becoming modelPickerGroups, the two new hint branches, and the Input+Dropdown pair
collapsing into ModelIdCombobox) go to settings/ProviderSettings.tsx.

Verified rather than assumed: every line main added is present somewhere in the
split, every construct it removed is gone (modelPickerItems, canFetchModels =
Boolean(...), the supplementary Dropdown), and the import specifier gained the
level the new directory needs.

desktop/package.json — taking main's version wholesale dropped the eslint setup
from f36c9cb49. Reconstructed with both sides: main's six prosemirror packages and
the three eslint devDependencies, with lint back to eslint + tsc.

Everything else merged clean, including the files both sides touched:
src/server/ws/handler.ts (main's four title-generation changes all sit in code the
three splits left behind), desktop/src/stores/chatStore.ts (main's mention/
repository-launch state alongside the turn-scoped replay guard), and the five
locales — 2526 - 9 removed + 5 added = 2522, still aligned across all languages.

Checks: desktop lint + 4049 tests + build, check:electron, check:policy all green.
The one server failure, workspace-service.test.ts "rejects a file outside the
workdir", fails identically on main — confirmed against a temporary worktree at
main, which fails it plus three more. It passes 3/3 in isolation; the registry it
asserts on is a module-level Set shared across test files.
2026-08-04 15:46:41 +08:00
程序员阿江(Relakkes) f36c9cb495 ci(desktop): lint React hook rules alongside types
`bun run lint` was `tsc --noEmit` alone. tsc types the code but knows nothing
about React's rules, which is how a conditional useMemo sat in
AskUserQuestion.tsx long enough to be a latent crash — the fix in cf5200922.

One rule, react-hooks/rules-of-hooks, as an error. It is the one React rule with
no judgement in it: a conditional hook is always a bug, never a preference, so
it needs no suppressions and the tree is already at zero.

exhaustive-deps stays off. It has 27 hits here, most deliberate, and a
permanently-yellow lint is one nobody reads. The 13 existing eslint-disable
comments name rules this config does not enable, so unused-directive reporting
is off too — they are dormant records of intent, not mistakes.
2026-08-04 12:44:44 +08:00
程序员阿江(Relakkes) 0c9dc0edd5 feat(desktop): inline @-mentions as ProseMirror pills in the composer
The composer was a plain textarea, so @-selected files and folders could
not render inline: they became attachment chips above the input and were
sent as a detached @"path" prefix. The composer now runs on ProseMirror
(ChatGPT desktop's architecture): @ selections insert an inline mention
pill (an atom node carrying label/path/isDirectory), and the pill is
serialized back to the @"absolute path" text the CLI already parses at
its exact position in the prompt.

- MentionComposer + composerEditor: schema, doc<->projection mapping,
  controlled bridge (doc changes project to text+mentions; external
  writes rebuild the editor state, resetting undo history), single-
  backspace whole-pill deletion, placeholder/disabled/aria plumbing
- composerMentions: tokenOrdinal keeps pills distinct from literal text
  that happens to spell the same token, so serialization and rebuilds
  never rewrite the wrong occurrence
- ChatInput and EmptySession composers both migrated; drafts persist
  mentions; drag-and-drop attachment chips unchanged
2026-08-03 21:57:03 +08:00
程序员阿江(Relakkes) e9b53f6848 revert(desktop): roll back the shadcn UI migration, keep backend hardening
The shadcn migration (ad597ffe) and its follow-up (5b4e224f) were
mega-commits: only ~16% of the insertions were UI work. Rolling either
one back wholesale also deletes ~3400 lines of unrelated server,
Electron, and store hardening -- and because each of those changes
shipped with its own tests, the suite stays green while the hardening
silently disappears.

This rolls back the UI layer only.

Reverted (back to c2774fc1):
- desktop/src/components, pages, features, theme, i18n
- components/ui/**, components.json, src/lib/utils.ts (cn helper)
- radix-ui, class-variance-authority, tailwind-merge deps
- src-tauri/src/lib.rs hardening: dead code, nothing compiles it
  (no @tauri-apps dep, no cargo invocation anywhere, and
  scripts/pr/release-workflow.test.ts asserts Tauri's absence)

Kept (identical to main):
- src/** -- WhatsApp authDir escape allowing arbitrary recursive
  directory removal, computer-use tier bypass granting every
  pre-authorized app full tier, plugin uninstall keepData inversion
  that deleted data when asked to keep it, plugin project-scope
  writing to the sidecar cwd, diagnostics share leaking provider
  config, memory API TOCTOU plus atomic writes
- desktop/electron/** -- PTY leak on renderer destruction, IPC
  boundary validation rejecting NaN and unbounded input
- desktop/src/stores/** -- request-id race guards
- desktop/src/api, lib/desktopHost -- kept in step with the stores

Follows main's b64069a3 in dropping the installed-skills overview.

Updated two memorySettings assertions to expect the optimistic-lock
fields the retained memory store sends.

check:desktop pass (lint clean, 225 files / 2519 passed / 1 skipped,
build ok). check:server pass (224 files / 2375 passed / 0 failed).
2026-07-25 21:05:02 +08:00
程序员阿江(Relakkes) ad597ffe0b feat(desktop): unify UI with shadcn components (#1089) 2026-07-24 23:59:48 +08:00
程序员阿江(Relakkes) 727bcea077 fix(desktop): harden Windows crash recovery #1064 #1065 #1071 2026-07-20 22:06:34 +08:00
程序员阿江(Relakkes) 01d8691673 fix(providers): make provider list sortable (#753)
Render provider settings through dnd-kit sortable rows, include official providers in the same order model, and persist providerOrder across server and desktop state.

Tested:

- bun test src/server/__tests__/providers.test.ts src/server/__tests__/persistence-upgrade.test.ts

- cd desktop && bun run test -- --run src/stores/providerStore.test.ts src/__tests__/generalSettings.test.tsx -t "providerStore reorderProviders|Settings > Providers tab"

- cd desktop && bun run lint

- cd desktop && bun run build

- bun run check:persistence-upgrade

Not-tested:

- bun run check:server (broad suite hit environment failures during this run: MCP stdio zshrc timeout, adapter dependency gap at the time, and e2e cascade)

Confidence: high

Scope-risk: moderate
2026-06-13 08:07:36 +08:00
程序员阿江(Relakkes) 81845fbc49 fix: finalize Electron migration boundaries
Complete the Electron replacement boundary before merging by removing the renderer-side Tauri host fallback, tightening H5/browser access so only desktop navigation is tokenless, and moving desktop release publication to a tag-driven GitHub Actions matrix with a single final publish job.

Constraint: H5/browser capability access must not gain tokenless access through localhost or retired Tauri origins

Constraint: Desktop release artifacts must be built by GitHub Actions from version tags, not treated as local build outputs

Rejected: Keep localhost browser origins trusted for convenience | local browser contexts can access loopback services and must use the H5 token path

Rejected: Publish from each matrix job | partial releases can be created before all platforms finish

Confidence: high

Scope-risk: broad

Directive: Do not reintroduce Tauri origins or localhost browser origins into the trusted desktop origin set without a reviewed security design

Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/__tests__/diagnostics-service.test.ts src/server/middleware/cors.test.ts

Tested: bun test scripts/pr/release-workflow.test.ts scripts/release-update-metadata.test.ts

Tested: bun run check:desktop

Tested: bun run check:native

Tested: git diff --check

Not-tested: bun run check:server is blocked by expired quarantine entries server:cron-scheduler, server:providers-real, server:tasks, server:e2e:business-flow, server:e2e:full-flow
2026-06-02 22:42:53 +08:00
程序员阿江(Relakkes) 386a41e606 feat(desktop): enable Electron migration path
Introduce the Electron desktop shell alongside the existing React renderer and local Bun server boundary. The migration keeps the DesktopHost contract explicit across Tauri, Electron, and browser runtimes while adding Electron main/preload services for dialogs, shell, notifications, updates, tray/window lifecycle, terminal, preview WebContentsView, app mode, and release/package validation.

The commit also carries the latest local main desktop command updates, including agent slash entries and hidden-by-default markdown thinking details, so the packaged Electron build matches the current main UX surface.

Constraint: React renderer, local Bun server, REST/WebSocket, and sidecar boundaries must remain reusable during the migration
Constraint: macOS dev packages are ad-hoc signed and cannot prove Developer ID notarization or Gatekeeper release launch
Rejected: Browser-only smoke validation | it cannot exercise native dialogs, keychain prompts, notification behavior, or packaged app startup
Confidence: medium
Scope-risk: broad
Directive: Do not remove Tauri host support until signed Electron release artifacts pass native OS smoke on macOS, Windows, and Linux
Tested: bun run check:desktop
Tested: cd desktop && bun run check:electron
Tested: CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir
Tested: bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electron
Tested: Computer Use read packaged Electron app window at desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app
Not-tested: Developer ID signed/notarized Gatekeeper launch
Not-tested: Real OS notification click-to-session action
Not-tested: Windows and Linux packaged app smoke on real hosts
2026-06-01 22:43:16 +08:00
程序员阿江(Relakkes) 26018fa40b feat(desktop): in-page screenshot capture via html2canvas (mock-tested; real-engine validation deferred)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 17:40:45 +08:00
程序员阿江(Relakkes) 4fce6014a6 fix: preserve Shiki code rendering with legacy fallback
Code blocks should keep the richer Shiki rendering in modern WebUI while avoiding the old WebKit startup crash path by loading Shiki lazily and falling back to Prism only when the runtime cannot safely parse or execute it.

Constraint: Issue #461 is triggered by older Safari/WebKit parsing modern RegExp syntax during startup.
Rejected: Replace Shiki entirely with Prism | visual quality regressed for normal WebUI usage.
Confidence: high
Scope-risk: moderate
Directive: Keep Shiki out of the startup path unless macOS 12 WebView compatibility is re-verified.
Tested: cd desktop && bun run test -- --run src/components/chat/CodeViewer.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: Real WebUI smoke on http://127.0.0.1:1420/ verified six code blocks rendered with data-highlight-engine=shiki.
Not-tested: Physical macOS 12 WebView runtime.
Related: https://github.com/NanmiCoder/cc-haha/issues/461
2026-05-22 17:55:33 +08:00
程序员阿江(Relakkes) 7d2836643c Render model math as readable desktop markdown
Desktop assistant responses previously showed LaTeX source for common
model outputs. The markdown renderer now extracts math outside code spans
and fences, renders it through KaTeX, and applies chat-safe layout rules
for inline, block, multiline, matrix, and long-form formulas.

Constraint: Desktop chat already forces long markdown text to wrap, so KaTeX internals must opt out of that wrapping while display blocks handle overflow locally
Rejected: Render all dollar-delimited text blindly | currency and escaped dollar text would become false-positive formulas
Confidence: high
Scope-risk: narrow
Directive: Keep math extraction before marked parsing and preserve code fence protection when extending markdown rendering
Tested: bun run test --run src/components/markdown/MarkdownRenderer.test.tsx
Tested: bun run lint
Tested: bun run build
Tested: WebUI complex formula screenshot and 390px viewport overflow check
Not-tested: Full desktop gate still has unrelated /goal command hint expectation drift
2026-05-16 13:29:08 +08:00
程序员阿江(Relakkes) 9719726cd2 feat: make quality gates observable and enforceable
The repository now has a measurable PR quality path instead of a loose set of
manual checks. Coverage, quarantine governance, provider smoke, desktop smoke,
and workflow wiring all produce durable reports that contributors and maintainers
can inspect without reconstructing terminal output.

This also fixes the desktop smoke current-runtime path so browser-driven smoke
runs use the desktop default active provider instead of forcing the official
current model, and records that runtime decision as an artifact.

Constraint: Default PR gates must remain non-live and contributor-safe while live model checks stay explicit.
Constraint: Release packaging is still GitHub Actions based, so release preflight must run before the build matrix.
Rejected: Make live provider or desktop smoke mandatory on every PR | secrets, quotas, and model availability are maintainer-controlled.
Rejected: Let PRs lower coverage baselines in the same change | base-branch ratchet comparison must remain authoritative.
Confidence: high
Scope-risk: moderate
Directive: Do not relax coverage or quarantine policy without a maintainer approval label and a fresh quality report.
Tested: ALLOW_CLI_CORE_CHANGE=1 ALLOW_COVERAGE_BASELINE_CHANGE=1 bun run quality:gate --mode pr
Tested: bun run quality:gate --mode baseline --allow-live --only provider-smoke:* --provider-model nvidia-custom:main:nvidia-custom-main --artifacts-dir /tmp/quality-gate-live-smoke
Tested: bun run quality:gate --mode baseline --allow-live --only desktop-smoke:* --provider-model current:current:current-runtime --artifacts-dir /tmp/quality-gate-desktop-smoke-fixed
Tested: git diff --check
Not-tested: Full live release mode with multiple providers in hosted CI; provider credentials and quota remain maintainer-controlled.
2026-05-06 16:25:10 +08:00
程序员阿江(Relakkes) 8a81636757 Merge Azure OpenAI auth into local main
Remote main already contains PR #217. Local main had provider context-window and auth-strategy work, so this merge keeps both context resolvers and reconciles the desktop Bun lockfile with the merged desktop package manifest. The accidental remote .nvimlog artifact is excluded from the merge result.

Constraint: Local main was 15 commits ahead and 8 commits behind origin/main after PR #217 was merged remotely
Rejected: Fast-forward pull | local main had unpushed commits
Rejected: Keep remote desktop lockfile verbatim | failed bun install --frozen-lockfile against the merged package.json
Confidence: high
Scope-risk: broad
Directive: Keep provider-configured context windows ahead of OpenAI OAuth model windows so explicit user/provider settings win
Tested: bun install --frozen-lockfile; cd desktop && bun install --frozen-lockfile; git diff --check; bun run check:server; bun run check:desktop; ALLOW_CLI_CORE_CHANGE=1 bun run quality:pr
Not-tested: live provider OAuth login with a real OpenAI account
2026-05-04 21:24:22 +08:00
cynicalight ff40028ae1 fix: desktop and more test 2026-05-04 17:57:03 +08:00
程序员阿江(Relakkes) 2ca5228171 feat: make IM adapter behavior consistent
WeChat and DingTalk were using different pairing, attachment, and response
state paths, which made the new IM channels behave differently from Feishu
and Telegram. Align the shared pairing model, wire inbound media into the
existing attachment bridge, and map platform response capabilities to their
real APIs: WeChat block streaming plus typing, DingTalk AI Card streaming.

Constraint: WeChat iLink exposes typing and block streaming, but no editable message/card streaming API
Constraint: DingTalk streaming depends on the AI Card create/deliver/stream/finalize lifecycle
Rejected: Fake DingTalk typing with standalone markdown | it would add chat noise instead of platform state
Rejected: Auto-pair WeChat after QR login | it bypasses the shared IM pairing model
Confidence: high
Scope-risk: moderate
Directive: Keep WeChat streaming as block-send unless iLink adds editable messages; keep DingTalk streaming on AI Card APIs
Tested: bun run check:adapters; bun run check:server; cd desktop && bun run test src/stores/adapterStore.test.ts; cd desktop && bun run build; bunx tsc -p adapters/tsconfig.json --noEmit; git diff --check
Not-tested: Live WeChat and DingTalk platform smoke with real production credentials
2026-05-03 21:08:12 +08:00
程序员阿江(Relakkes) fa5fda24d0 feat: notify users when desktop attention is needed
Add native system notifications as a desktop-wide attention channel for permission prompts and scheduled task completion. The implementation keeps notification presentation owned by the OS, adds a user-facing enable switch with permission handling, and lets scheduled tasks choose desktop notifications without routing that channel through IM adapters.

Constraint: Notifications must use OS-native APIs without custom sound playback.
Constraint: Desktop channel is local-only and must not be sent through IM adapter delivery.
Rejected: Browser Notification API | not reliable inside the packaged Tauri desktop runtime.
Rejected: Treat desktop as an IM channel | would leak a local-only channel into server-side adapter sending.
Confidence: high
Scope-risk: moderate
Directive: Keep notification styling at the OS layer; business code should only provide title, body, dedupe, and routing decisions.
Tested: bun run check:desktop
Tested: bun run quality:pr
Tested: Computer Use macOS debug app verification for settings toggle, permission prompt, scheduled task desktop channel, and task-run polling dedupe
Not-tested: Windows and Linux native runtime smoke tests on physical hosts
2026-05-03 16:45:32 +08:00
程序员阿江(Relakkes) 0c58a9f36f Give desktop users a real terminal for command-based setup
Some setup flows end in a shell command instead of a natural-language install path, so Settings now exposes a host PTY terminal backed by portable-pty and xterm. The terminal inherits the user's login-shell environment, forces a UTF-8 locale when needed, and preserves split UTF-8 output so Chinese paths render correctly.

Constraint: Desktop GUI apps do not inherit the user's interactive shell PATH on macOS.
Constraint: Command output may split UTF-8 characters across PTY reads.
Rejected: Use Tauri shell commands only | users need an interactive PTY for copy-pasted install flows.
Rejected: Ask users to edit shell profiles | terminal setup should work out of the box.
Confidence: high
Scope-risk: moderate
Directive: Keep terminal startup tied to host environment checks; do not bundle runtimes to solve PATH issues.
Tested: cargo fmt --check; cargo test --lib; cargo check; cd desktop && bun run lint; cd desktop && bun run test src/pages/TerminalSettings.test.tsx; cd desktop && bun run build; cd desktop && bun run build:macos-arm64
Tested: Computer Use verified npm is available in the built macOS app terminal and Chinese output renders after UTF-8 decoding fix.
Not-tested: Native Windows/Linux package runtime validation.
2026-04-24 09:36:00 +08:00
程序员阿江(Relakkes) 8888e1c3fb chore: comprehensive code review fixes — security, perf, leaks, quality, docs
- security: XSS sanitization with DOMPurify in Markdown/Mermaid/PermissionDialog;
  path whitelist in filesystem API; fake keys in test/config files
- perf: fine-grained Zustand selectors in Sidebar/StatusBar/ContentRouter;
  50ms throttle on streaming deltas; React.memo + useMemo in MessageList;
  useRef for frequent keyboard shortcut state; AbortController 30s timeout
- leaks: WS session TTL timers (5-min cleanup on close); batch splice for
  sdkMessages/stderrLines; folderPath validation in cronScheduler
- quality: optimistic update rollback in settingsStore; error state in
  providerStore/teamStore; i18n for all hardcoded English strings
- docs: desktop architecture and features docs updated; VitePress nav fixed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 22:27:17 +08:00
程序员阿江(Relakkes) 635a966c3e fix(desktop): unblock rollout with reliable session and IM flows
This folds together the desktop-side fixes needed before broader rollout.
Session resume no longer deadlocks waiting on init, Mermaid and inline image
output render inside chat, task and sub-agent state stay visible during
execution, local build/release paths are safer, and Feishu/Telegram now expose
lightweight mobile commands (/help, /status, /clear) without adding a new
adapter-specific protocol.

Constraint: Desktop releases must publish updater artifacts from non-draft GitHub releases
Constraint: IM commands need short, phone-friendly responses and low operational complexity
Rejected: Add a dedicated IM command API surface | re-used existing slash commands and session/task REST endpoints to keep adapters thin
Rejected: Wait for task_update push events in WebUI | added low-risk polling because the current frontend ignores that event path
Confidence: medium
Scope-risk: broad
Reversibility: clean
Directive: Keep IM command replies terse and mobile-first, and merge local fallback slash commands when server-provided lists are partial
Tested: cd desktop && bun x vitest run src/components/chat/MermaidRenderer.test.tsx src/components/markdown/MarkdownRenderer.test.tsx
Tested: cd desktop && bun x vitest run src/components/chat/composerUtils.test.ts src/pages/ActiveSession.test.tsx src/stores/chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "SDK init arrives only after the first user turn" --timeout 60000
Tested: cd adapters && bun test common/ feishu/ telegram/
Tested: cd adapters && bunx tsc --noEmit
Not-tested: Full GitHub Actions release run on all three desktop platforms
Not-tested: Local DMG packaging end-to-end on Apple Silicon
Not-tested: Real Feishu/Telegram device sessions against a live adapter process
2026-04-10 16:41:59 +08:00
程序员阿江(Relakkes) 7983cce478 feat(desktop): add CI/CD release pipeline, auto-updater, and installation guide
- Add GitHub Actions workflow for 5-platform builds (macOS ARM/x64, Linux x64/ARM64, Windows x64)
- Integrate tauri-plugin-updater with signing key and UpdateChecker UI component
- Add version management release script (scripts/release.ts)
- Add installation guide with Gatekeeper/SmartScreen bypass instructions
2026-04-10 11:00:46 +08:00