简体中文 | English
# dsh-openwiki
> A DSH plugin that brings [openwiki](https://github.com/langchain-ai/openwiki)'s codebase knowledge-base capability into DeepSeek Harness — generate / read / update repository Wiki and Grounded Claims (traceable knowledge cards) in one click, **reusing the model already configured in DSH**, no need to enter an API key again.
`dsh-openwiki` is a **Web-profile package plugin** for DeepSeek Harness (a Cordis all-plugin architecture): the Host half hosts the openwiki CLI runtime and drives generation jobs, while the Client half provides the knowledge-base entry, floating window, directory tree and document reading UI in the DSH main interface. The core idea is to **treat openwiki as an incremental generation engine** (CLI + disk-artifact contract); the DSH side owns UI, job orchestration, model bridging and triggers.
***
## 📑 Table of Contents
* [🚀 Installation](#-installation)
* [🛠️ Development & Maintenance](#-development--maintenance)
* [✨ Feature Overview](#-feature-overview)
* [🧱 Architecture](#-architecture)
* [🖼️ Feature Tour](#-feature-tour)
* [🧠 Key Logic](#-key-logic)
* [📡 RPC API](#-rpc-api)
* [⚠️ Known Limitations](#-known-limitations)
* [🧪 Verification Scripts](#-verification-scripts)
***
## 🚀 Installation
Prerequisites: Node ≥ 20, openwiki CLI (the plugin can install it automatically), DSH model + credentials configured.
### Option 1: npm package (recommended)
```powershell
dsh plugin --profile web add dsh-openwiki
```
### Option 2: Local source
```powershell
# 1. Get the source into any local directory (referred to as below)
git clone
# 2. Build the artifacts (lib/ and client/)
cd
npm run build
# 3. Install into the DSH web profile as a local directory
dsh plugin --profile web add
```
### Post-install configuration (same for both options)
```powershell
# Edit \profiles\web\cordis.patch.yml, append:
# - id: dsh-openwiki
# name: 'dsh-openwiki'
# Restart dsh web
```
> Notes:
>
> * When installing from a local directory, `dsh plugin add` links the profile's `node_modules` entry to `` (pnpm's default behavior for directory installs); edit source + `npm run build`, then restart dsh web to load the new bundle
>
> * `dsh.profile.bundles` must include `dsh-openwiki` (dsh.client manifest: platform web, peerDependency schemastery)
***
## 🛠️ Development & Maintenance
### Directory Layout
```
/
├── src/host/index.js # Host authoritative source (shared by dynamic & package forms)
├── src/client/index.js # Client authoritative source
├── scripts/build-host.mjs # → lib/index.js (ESM entry)
├── scripts/build-client.mjs # → client/client.js (ModuleLoader bundle)
├── lib/ client/ # build artifacts
├── tests/ # Playwright / offline verification scripts + screenshots/
└── package.json # dsh.client manifest (platform web)
```
### AI-Facing Notes
* **Build script rewrites**: build-host rewrites `harness.handle` → `rpc.handle` and injects `webServer`/`settings`; build-client rewrites `host.call` → `rpc.call`. Use `harness.handle(...)` for new Host handlers and `host.call(...)` for new Client interactions; the build adapts automatically.
* **readBytes limit**: `fs.readBytes` throws when the file exceeds maxBytes (it does not truncate) — read file heads with `readText` + slice.
* **Missing manifest is the norm**: all wiki reads must go through the disk-scan fallback (`readWikiTree`/`readWikiOverview`/`readWikiClaims`).
* **Shim EPERM**: on Windows do not spawn `.cmd`; parse the script path inside the shim and spawn node directly.
* **not found stays silent**: optional state files (`.page-manifest.json`/`.run.json`/`.last-update.json`) missing must not `console.error`, or polling will spam.
* **settings namespace**: `settings.register('openwiki', schema)` depends on `@deepseek-ai/schemastery`, whose dynamic import from the profile may fail (`settings namespace skipped`) — do not rely on it; use in-memory state + localStorage.
* **Client service registry is rebuilt on every refresh**: the better-sidebar registration must auto-re-register (autoRegisterSidebar), never depend on a user click.
* **openwiki has no git trigger**: auto-update relies on the plugin polling `git rev-parse HEAD`.
* **Non-git repos cannot be generated**: `startJob` pre-checks and returns a clear error.
* **Markdown rendering**: the fence detection must be `startsWith('```')` (see the hang lesson under «🧠 Key Logic»).
* **Performance**: idle polling only refreshes jobs + overview (lightweight); full `refreshWorkspace` only while a job is running — avoid a full disk scan every 3s.
***
## ✨ Feature Overview
* **📚 Knowledge-base entry**: the "openwiki知识库" entry above the "Settings" button in the DSH bottom-left (can be hidden, persisted in `localStorage`), opening a draggable/resizable **floating window**; plus a `conversation.view` session-view tab and a better-sidebar side page as two more embedded forms. **The workspace list is re-fetched whenever the knowledge base opens or the "Refresh" button is clicked** (a workspace added afterwards shows up without a page reload).

* **🗂️ Three-mode views**: three persistent tabs — `Open Wiki` (repo Wiki document tree), `知识卡片` (Grounded Claims traceable points) and `知识库` (personal-mode knowledge base) — with selected highlight; plus "忽略文件" (ignore file) and "Refresh" buttons; the left column width is draggable.

* **🧠 Knowledge base (personal mode)**: the third tab `知识库` — upload local files (text formats, with a file-type hint; add/remove file behavior is described under the "生成知识库" button) to build a personal knowledge base at `/openwiki-kb/wiki` (via `OPENWIKI_CONFIG_DIR` injection); the tree reader reuses the document view. **Model credentials stay single-sourced**: they are injected from `~/.openwiki/.env` into the child process — nothing is duplicated in the project, and one `.gitignore` line for `openwiki-kb/` excludes every personal artifact.

* **📄 Document reading**: preview / code dual views + **TOC split pane** (click "目录" to split a left TOC panel beneath the toolbar, with its own vertical scrollbar, sticky and not scrolling with the body; clicking an entry smooth-scrolls to the heading).


* **🗂️ Knowledge cards**: Grounded Claims traceable points (statement + evidence), viewed from the "知识卡片" tab.

* **🔗 In-app link navigation**: internal md links (including `/openwiki/...` absolute paths) navigate within the app on click, never taking the browser to a `file://`; folder links (trailing `/`) enter folder browse.
* **⚡ Generation jobs**: generate / regenerate (incremental update) / cancel with live progress (`已完成 X/Y (Z%),处理中: N,失败: M`), resumable via openwiki's `.run.json`; non-git repos get a clear error.
* **📊 Generation status card**: the right panel shows file count / success / failure / last update / document location (`openwiki/`) plus a "Regenerate" button.
* **🔌 Model reuse**: reads the DSH default model (`agentDefaultModel`) and credentials, maps them to openwiki provider config written to `~/.openwiki/.env` (openai-compatible / anthropic / gemini / openrouter).
* **🖥️ Runtime hosting**: auto-detects the openwiki CLI (parses the npm shim), version check (registry), install / upgrade / self-check (`--help`).
* **🔔 Auto-update**: polls each workspace's git HEAD; on a new commit it runs an incremental update (openwiki has no native git trigger, the plugin supplies it); **defaults to ON for every workspace** — the switch sits next to the "Refresh" button in the knowledge-base left column (**shown only on the Open Wiki tab**; cards and knowledge base are unaffected), **per-workspace independent**, a manual disable is never overridden.
* **🧩 better-sidebar integration**: when the `dsh-better-sidebar` service is detected it **auto-registers** a side page (re-registered after refresh, effectively persistent); when not installed the settings page shows install guidance.
* **🛡️ Ignore file**: `.openwikiignore` (gitignore syntax) graphical editing and save.
* **⚙️ Settings page**: runtime / model / better-sidebar registration / entry visibility (the auto-update switch moved to the knowledge-base panel, per workspace).

> 🔌 **Core idea**: openwiki is the CLI engine, DSH is the host. All state (`.page-manifest.json` / `.run.json` / `.last-update.json` / `.claims/` under the `openwiki/` directory) is a disk contract; the plugin only **reads + displays + triggers**, never touching the generation algorithm itself.
***
## 🧱 Architecture
### Dual Half Structure (Host / Client)
A Cordis plugin splits into two halves, each with **authoritative source code**, and build scripts produce the package artifacts:
| Half | Authoritative source | Build artifact | Responsibility |
| ------ | --------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Host | `src/host/index.js` | `lib/index.js` (ESM entry) | openwiki runtime hosting, model bridging, generation jobs, wiki/claims disk reads, ignore file, auto-update, RPC server |
| Client | `src/client/index.js` | `client/client.js` (Web ModuleLoader bundle) | all UI: entry, floating window, directory tree, document rendering, settings page, better-sidebar registration |
The build scripts (`scripts/build-host.mjs` / `build-client.mjs`) rewrite the free identifiers in the source into package form:
* Host: `harness.handle(` → `rpc.handle(`; `lib/index.js` injects hard deps `webServer`/`settings` and registers the same-origin JSON-RPC route `/dsh-openwiki/rpc`
* Client: `host.call(` → `rpc.call(` (`fetch('/dsh-openwiki/rpc', { headers: {'x-dsh-openwiki':'1'} })`); `styles.insert` → local `