# DEVELOPING — Local development, build, and integration

[中文](DEVELOPING.zh.md)

This guide is for contributors who want to run this plugin locally, debug it against their own DSH deployment, or wire it into a DSH profile manually.

## 1. Clone

```bash
git clone https://github.com/Elpsycoogroo/dsh-work-report.git
cd dsh-work-report
```

The plugin is a standalone repo with its own `.git`. It is not part of the DSH `packages/` workspace; at runtime it lives under `plugins/` and is referenced by a `file:` dependency from the profile.

## 2. Install dependencies

Install with npm (or pnpm):

```bash
npm install
```

`prepare` runs `tsdown` on install. If the build fails because DSH runtime packages (`@deepseek-ai/dsh-*`) are missing, that's expected — those packages only exist inside the DSH monorepo or a profile. Two options:

1. Build inside the DSH environment (see [§4](#4-wire-into-a-local-dsh-profile)).
2. Skip the build failure and install the peer packages from within the profile directory.

Either way a successful build produces `lib/`.

> **pnpm / `dsh plugin add` installs**: pnpm blocks install scripts by default. Run the install command once — pnpm prints the key to add under `allowBuilds` in the profile's `pnpm-workspace.yaml`; add it, then install again.

## 3. Build

```bash
npm run build        # = tsdown
```

Outputs:
- `lib/index.js` — host side (server plugin, ESM)
- `lib/client.js` — browser side (CJS with `__ModuleLoader__` banner; echarts inlined)

## 4. Wire into a local DSH profile

Two ways.

### 4a. `file:` dependency (recommended for development)

In the DSH repo, edit the profile manifest, e.g. `dsh/.dsh-home/profiles/web/package.json`:

```json
{
  "dependencies": {
    "dsh-work-report": "file:../../../plugins/dsh-work-report"
  },
  "dsh": { "profile": { "bundles": ["dsh-work-report"] } }
}
```

Then reinstall the profile under `.dsh-home/profiles/web` (pnpm/npm). The plugin loads as a local package; rebuild with `npm run build` and restart the DSH app.

> ⚠️ **`package.json` `exports` must include `"./package.json"` (else plugin list shows but UI never loads)**
> DSH's client-modules reads the manifest via `require.resolve('<pkg>/package.json')` to locate the `./client` entry. If `exports` omits `"./package.json"`, it throws `ERR_PACKAGE_PATH_NOT_EXPORTED` and the package is **permanently cached as "not a client plugin"** — the plugin appears in the list and the host shell loads, but client.js is never injected and the UI never appears. Also keep the three `name`s aligned (package.json / plugin's own cordis.patch.yml / profile reference). After changing the manifest you **must restart dsh** (the negative verdict is process-lifetime cached).

### 4b. Direct copy of `lib/` (quick smoke test)

Build first, then copy the artifacts into the installed plugin directory:

```bash
cd dsh/plugins/dsh-work-report
../../node_modules/.bin/tsdown
Copy-Item -Recurse -Force lib\* "dsh/.dsh-home/profiles/web/node_modules/dsh-work-report/lib/"
```

Restart the DSH web app. For a smoother loop use `npm run dev` (or `node dev.mjs`) — it watches `src/`, auto-builds, and syncs the whole package into your DSH profile when `DSH_PROFILE_DIR` is set (see [dev.mjs](dev.mjs)).

## 5. Confirm it loaded

Open the DSH app's browser console. You should see:

```
[dsh-work-report] v0.1.0 client loaded
```

Click the 🧠 floating button — the Neural Ledger overlay opens. If you don't see it, check:

- Server log shows `[dsh-work-report] host plugin loaded: GET /api/work-report`.
- `curl http://127.0.0.1:3080/api/work-report?days=7` returns JSON (not `not found`).

## 6. Debugging with the console bridge

| Log | Meaning |
|-----|---------|
| `[dsh-work-report] v0.1.0 client loaded` | Client bundle injected. |
| `[dsh-work-report] host plugin loaded: GET /api/work-report` | Host route registered. |
| `work-report error: ...` | Report build failed; the detail is in the error. |

Debugging tips:

- **API returns `not found`** — the route was shadowed by another `/api` prefix handler; make sure the registration uses `kind: 'exact'` (`ctx.webServer.register`).
- **No data (0 sessions)** — check `sessions.list()`/`sessionPersistence` availability and that `storages/session_projcache.json` exists under `$DSH_HOME`.
- **Subagent tokens are 0** — those sessions are blank (created but never ran); they are filtered out by design. If real sessions still show 0, the event `usage` aggregation did not find the blocks — inspect the `assistant/message` event shape.
- **Forecast shows 0s** — sparse daily data triggers the fallback baseline; with enough history the linear regression kicks in.

## 7. Project structure

```
├── src/
│   ├── index.ts             # Host entry (re-exports apply/name/inject)
│   ├── server/
│   │   ├── index.ts         # Route registration + mock mode
│   │   └── report-data.ts   # Collection, aggregation, insights, forecast
│   ├── client/
│   │   ├── index.ts         # Client entry: draggable FAB + overlay mount + hover label
│   │   ├── i18n.tsx         # zh/en dictionaries + language provider
│   │   ├── ReportView.tsx   # Main dashboard shell
│   │   ├── StatCards.tsx / Insights.tsx / TokenCharts.tsx / ForecastCard.tsx
│   │   ├── WorkspaceChart.tsx / EfficiencyCharts.tsx / ToolRanking.tsx
│   │   ├── SessionTimeline.tsx / ContextExporter.tsx / markdown.ts / report-api.ts
│   └── types/
│       └── dsh-env.d.ts     # Ambient types
```

No DSH source files are modified. Integration is DOM-level only.

## 8. Common issues

| Issue | Fix |
|-------|-----|
| pnpm refuses to run install scripts | Add the printed key to the profile's `pnpm-workspace.yaml` → `allowBuilds`. |
| Plugin loads but FAB doesn't appear | Check client bundle is served: `curl /plugins/dsh-work-report/client.js`; restart dsh after manifest changes. |
| echarts build error | echarts is a `devDependency` so tsdown bundles it; do not move it to `dependencies` (it would be externalized and missing from the module table). |