Contributing
September 21, 2026 · View on GitHub
Thanks for considering contributing to dsh-TUI! This guide is the shared
development contract for humans and coding agents working on @deepseek-harness-tui/dsh-tui.
How To Contribute
- Report bugs through the bug issue form: version, terminal environment, and a minimal reproduction. A report does not reserve the implementation or authorize a pull request.
- Request features in Discussions Ideas.
- Issues do not accept feature requests.
- Accepted proposals get a tracking issue, and its assignee owns the implementation.
- Do not start writing code before the proposal is accepted — OAuth,
/cost, notifications, a plugin API and a remote runtime were each written in full and then closed. - A discussion, issue, comment, or a claim that a maintainer agreed does not authorize a pull request.
- Open a pull request only if you have write/admin/maintain on this
repository, or your GitHub username is listed in
.github/APPROVED_CONTRIBUTORS.- Unsolicited implementation pull requests from everyone else are closed by
pr-gate, regardless of size, title, test results, or whether a human or an agent wrote the code. - Maintainers add names based on trusted prior work. It is not an application program — do not open an issue or discussion asking to be added.
- Membership permits a pull request; it grants no write access and does not pre-approve feature scope.
- A write collaborator may reopen a closed pull request as a one-off exception. Reopening by anyone else is closed again.
- Open the pull request against
main. Keep changes focused: one logical change per PR, with a Chinese or bilingual title and a description that covers motivation, what changed, and how it was verified. - A pull request that changes code must link an issue: add a
Closes #<issue>line to the description, or link it through the Development sidebar. Theissue-linkCI group checks this and fails without a link. - Changes classified as docs-only by CI are exempt (see path routing under
Verification). For a maintainer release, revert, or CI hotfix that genuinely
has no issue to link, apply the
no-issue-neededlabel.
- Unsolicited implementation pull requests from everyone else are closed by
- Run the verification matrix below before requesting a review; CI runs the same commands.
- New features should include or extend a focused regression script.
Before opening an implementation pull request, confirm the authenticated GitHub
account has write access or appears in .github/APPROVED_CONTRIBUTORS.
- If neither is true, refuse to open the pull request and point at the bug form or Discussions.
- A human cannot bypass this with a private approval, an issue link, or a pasted maintainer comment.
When the gates take effect
The feature proposal flow applies only to pull requests opened on or after 2026-08-24. The pull-request allowlist applies only to pull requests opened (or reopened) after the gate lands.
- Pull requests already open before that follow the previous rules.
- They are not closed retroactively and need no Discussion or tracking issue.
Scope
This file applies to the entire repository. It is the shared development
contract for humans and coding agents working on @deepseek-harness-tui/dsh-tui.
@deepseek-harness-tui/dsh-tui is a single-package, ESM-only TypeScript project.
It provides a React terminal UI front door for DeepSeek Harness through Cordis.
- The package owns the TUI, its local command surface, and an Ink/Yoga renderer.
- DeepSeek Harness owns the agent, session, model, tool, skill, persistence, and policy domains that the TUI consumes.
Before making a broad change, read package.json, the relevant README section,
and every source file being edited. Prefer the repository's existing service
boundaries and helpers over introducing parallel abstractions.
Repository Map
src/index.ts: public Cordis plugin entry point, configuration schema, and lazy handoff to the runtime plugin.src/dsh-adapter/plugin.ts: TTY validation, service registration, agent creation/resume, React tree mounting, and terminal/process teardown.src/dsh-adapter/questions-answerer.tsandpreset-resolution.ts: isolate upstream prerelease dispatch for user questions and agent presets so version branches do not spread into bootstrap or channel actions.- The questionnaire "provider seat" guard (DUPLICATE_PROVIDER probe + private
symbol check, #586) only applies to the legacy rc
registerProviderpath. - On the 0.1.2 line's
user-questions/requestwaterfall, Cordis first scope-filters requests carrying an agent; agentless/authrequests are dispatched without a scope carrier. - Under the answerer convention, the first eligible listener that returns
instead of delegating with
next()claims the request. - Cordis waterfall is around middleware, however: an outer listener can call
next()and then observe, replace, or reject the downstream result, while{ prepend: true }inserts a listener at the front. - Upstream offers no supported way to discover or reserve a verifiably exclusive claimant, so the legacy seat guard and its warning cannot be reproduced locally.
- The questionnaire "provider seat" guard (DUPLICATE_PROVIDER probe + private
symbol check, #586) only applies to the legacy rc
src/dsh-adapter/channel.ts: event-to-view projection and the non-React action surface.- It translates DSH session events into transcript rows.
- It implements submit, steering, rewind, resume, model/preset switching, local reports, and related state transitions.
src/screens/Chat.tsx: top-level interaction coordinator. It owns modal precedence, global keyboard handling, scroll/search/selection state, slash command dispatch, and composition of the chat screen.src/screens/StatusLine.tsxandsrc/screens/StatusMetrics.ts: terminal status presentation and metric derivation.src/components/: feature components.components/design-system/contains theme-aware primitives;components/messages/contains transcript rows;components/questions/contains theask_user_questionUI.src/ui.ts: preferred facade for the local renderer, themedBox/Text, hooks, and public TUI primitives.src/ink/: low-level Ink-based renderer and terminal implementation. Treat it as sensitive infrastructure: keep changes focused and accompany them with renderer-specific regression coverage.src/native-ts/yoga-layout/: ported layout engine used by the renderer.src/terminal-utils/: terminal formatting and presentation helpers.src/*Prefs.ts,src/customTheme.ts, andsrc/sessionHistory.ts: persisted user preferences and local session metadata under~/.dsh-tui..agents/skills/*/SKILL.md: project skills for repository maintainers, discovered by the DSH filesystem provider and excluded from the npm package.cordis.patch.yml: package bundle overlay used by profile installation. Ordering, row IDs, disabled host rows, and insert/override semantics matter.cordis.yml: full bare-composition example for direct Cordis/DSH startup.scripts/: headless regressions, reproduction harnesses, probes, and diagnostics. Read each script's header before running it..github/scripts/pr-intake/: PR intake gate (locale, close copy, allowlist, issue-link). Workflows only orchestrate;pr-gate.ymlmust check out the default branch and must not run the PR head.lib/: ignored JavaScript, declarations, and declaration maps generated fromsrc/and shipped to npm../invariantuses the compiledlib/types/dsh-adapter/invariant.jsentry as well.README.md(English, the default front page) andREADME_ZH.md(Chinese): the bilingual user documentation. Keep behavior, configuration, shortcuts, and limitations synchronized between them.
Runtime Shape
The central runtime path is:
Cordis config
-> src/index.ts
-> src/dsh-adapter/plugin.ts
-> DSH agent/session services
-> src/dsh-adapter/channel.ts (session events -> Channel snapshot)
-> src/screens/Chat.tsx
-> src/components/*
-> src/ui.ts
-> src/ink/* + Yoga layout
-> terminal ANSI output
Keep ownership in the layer where it belongs:
- Agent/session/tool facts come from DSH services and durable session events.
- Projection and TUI actions belong in
dsh-adapter/channel.ts, not in presentation components. - Interaction modes and key precedence belong in
Chat.tsxor the focused modal/input component. - Reusable visual behavior belongs in
components/and theme-aware primitives. - Terminal protocol, layout, hit-testing, selection, and frame-diff behavior
belong in
ink/.
Do not reimplement a DSH domain service in the TUI merely to make a screen easier to build. Adapt the service through the channel or an existing registry seam.
Toolchain
-
Supported Node versions are
^22.19 || >=24; CI uses Node 24. -
CI and publishing use pnpm 11. Use pnpm as the development package manager. The
packageManagerfield in the rootpackage.jsonis the single source of truth for the pnpm version; both CI and corepack read it from there. -
Install a clean checkout with:
git clone --recurse-submodules https://github.com/ccch1mneyyy/dsh-TUI.git cd dsh-TUI pnpm install --frozen-lockfileIn an existing checkout, run
git submodule update --init --recursivefirst.vendor/dsh-stdanddsh-authare workspace /link:dependencies, so the install always fails while those submodules are empty. -
pnpm-lock.yamlis the single lockfile. npm consumers do not read a dependency's lockfile, sopackage-lock.jsonhas been removed (follow-up of #173). -
When intentionally changing dependencies, update
pnpm-lock.yamlwithpnpm add, inspect the full lockfile diff, and avoid unrelated upgrades. -
Every
@deepseek-ai/*framework package this package references at runtime or from its published types (followingUPSTREAM_BLESSED_PACKAGES, including@deepseek-ai/schemastery) is both a peer and a dev dependency.- Framework packages are host-provided and resolve at runtime to the host's
own instance through the
$DSH_HOME/profiles/node_modulesfallback tree (see #198 — declaring them as runtime dependencies lands real copies inside the profile and splits module identity from the host). - The dev declarations exist only so the package can type-check locally. Add new references of this kind to both sections at matching ranges (the verify:manifest-deps gate enforces it).
- Framework packages used only by tests/scripts (e.g. dsh-settings, dsh-tools, dsh-session-persistence-*) stay dev-only — do NOT declare peers for them.
- Non-host packages such as
dsh-working-activitystay runtime dependencies. - Historical exception, now resolved:
dsh-working-activity@0.2.4and earlier pulled a real copy of@deepseek-ai/schemastery(plus cosmokit) into the profile via its runtime dependency, shadowing the fallback tree. - 0.2.5 peer-ified it (working-activity#2), so profiles no longer carry any
framework copies. Keep the dependency range at
^0.2.6or above (0.2.6 also fixes the web-side WorkingLine absent-field guard on unpatched hosts, working-activity#5).
- Framework packages are host-provided and resolve at runtime to the host's
own instance through the
-
Do not expose, persist, or print credentials. Interactive startup reads
DEEPSEEK_API_KEY; diagnostics may report whether it is set but must not reveal the complete value.
Build And Generated Files
The normal build and type-check gate is:
pnpm build
- This removes the complete
lib/directory, runstsc -p tsconfig.jsonto emitsrc/intolib/types/, and then checks the adapter boundary, upstream contract, and patch surface. - The
preparelifecycle serves source-checkout bootstrapping only (it fails fast when the vendored submodules are absent — see scripts/prepare-guard.mjs). - Git URL dependency installs have been triply blocked since vendoring (#308: workspace deps / submodules / pnpm ≥11's prepare allowlist) and are unsupported — install the registry package.
- Local and CI workflows use explicit commands instead of depending on whether pnpm implicitly runs the root lifecycle.
Rules for generated output:
- Edit
src/, neverlib/, to implement behavior. - After any source change, run
pnpm build, but do not commit generated files fromlib/. - Clean compilation removes the complete
lib/first, so renamed or deleted source modules cannot leave stale output behind. - Run
pnpm verify:packageto ensure everymain,types,bin, andexportstarget is present in the npm tarball and to smoke-import the main and invariant entries. - Documentation-only, workflow-only, and YAML-only changes do not require a rebuild unless they also alter TypeScript inputs.
- Changes limited to ordinary comments and blank lines may skip the local rebuild; behavior, type, configuration, or build-input changes are not exempt. This does not waive the regressions required below for the changed area; see Verification for the applicable checks.
- Git URL installation with
--ignore-scriptsskipsprepareand is therefore unsupported. Registry packages already contain compiled output and do not depend on lifecycle scripts running on the consumer's machine.
scripts/build.sh is an alternate builder for a local DeepSeek Harness source
checkout. It locates a DSH checkout and rewires dependencies to that checkout.
It is not the default build command for this standalone repository.
Verification
There is no root test or lint script. Do not claim that either ran. The
TypeScript build is the universal static gate, followed by focused executable
regressions.
Select local verification by actual impact.
- For documentation and skills, check facts, links, triggers, and conflicting instructions.
- For ordinary comments, check the explanation against the implementation and confirm that code and types are unchanged, for example with an AST comparison that ignores comments. Compiler directives, JSDoc type annotations, and build-tool annotations are not ordinary comments.
- For workflow and YAML changes, check syntax and affected configuration contracts.
- Do not add behavior tests for prose edits. Once required checks pass, broaden or repeat them only for new changes, failures, or unresolved risks.
CI separately routes changes using the path allowlist in
.github/workflows/ci.yml.
AGENTS.md,.agents/skills/, and comments in source files are outside the docs-only exemption and still trigger code gates.- A local rebuild exemption does not skip CI; preserve required gates and report the actual local verification scope.
verify:build also checks source hygiene, renderer primitives, theme and
activity preference migrations, status animations, table layout, and
side-question behavior.
- Source hygiene rejects the listed naming and compiled-input regressions.
- It is not a source-provenance or license audit.
CI runs these commands after installation:
pnpm compile # generate a clean runtime
test -f lib/types/index.js
pnpm verify:build # build gates without recompiling
pnpm verify:package # npm tarball and entry smoke test
node --import tsx/esm scripts/repro-askpanel.tsx
node --import tsx/esm scripts/verify-askpanel-layout.tsx
node --import tsx/esm scripts/repro-toolcards.tsx
Run all three CI regressions for changes to shared rendering, Chat, prompt or
question layout, tool cards, theme primitives, or the Ink core. For a narrow
change, also run the closest focused script:
| Change area | Focused verification |
|---|---|
| General headless screen composition | pnpm smoke |
| Channel submit/steer/pending behavior | node scripts/verify-submit.mjs |
| Rewind/edit/resend and historical inbox cancellation | pnpm verify:rewind-edit |
| Prompt queue behavior | node scripts/verify-queue.mjs |
| Goal/todo projection and rendering | node scripts/verify-channel-goal-todo.mjs and node scripts/verify-goal-todo.mjs |
| Compaction and folded transcript rows | node scripts/verify-compact.mjs |
| Compaction × session-switch lifecycle (cancel before the fork snapshot, persistence-classified toast) | node --import tsx/esm scripts/verify-compact-switch.tsx |
| Theme loading, persistence, and runtime plugin seam | node --import tsx/esm scripts/verify-themes.mjs, node --import tsx/esm scripts/verify-runtime-themes.ts |
| Default-reasoning-effort and similar preference chains (effortPrefs / settings defaults) | node --import tsx/esm scripts/verify-effort-default.ts |
| Scrolling/sticky-bottom behavior | node scripts/verify-scroll.mjs, node scripts/verify-resticky.mjs, and the matching repro-* harness |
Long plan-review body (exit_plan_mode windowing + wheel) | node --import tsx/esm scripts/verify-plan-review-scroll.tsx |
| Fullscreen copy-on-select | node scripts/verify-copy-on-select.mjs |
| Component-level mouse drag protocol (target capture, bubbling, click/selection compatibility, interrupted-session cleanup) | node --import tsx/esm scripts/verify-drag-protocol.tsx |
| Mouse pointer event pipeline (wheel coords/modifier bits, click/hover dispatch, out-of-bounds clamping, pointer-state reset) | node --import tsx/esm scripts/verify-pointer-events.ts |
| Hover event performance (complete interest boundaries, no-interest rect fast path, frame/multi-root invalidation) | node --import tsx/esm scripts/verify-hover-coalesce.tsx |
| Prompt-input mouse selection editing (drag/Shift+click/double-click word select, delete/replace, layered Esc, Ctrl+C copy, CJK wide cells, fold-side clamping) | node --import tsx/esm scripts/verify-input-selection.tsx |
| Sixel encoding, worker cache, thumbnail/preview lifecycle | node --import tsx/esm scripts/verify-terminal-images-sixel.tsx, node --import tsx/esm scripts/verify-sixel-transcript.tsx; timing comparison node --import tsx/esm scripts/bench-sixel-encode.tsx |
Most focused scripts invoked with plain node import lib/types/; run
pnpm build first. Scripts that import TypeScript sources declare the
node --import tsx/esm <script> form in their header.
- Do not infer the input layer from the file extension.
verify-themes.mjs, for example, importssrc/throughtsx.
Regression scripts take their wait primitives from scripts/lib/term-test.mjs:
settled for wait-then-assert, settle for wait-then-act.
- Any fixed
sleep(that stays must carry a machine-readable tag,固定窗:探针/固定窗:墙钟/固定窗:pacing(defined in that file's header), in a trailing comment on the same line or in the comment block directly above. - The
verify:fixed-windowgate scans every script registered inscripts/run-ci-group.mjsand fails on an untagged call. 固定窗:待迁移marks pre-existing debt (burn-down tracked in issue #791), pinned per file inscripts/fixed-window.baseline.json: any file going up fails, and old debt going down never offsets it.- After clearing a site, run
--write-baselineand commit the rewritten baseline alongside. It must not appear in new code.
Some scripts are forensic or interactive tools, not bounded tests. In
particular, heap/leak scripts, PTY probes, replay capture, performance probes,
and scripts/run.ts can require a specific OS, terminal, native dependency,
DSH checkout, or long-running process.
- Read the header and prerequisites.
- Do not run every file in
scripts/as a blanket suite.
For terminal-visible changes, headless assertions are necessary but not always sufficient.
- When the environment is available, manually exercise the affected flow in both inline and fullscreen modes and at a narrow terminal width. Check startup, resize, scrolling, input, cancellation, and clean exit.
- Windows ConPTY, tmux, OSC clipboard behavior, and synchronized output have distinct paths, so use the matching probe when changing one of them.
pnpm tui invokes scripts/run.ts, which assumes the package lives inside a
DeepSeek Harness monorepo layout with apps/cli and packages/*.
- It is not a portable standalone smoke command.
- For an end-user integration check, install the plugin into a DSH profile and
run
dsh --profile dsh-tuiin a real TTY with the required credentials.
TypeScript And Style
- The package is ESM. Relative imports in TypeScript use
.jsspecifiers, for exampleimport { Chat } from './screens/Chat.js'. Preserve this rule. - In repository-authored TypeScript, follow the prevailing style: two-space
indentation, single quotes, no semicolons, and trailing commas in multiline
constructs.
- The Ink-based renderer files under
src/inkmay retain their upstream tabs or quoting; do not mass-format them.
- The Ink-based renderer files under
- Prefer
import typefor type-only dependencies. - Do not introduce
anymerely becausetsconfig.jsonrelaxesnoImplicitAny. Those relaxations exist to compile the Ink-based renderer and must not become the quality bar for new application code.- Use
unknownand narrow it, or define a small structural interface at an external seam.
- Use
- Preserve readonly data where the surrounding API uses it. Keep state mutations inside the channel/store implementation rather than mutating values from components.
- Keep exported APIs documented with concise JSDoc. Explain contracts and non-obvious invariants, not line-by-line mechanics.
- Comments should explain current ownership, ordering, failure causes, or
compatibility constraints.
- Reference functions or modules rather than unstable line numbers.
- Keep issue or regression evidence that explains a tradeoff.
- Put future ideas in TODOs with explicit conditions instead of describing them as existing capabilities, and revisit related comments when behavior changes.
- Avoid one-use abstractions and unrelated refactors. Inline a trivial helper when it has one call site and does not clarify a real invariant.
- Preserve initialization ordering around environment-sensitive imports.
FORCE_COLOR,NODE_ENV, and terminal capability flags are often read at module evaluation time; moving an import above their setup can change behavior without a type error.- Regression scripts that import
lib/types/directly bypass the package entry, so React loads its dev build and structured-clones every component's props on each commit. - A script that passes large image buffers as props must make
lib/types/force-production-react.jsits first import.
- Regression scripts that import
Agent Instructions And Skills
Keep common constraints and task-specific reading pointers in AGENTS.md; this
guide owns detailed contracts such as the toolchain and verification matrix.
.agents/skills/ contains maintainer workflows and is excluded from npm.
- A skill description should say when to use it and distinguish adjacent skills.
- Keep the body focused on one outcome, the evidence needed to finish, and the necessary steps.
AGENTS.mdintroduces shared rules; skills should not repeat their content or reading reminders.- Link additional references only when the task needs them, and say when to read them.
- Preserve the user's goal and existing authorization: review, repair, reporting,
and publishing are different tasks.
- Ask only for missing information that affects the result.
- If external data is unavailable, state the gap instead of substituting a different task.
- Choose the smallest view that answers the current question: a short call tree
for ordering, a shallow module tree for ownership, or a focused diff for a change.
- Plain prose can be sufficient. Use real names and only relevant boundaries; diagrams are optional.
- Use examples to clarify ambiguous choices, not to enumerate every case.
- Allow no findings, unknowns, and short results; avoid mandatory praise, empty sections, or fixed lengths.
- Check whether triggers hijack another task or steps stop already-authorized work before it is complete.
Architectural Invariants
Cordis Lifecycle And Configuration
- Keep
src/index.tsas the small public plugin contract andsrc/dsh-adapter/plugin.tsas the runtime implementation. Preserve the lazy handoff unless the task intentionally changes the plugin-loading contract. - Register resources through Cordis and clean them up through
ctx.effector the existing single exit funnel. A render failure must remain loud and non-zero; normal exit must restore terminal state before process exit. cordis.patch.ymlis layered overdsh-base. Do not duplicate a service row that the base already mounts. Distinguish an ID override from aninsert, and preserve ordering when one service depends on another.- A profile override replaces an entire
configblock. When documentation shows an override, include every key that must survive the replacement. - When adding or renaming a plugin option, update the
Configinterface and Schema insrc/index.ts, its consumption in runtime code, the applicable rows incordis.patch.ymlandcordis.yml, and both READMEs.
Session And Channel State
- The durable DSH session event log is the transcript source of truth. Rows are replayed/projected from events; do not insert optimistic assistant or tool facts that can diverge from persistence.
- Preserve event ordering, sequence anchors, and call-ID matching. Rewind, resume, folding, tool result association, and exports depend on them.
- Every observable channel mutation must use the appropriate synchronous or
frame-coalesced emitter so
versionadvances and subscribers are notified. - Keep long-session memory bounded. Do not remove transcript folding, replay coalescing, virtualization, or cache limits without a measured replacement.
- Agent changes such as resume, rewind, model switch, and preset switch must reset all session-scoped projections together. Audit rows, goals, todos, titles, pending messages, metrics, and loaded context for stale state.
- Resolve agent/model/tool/preset capabilities through the mounted DSH services and registries. Do not guess external API shapes; inspect the installed package types when changing an integration.
Interaction And Commands
- Keyboard precedence is behavior, not incidental control flow.
- A focused questionnaire or modal consumes its keys before global handlers.
- Mouse text selection consumes Escape before rewind/clear behavior.
- The prompt owns text editing only when no overlay is active.
- Do not hardcode a new shortcut in one component and stop there. Update the relevant help UI and both README shortcut tables, and add or extend a regression for conflicts with existing modes.
- Local slash commands are declared in
src/commands.tsand dispatched inChat.tsx; registry commands are merged at runtime.- When adding a command, update declaration, dispatch, help/documentation,
the i18n description (
cmd-desc-<name>insrc/i18n.ts, zh only — en falls back to the declaration), and any related skill mapping together.
- When adding a command, update declaration, dispatch, help/documentation,
the i18n description (
- Skill commands stay out of LOCAL_COMMANDS: user-invocable skills discovered by DSH are merged from the registry as dispatch commands. Names must be parseable kebab-case and must not collide with a local command.
- Keep
ask_user_questionserialized throughQuestionStore; concurrent questions are intentionally presented FIFO and summarized after completion.
Terminal Rendering
- Prefer themed primitives and hooks exported by
src/ui.ts. Reach intosrc/ink/only for behavior that the facade intentionally does not expose. - Terminal width is display-cell width, not JavaScript string length. Account for ANSI escapes, combining characters, emoji, and East Asian wide glyphs; use the repository's width, slicing, wrapping, and ANSI helpers.
- Keep frame output buffered and normal runs quiet. Do not add
console.logor stdout diagnostics while the TUI is active. Use an opt-in stderr/debug path such asDSH_TUI_DEBUG, or the existingDSH_TUI_RENDER_LOGframe capture. - Preserve raw-mode, cursor, alternate-screen, synchronized-output, mouse, focus, and terminal-query cleanup on success, error, interrupt, and teardown.
- Avoid render-time unbounded collections or per-token/per-frame allocations. Streaming sessions are long lived, and this repository has explicit regressions for prior OOM and scroll-performance failures.
- Layout changes must not allow transcript content to displace the input and status line. Exercise resize storms, long unbroken content, streaming rows, scrolled-up state, and sticky-bottom restoration when those paths change.
- Keep platform detection narrow. Windows Terminal/ConPTY, WSL, tmux, VS Code, and terminals with or without truecolor/DEC 2026 support follow different protocol paths.
Preferences, Themes, And Files
- Follow the existing precedence for configurable preferences: explicit deployment config or environment override, then persisted user choice, then detected/default value. Document any change to that order.
- Persist user data beneath the existing
~/.dsh-tuilocations. Validate and safely parse external JSON; malformed optional state should warn or fall back rather than crash the TUI. - Treat theme names, plugin descriptors, and file contents as untrusted input. Preserve path containment checks, plugin ID constraints, activation cleanup, and all-or-nothing validation of malformed theme files.
- Keep theme additions complete across the
Themecontract and every built-in palette.- Runtime themes must use the
tuiThemesseam; plugins must not rewrite~/.dsh-tui/themes/or bypass the managed extension service. - Use semantic theme keys in components instead of isolated literal colors.
- Runtime themes must use the
Cross-File Change Checklist
| If you change | Keep these in sync |
|---|---|
| Plugin config or environment behavior | src/index.ts, runtime consumer, cordis.patch.yml, cordis.yml, README.md, README_ZH.md |
| Slash commands or shortcuts | src/commands.ts, src/screens/Chat.tsx, help/input components, both READMEs, relevant skill mapping/tests |
| Theme contract, plugin seam, or persisted theme behavior | src/theme.ts, src/themeCatalog.ts, src/dsh-adapter/themes.ts, all palettes, theme provider/picker, custom-theme parser, theme verification, both READMEs, plugin docs |
| Session/channel behavior | src/dsh-adapter/channel.ts, affected UI projections, compiled output, focused channel/replay regression |
| Renderer/layout behavior | src/ink/ or Yoga source, compiled output, CI regressions, focused scroll/resize/PTY probe |
| Skill discovery or presentation | DSH adapter, slash-command merge, /skills, and focused regressions; maintainer-only skills live in .agents/skills/ and must stay out of npm |
| User-facing documented behavior | Chinese and English READMEs, plus config comments/help text where applicable |
| Contribution intake or PR gate | docs/contributing.md, docs/contributing.en.md, .github/workflows/pr-gate.yml, .github/scripts/pr-intake/, .github/APPROVED_CONTRIBUTORS |
| Package version or dependency | package.json, pnpm-lock.yaml, generated/published artifacts as applicable; do not churn the legacy npm lock incidentally |
| Upstream validated-line bump | src/dsh-adapter/contract.ts, both peer and dev ranges in package.json, bundled dsh-auth/package.json and dsh-auth/pnpm-lock.yaml, pnpm-workspace.yaml, the upstream SHA in the alpha-compat job of .github/workflows/ci.yml, the version constants in scripts/verify-{alpha-source,patch-surface,web-coexistence,upstream-contract}, patch-surface.snapshot.json, ADAPTER.md, docs/user-guide.md; steps in the upgrade section of ADAPTER.md |
Git And Release Safety
- The worktree may contain another person's changes. Inspect
git statusand relevant diffs before editing, preserve unrelated changes, and never discard work you did not create. - Do not run destructive cleanup commands such as
git reset --hard,git checkout ., orgit clean -fd. Do not usegit stashto hide another session's work. - Stage explicit paths only; never use
git add .orgit add -Ain a shared worktree. - Commit, tag, push, publish, and release actions require user authorization. Authorization already given in the conversation remains valid; do not ask again at every step. Authorization for one action does not extend to other release actions.
- Publishing is tag-driven.
.github/workflows/publish.ymlrequires av*tag whose version exactly matchespackage.json, then builds, runs focused regressions, and publishes to npm.- Treat version changes and tags as release operations, not routine cleanup.
- Release notes credit contributors. Create GitHub Releases with
gh release create vX.Y.Z --notes-file notes.md --generate-notes.- The hand-written summary comes first, and GitHub appends What's Changed
(PR title + author + link), New Contributors, and the Full Changelog;
.github/release.ymlexcludes bots from the generated list. - In the hand-written summary, entries from external contributors end with
(#PR by @user); the maintainer's own entries are unmarked. - Write bare
#123and@user— GitHub renders them as links.
- The hand-written summary comes first, and GitHub appends What's Changed
(PR title + author + link), New Contributors, and the Full Changelog;
- Before handing off a code change, inspect
git diff --check, the source diff, the generated diff, andgit status. Report exactly which verification ran and any platform or credential-dependent checks that could not run.