# dsh-task-gantt — plugin-market submission dossier
> **Every requirement in this file carries a source** — a path on this machine
> (with line numbers) or a URL. Anything we could not verify is marked
> **❓unverified** or **⛔not-yet-satisfied**, never asserted as done.
## 0. Status at a glance
Last checked `2026-10-15T10:48Z` — GitHub API (`gh`) plus
`https://awesome-dsh-plugin.com/plugins.json`.
| Item | Status |
|---|---|
| Package manifest market-compatible | ✅ (checked against the local rules below) |
| Install / uninstall commands | ✅ written down once, in `docs/INSTALL.md`; all three marked **[not run]** end-to-end (see §4) |
| Published to GitHub | ✅ since `2026-10-10T17:37:09Z` — `gh repo view xx529/dsh-task-gantt` resolves, `origin` = `https://github.com/xx529/dsh-task-gantt.git`, topics `['dsh','dsh-plugin','deepseek-harness','dsh-better-sidebar','agent-team','gantt']` |
| Repo age ≥ 1 day | ✅ cleared `2026-10-11T17:37:09Z` as predicted; the catalog's own `Submission gate` confirmed it — SUCCESS `2026-10-12T07:22:46Z` |
| `dsh-plugin` topic | ✅ set — see the topic list above |
| Catalog entry (`data/plugins/xx529__dsh-task-gantt.yml`) | ✅ submitted — [PR #7086](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/7086), +6 lines and nothing else, opened `2026-10-10T18:16:41Z`, both checks SUCCESS, `MERGEABLE` / `CLEAN` |
| **Catalog PR merged → visible in the market** | ⛔ **not yet** — submitted but unmerged, so the live `plugins.json` (4671 entries, `updated: 2026-10-14`) contains no `xx529` entry and no name containing `gantt`.
**预计合并窗口 / ETA to merge: `2026-10-17` – `2026-10-24`, centred on `2026-10-20`** — a queue position, not a promise; method and sources in `docs/SUBMISSION.md` §Merge queue tracking |
| CI on `main` | ✅ latest run `CI` = success, `2026-10-15T06:46:50Z` |
| Screenshots | ⚠️ 5 PNGs captured and published under `docs/screenshots/`, but no `screenshots.json` next to `package.json` yet — so the listing declares none (see §6.3 O1) |
| Published to npm | ➖ optional; not planned, and not required for listing |
## 1. One-line description
**en (required by the catalog):**
> Agent-team task Gantt chart for the DSH sidebar: one swimlane per teammate, real session-log time on the x-axis, and each shared task drawn with its title and summary.
**zh (optional; the catalog says a maintainer will fill it in if omitted):**
> DSH 侧边栏的 agent team 任务甘特图:每个 teammate 一条泳道,横轴取自真实会话日志时间,条内显示共享任务的标题与简介。
Both must be accurate to the code — the catalog treats the description as a
claim that is checked against the source:
> **The description must be accurate.** It is read as a claim about your plugin,
> and it is checked against your code. … Overstating is the one thing that gets
> an otherwise-good plugin sent back.
> —
### 1.1 Claim-by-claim self-audit
| Claim in the description | Where it is true in the code |
|---|---|
| "one swimlane per teammate" | `TimelineLane` = one roster member; lanes are Lead first, then teammates, then `unassigned` (`src/shared/contract.ts:104-125`, `:147-148`) |
| "real session-log time on the x-axis" | spans come from `turn/start`…`step/end` in the durable log, never invented (`src/shared/contract.ts:41-43`) |
| "each shared task drawn with its title and summary" | `TimelineTask.subject` + `TimelineTask.description` are first-class fields (`src/shared/contract.ts:85-87`) |
| "sidebar tab" | registered via `ctx.betterSidebar.registerTab` (`src/client/index.ts:109-121`) |
> ⚠️ Do **not** put "real-time" or "live updates" in the catalog line unless the
> polling behaviour is verified on a mounted profile; the panel's refresh
> strategy is still being implemented.
## 2. Long description (for the market detail view / README reuse)
```
You are running several teammates at once and the transcript no longer tells you
who did what, when.
dsh-task-gantt adds one tab to the dsh-better-sidebar sidebar:
y-axis the team roster — the Lead, then every teammate, then an
"unassigned" row for tasks the board has not handed to anyone
x-axis wall-clock time in milliseconds, read from the durable session
event log — turn bands with step bars inside them, and a "now" line
bars the shared tasks: subject, a one-line summary, status, owner,
blockedBy, writeScopes and readiness
The chart is assembled from two sources on purpose:
* the agentTeam session projection says WHAT exists and what state it is in —
but it contains no timestamps at all;
* the session event log says WHEN it happened — but it never says what the
board currently holds.
Where the log does not date a task, the task is drawn at its current position
and labelled as live. The plugin never invents a timestamp, and it says so in
the panel when a lane could not be dated.
Read-only: the plugin never creates or updates a shared task. It is safe to
leave open.
```
## 3. Category and keywords
**Category: `ui`.**
- The catalog's valid set is
`agi ui usage theme model identity session memory tools wsl browser vision voice docs skill workflow git notify dev security remote market fun`
().
- `ui` is what the installed market snapshot itself uses for
sidebar/output-surface plugins — e.g. `DSH-Right-Sidebar`, `dsh-explorer`,
`dsh-message-rail` are all `ui`
(`/Users/lzx/.dsh/profiles/web/node_modules/dshmarket/data/registry-snapshot.json`,
`plugins[0]`, `plugins[1]`, `plugins[3]`).
- It is **not** `theme`: the Themes tab is reserved for skins that swap
appearance (`…/contributing.md`, "Themes & skins").
**Keywords** (already in `package.json`): `dsh`, `dsh-plugin`,
`deepseek-harness`, `dsh-better-sidebar`, `agent-team`, `gantt`
(`/Users/lzx/Documents/GitHub/dsh-task-gantt/package.json`).
Note: the catalog entry itself has no keyword field — its YAML is
`url` / `name` / `category` / `description.{en,zh}` (+ optional `tarball`)
(`…/contributing.md`, "Adding a plugin"). Keywords only serve npm discovery.
## 4. Install command
Quoted **verbatim** from `docs/INSTALL.md` (owner: packaging) — that file is the
single place the commands are written down and carries the evidence for each.
**From GitHub (the recommended form):**
```bash
cd ~/.dsh && dsh plugin --profile web add "github:xx529/dsh-task-gantt"
```
**Local development (link the checkout instead of installing a copy):**
```bash
cd ~/.dsh && dsh plugin --profile web add "link:/Users/lzx/Documents/GitHub/dsh-task-gantt"
```
**Uninstall:**
```bash
cd ~/.dsh && dsh plugin --profile web remove dsh-task-gantt
```
Status: all three are **[not run]** end-to-end — the repository now exists on
GitHub, so the `github:` spec has something to resolve, but a real install writes
the live `~/.dsh/profiles/web` profile, which only the Lead does during the mount
smoke test (`docs/INSTALL.md` §1.1, §1.2, §5).
Why these are the right verbs — sources as recorded in `docs/INSTALL.md`:
| Fact | Source |
|---|---|
| `dsh plugin` forwards its arguments **verbatim to pnpm** in the profile directory | `docs/INSTALL.md` §1.1, quoting `~/.nvm/versions/node/v22.22.2/lib/node_modules/@deepseek-ai/dsh/lib/bin.js:96` (the CLI's own help text: `"pnpm arguments, forwarded verbatim (add , remove , why , ...)"`) |
| therefore `add` / `remove` are pnpm subcommands, not bespoke dsh verbs | same |
| `github:owner/repo` is the form the official docs print for a bundle plugin | §2, cited in `docs/INSTALL.md` §1.1 |
| `link:` is the official local-development form | §2, cited in `docs/INSTALL.md` §1.2 |
| `remove ` is the documented uninstall verb, and it takes the **package name** | §7, cited in `docs/INSTALL.md` §5 |
| the catalog emits the same shape for GitHub entries: `dsh plugin --profile web add github:/` | `/Users/lzx/.dsh/profiles/web/node_modules/dshmarket/data/registry-snapshot.json` — e.g. `plugins[0].install` = `"dsh plugin --profile web add github:Limitinfinitude/DSH-Right-Sidebar"` |
> ### ⚠️ Never install under an alias
>
> `… add "dsh-task-gantt@github:xx529/dsh-task-gantt"` parses, but the package
> lands at `node_modules/` while its inner `package.json` still says
> `"name": "dsh-task-gantt"`. The profile's `dsh.profile.bundles` list and the
> Loader row are keyed by the **package name**, so the mismatch degrades to
> "warn, then skip" (`docs/INSTALL.md` §1.1, with the alias behaviour measured
> against a real package). If the README ever advertises the aliased form, the
> listing installs and then does nothing.
> ⚠️ **`remove` does not rewrite the patch layer.** Uninstalling deletes the
> dependency but does not remove manually-added `insert` rows from a
> `cordis.patch.yml`. This package's row comes from its own bundle patch, so
> nothing should be left behind — but a hand-added `- id: dsh-task-gantt` row in
> `~/.dsh/profiles/web/cordis.patch.yml` must be deleted by hand
> (`docs/INSTALL.md` §5).
## 5. Repository, author, compatibility, license
| Field | Value | Source |
|---|---|---|
| GitHub | `https://github.com/xx529/dsh-task-gantt` | `package.json` → `repository.url` |
| Issue tracker | `https://github.com/xx529/dsh-task-gantt/issues` | `package.json` → `bugs.url` |
| Homepage | `https://github.com/xx529/dsh-task-gantt#readme` | `package.json` → `homepage` |
| Author | `xx529` (GitHub account; the repo has no `author` field yet) | `gh auth status` reported the logged-in account as `xx529` per `docs/TEAM-BRIEF.md` §1 |
| License | MIT | `LICENSE` (MIT License, "Copyright (c) 2026 dsh-task-gantt contributors") + `package.json` `"license": "MIT"` |
| Package name / version | `dsh-task-gantt` @ `0.2.34` (checked 2026-10-15) | `package.json` |
### Compatibility matrix
| Axis | Value | Source |
|---|---|---|
| DSH host version tested | **0.2.0-rc.2** | `~/.dsh/dsh-runtimes/dsh-primary-runtime/runtime.json` → `desktopVersion` (`docs/TEAM-BRIEF.md` §1) |
| dsh-better-sidebar minimum | **0.4.0** — the version that introduced the `ctx.betterSidebar` registry service | `/tmp/dsh-better-sidebar-src/docs/external-plugin-guide.md:5`, `:49` |
| dsh-better-sidebar tested | **0.22.1** (installed in the `web` profile) | `/Users/lzx/.dsh/profiles/web/node_modules/dsh-better-sidebar/package.json`; `docs/TEAM-BRIEF.md` §1 |
| dsh-better-sidebar v0.24.0+ | `hostRouteUrl` is available (`features` probe) but **not required** by this plugin | guide `:5` (`hostRouteUrl` v0.25.0+), `:767`, `:796-799` |
| Platform | any browser-backed DSH Web profile; no native code, no `node-pty`, no platform-specific bundle | `package.json` `engines.node >= 20`; no `os`/`cpu` fields; no native deps |
| Node | `>= 20` | `package.json` `engines.node` |
**Peer dependencies.** The plugin declares exactly one peer,
`@deepseek-ai/cordis: ^4.0.0`, and marks it optional.
| Rule | Source |
|---|---|
| Never put `@deepseek-ai/dsh` / `@deepseek-ai/dsh-*` in `peerDependencies` — the host's startup preflight evaluates `semver.satisfies(runtimeVersion, range, { includePrerelease: true })` for those names and **disables the whole profile row** on failure, with no dialog and no exemption for `peerDependenciesMeta.optional` | `/tmp/dsh-better-sidebar-src/tests/market-manifest.spec.ts:118-139`; `/tmp/dsh-better-sidebar-src/AGENTS.md:23`; `docs/TEAM-BRIEF.md` §2.3 |
| `@deepseek-ai/cordis` does **not** match that preflight (it matches neither `@deepseek-ai/dsh` nor the `@deepseek-ai/dsh-` prefix), which is why it is the one peer we may keep | `/tmp/dsh-better-sidebar-src/tests/market-manifest.spec.ts:141` |
| Official `@deepseek-ai/*` packages belong in `peerDependencies`, not `dependencies` | `…/contributing.md`, "Recommended for a better install experience" |
| A peer range must carry an explicit prerelease branch on the matching tuple or it silently excludes prerelease builds | `…/contributing.md`, same section |
## 6. Listing checklist — item by item, with sources
The catalog's own bar, distilled:
> An entry is added when the plugin installs with `dsh plugin add`, does what its
> one-line description says, sits in the right category, and is maintained.
> — ,
> "What it takes to be listed here"
### 6.1 Hard requirements
| # | Requirement (verbatim gist) | Source | Our status |
|---|---|---|---|
| R1 | The repo declares a **`dsh.bundle`** manifest in `package.json`; **only `dsh.client` is not installable** | `…/contributing.md`, "Requirements" + the ⚠️ note | ✅ `package.json` → `dsh.bundle.patch: "./cordis.patch.yml"` + `dsh.client.platform: "web"` |
| R2 | A `cordis.patch.yml` sits next to it, with an `insert` row | `…/contributing.md`, code example | ✅ `cordis.patch.yml` → `- insert: [{ id: dsh-task-gantt, name: 'dsh-task-gantt' }]` |
| R3 | Real, working code — no placeholder / name-squat / README-only repo | `…/contributing.md` | ✅ real host + client halves under `src/`, tests under `tests/` |
| R4 | Repo at least **1 day old** (CI-checked) | `…/contributing.md` | ✅ cleared `2026-10-11T17:37:09Z`; `Submission gate` SUCCESS `2026-10-12T07:22:46Z` |
| R5 | Actively maintained | `…/contributing.md` | ➖ ongoing obligation — commits on `main` through `2026-10-15` |
| R6 | Add the **`dsh-plugin`** GitHub topic | `…/contributing.md` | ✅ topics `['dsh','dsh-plugin','deepseek-harness','dsh-better-sidebar','agent-team','gantt']` |
| R7 | Description states what it does, no superlatives/marketing; must be **accurate to the code** | `…/contributing.md` | ✅ see §1.1 audit |
| R8 | Category matches what the plugin does | `…/contributing.md` | ✅ `ui`, see §3 |
| R9 | At most **3 entries per PR** | `…/contributing.md`, "One PR, at most 3 entries" | ✅ one entry |
### 6.2 Market-manifest constraints (from the market/registry side)
| # | Constraint | Source | Our status |
|---|---|---|---|
| M1 | No `cordis` key in `dependencies` / `peerDependencies` / `optionalDependencies` — hard-rejected by name, `optional` grants no exemption | `/tmp/dsh-better-sidebar-src/tests/market-manifest.spec.ts:6-12` and `:67-71`; `/tmp/dsh-better-sidebar-src/AGENTS.md:23` | ✅ only `@deepseek-ai/cordis` is declared |
| M2 | No `preinstall` / `install` / `postinstall` / `prepare` scripts in the **packed** manifest | `…/tests/market-manifest.spec.ts:14-16` (`LIFECYCLE_SCRIPTS`), `:79-85` | ✅ `package.json.scripts` = build / dev / typecheck / test / test:watch / verify:build / check / pack:check — none is a lifecycle hook |
| M3 | `dsh.bundle.patch` must be a safe relative path that exists inside the package | `…/tests/market-manifest.spec.ts:87-99` | ✅ `./cordis.patch.yml` exists at the repo root and is inside `files` |
| M4 | `repository.url` must normalise to a credential-free HTTPS GitHub `owner/repo` URL (the catalog ↔ npm backlink check) | `…/tests/market-manifest.spec.ts:101-112` | ✅ `https://github.com/xx529/dsh-task-gantt` — no credentials, no query, no hash, 2 path segments |
| M5 | Exact SemVer version (no ranges, no tags; prerelease allowed) | `…/tests/market-manifest.spec.ts:114-116` | ✅ `0.2.34` |
| M6 | npm `latest` must be an exact **stable** version for the automatic install preview (for the Community Market path) | , "自动安装条件" | ➖ we are not on npm, so that market can only offer the manual GitHub command; this does **not** block listing in the `dshmarket` catalog |
| M7 | `dshmarket` installs only from the curated catalog — anything else is rejected | `/Users/lzx/.dsh/profiles/web/node_modules/dshmarket/README.md:47` | ➖ our entry has to exist in the catalog first |
| M8 | To get into `dshmarket`, PR the **catalog**, not the market app | `…/dshmarket/README.md:57-59` | ✅ done — [PR #7086](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/7086) opened `2026-10-10T18:16:41Z`, unmerged as of `2026-10-15T10:48Z`; see §8 |
### 6.3 Optional / recommended
| # | Item | Source | Our status |
|---|---|---|---|
| O1 | `screenshots.json` next to `package.json`, 1–8 repo-relative images | `…/contributing.md`, "Screenshots" | ⚠️ 5 PNGs are captured and published at `docs/screenshots/`, but **no `screenshots.json` is declared** next to `package.json` (checked 2026-10-15) — so the listing declares none and the market falls back to images extracted from the README. Plan in `docs/SCREENSHOTS.md` |
| O2 | Publish to npm (skips the `allowBuilds` build-approval step; adds a download count) | `…/contributing.md`, "Recommended…" + "npm package" | ➖ not planned; listing is unaffected |
| O3 | Prebuilt tarball on a GitHub Release + `tarball:` field — **required** only if the repo cannot be installed from source at all | `…/contributing.md`, same section | ➖ not needed: `lib/` is committed, so `github:` installs need no build step |
| O4 | `package.json#icon` + `locale/.json` for the host plugin manager's display metadata. `locale/en.json` is the **discovery baseline** — without it the whole locale directory is ignored, and every failure is silent (the entry just degrades to a plain text row) | `/tmp/dsh-better-sidebar-src/AGENTS.md:103` | ✅ resolved — `locale/en.json` and `locale/zh.json` exist and are published (`gh api repos/xx529/dsh-task-gantt/contents/locale`, 2026-10-15), `package.json` exports `./locale/*.json` and lists `locale/*.json` in `files`, and `icon.svg` + `"icon": "./icon.svg"` are present |
## 7. What the market actually reads
Useful when deciding what to fix, and what to ignore:
| Layer | What it reads | Source |
|---|---|---|
| `dshmarket` catalog | `GET https://awesome-dsh-plugin.com/plugins.json`, cached 1 h, bundled snapshot as offline fallback | `/Users/lzx/.dsh/profiles/web/node_modules/dshmarket/src/registry.ts:36-59` |
| Catalog entry shape | `name`, `owner`, `url`, `category`, `description{en,zh}`, `npm`, `stars`, `install`, `added` | `…/dshmarket/src/registry.ts:9-27`; live sample in `…/dshmarket/data/registry-snapshot.json` |
| Activation state after install | `live` / `restart` / `inert` / `broken` / `missing`, decided by the profile's `dsh.profile.bundles` + the package's `dsh` metadata + a loadable entry artifact | `…/dshmarket/src/verify.ts:1-19`, `:98-187` |
| `dsh.plugin.json` | **not** a DSH contract — DSH reads `package.json`'s `dsh.bundle.patch` + `dsh.client`; `dsh.plugin.json` only serves third-party registry channels | `/tmp/dsh-better-sidebar-src/AGENTS.md:103` |
Consequence, and the decision this repo took: **no `dsh.plugin.json` is shipped**.
Its only consumer would be a third-party registry channel, and the catalog we are
targeting reads `package.json` from the repository URL
(`…/contributing.md`, "What CI checks"). Nothing that the listing path reads is
lost by omitting it.
## 8. The submission itself
Per the catalog guide, **one YAML file is the whole submission** — the READMEs
are generated and must not be hand-edited:
```yaml
# data/plugins/xx529__dsh-task-gantt.yml
url: https://github.com/xx529/dsh-task-gantt
name: xx529/dsh-task-gantt
category: ui
description:
en: Agent-team task Gantt chart for the DSH sidebar: one swimlane per teammate, real session-log time on the x-axis, and each shared task drawn with its title and summary.
zh: DSH 侧边栏的 agent team 任务甘特图:每个 teammate 一条泳道,横轴取自真实会话日志时间,条内显示共享任务的标题与简介。
```
(`en` is the only required description field; a `: `-containing description
must be quoted in YAML — neither of ours contains `: `.)
—
**Status of this PR:** opened `2026-10-10T18:16:41Z` as
[PR #7086](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/7086).
As of `2026-10-15T10:48Z` it is `OPEN`, `MERGEABLE` / `CLEAN`, with both `check`
(SUCCESS `2026-10-12T07:22:18Z`) and `Submission gate` (SUCCESS
`2026-10-12T07:22:46Z`) green. Nothing on our side blocks it; merging is manual
and batched by the maintainer, so the remaining question is queue depth only.
**预计合并窗口 / ETA to merge: `2026-10-17` – `2026-10-24`, centred on
`2026-10-20`.** This is a queue position derived from the maintainer's observed
merge history, **not a promise** — the method, the 156-PR wait-time distribution
it is built on, and how to re-check it are all in
`docs/SUBMISSION.md` §Merge queue tracking.
## 9. Open items
1. ✅ Push `xx529/dsh-task-gantt` to GitHub and add the `dsh-plugin` topic —
done `2026-10-10T17:37:09Z`; topics verified `2026-10-15`.
2. ✅ Wait out the 1-day repo-age bar before opening the catalog PR — cleared
`2026-10-11T17:37:09Z`, PR opened `2026-10-10T18:16:41Z` (before the bar
cleared) and the gate went green on its own at `2026-10-12T07:22:46Z`.
3. ⛔ Capture the three screenshots and add `screenshots.json`
(`docs/SCREENSHOTS.md`).
4. ✅ `locale/en.json` + `locale/zh.json` are shipped and published (checked
`2026-10-15`), so the silent-degradation risk is closed; contract source as
recorded: `/tmp/dsh-better-sidebar-src/AGENTS.md:103`.
5. ❓ Confirm on the mounted profile that the GitHub install spec resolves and
the tab renders (owner: Lead, per `docs/TEAM-BRIEF.md` §7). All three install
commands in §4 are currently **[not run]** end-to-end.
6. ⚠️ **Repo hygiene, for the record (outside this file's write scope):**
`package.json` → `files` lists `README.md`, `README.zh.md` and
`docs/INSTALL.md`, but the READMEs link to `docs/DESIGN.md`,
`docs/MARKET.md`, `docs/VALIDATION.md` and `docs/FINDINGS-host.md`, which are
**not** in `files`. Browsing the GitHub repository is unaffected; only a
published npm tarball would carry dead links. `package.json` is owned by
`packaging`; flagging rather than editing.
7. ➖ Decide later whether to publish to npm (would enable the Community
Market's automatic install preview).