# AGENTS.md

## Scope

`dsh-agent-plugin-market` is a dual-face DSH plugin. It clones Git-backed
markets, exposes enabled skills to DSH, and registers authorized Codex hooks.
Treat the running DSH process and the browser UI as the integration target; this
repository is not a standalone web application.

## Repository Layout

- `lib/index.js`: Host composition root. Wires injected DSH services to the
  market runtime, market service, hook manager, skills provider, startup update,
  feature settings, model tools, tool guidance, and authenticated RPC routes.
- `lib/market-runtime.js`: Host runtime for DSH-home paths, configuration I/O,
  Git command execution, market/plugin manifest parsing, and skill scanning.
- `lib/market-service.js`: Host lifecycle service for market Git operations,
  plugin installation, skill state, hooks authorization, state views, and
  startup auto-update.
- `lib/market-features.js`: Native DSH feature settings and optional tool/prompt
  Fiber lifecycle; the live Config form is the `dsh-agent-plugin-market` profile entry.
- `lib/market-tools.js`: Host model tools for market state reads and workspace
  plugin/skill override writes, with scoped restriction for home-path agents.
- `lib/market-config.js`: Pure configuration state transitions for markets,
  installed plugins, skill switches, and related cleanup.
- `lib/codex-hook-manager.js`: Codex hook inspection, desired-versus-active
  reconciliation planning, approval coordination, generated bridge
  configuration, and hook Fiber lifecycle management.
- `lib/codex-hooks.js`: Pure helpers for hook-source parsing, path validation,
  stable fingerprints and storage keys, plus command-environment injection.
- `lib/util.js`: Internal helpers without business semantics (currently log and
  runtime-error message extraction only).
- `lib/client.js`: Browser plugin. It is plain JavaScript loaded by
  `window.__ModuleLoader__`; split catalog models, shared controls, settings
  section, and workspace dialog into internal functions/sections in this file;
  use `require`, `React.createElement`, and no JSX, TypeScript, `import`, or
  bundler-only features.
- `cordis.patch.yml`: Adds the package to the web profile composition.
- `package.json`: `@deepseek-ai/dsh-client-ui-primitives`,
  `@deepseek-ai/dsh-home-paths`, and `@deepseek-ai/schemastery` are required
  peer dependencies. `@deepseek-ai/dsh-hooks-codex` is an optional peer; when
  absent, the UI shows the running-cohort profile `pnpm add` command for it and
  `@deepseek-ai/dsh-hook-protocol`.

## DSH Upgrade and Compatibility Policy

- npm `latest` and `next` are the required compatibility targets: both must work
  against the current implementation.
- `engines.dsh` declares a bounded best-effort range. Extend the lower bound as
  far as the current implementation naturally works, without version-specific
  compatibility code. Releases inside the range other than `latest` and `next`
  are best-effort: do not add bridges or parallel implementations to retain one.
  If a release needs ad-hoc compatibility work to start, drop it from the range
  instead and record the concrete incompatibility boundary.
- CI covers the earliest declared supported release, npm `latest`, and npm
  `next`, deduplicated by version, crossed with absent/present hooks
  dependencies. Add another release only when it is a meaningful API boundary.
- If `next` moves above the declared upper bound, the smoke preflight fails and
  prompts an adaptation: verify the new release, then extend the bound. Do not
  keep an untested maximum target.
- Keep `engines.dsh`, dependency pins, CI coverage, runtime installation
  guidance, and documentation consistent. Keep the plugin version plain SemVer,
  without encoding the DSH target in a suffix.

## Development Rules

- Keep Host and Client responsibilities separate. Host code owns filesystem,
  Git, persistent state, hooks, and RPC. Client code owns settings-page UI and
  calls Host routes through the existing API helper.
- DSH development dependencies target `0.2.1-rc.5` (npm `next`;
  `latest` targets `0.2.1-rc.2`). Pin each DSH package explicitly; individual
  subpackage dist-tags can still point to older cohorts. `engines.dsh` is bounded
  from `0.2.1-alpha.2` through `0.2.1-rc.5`, the range that works with the
  current implementation without version-specific code. `latest` and `next`
  must pass; intermediate releases are best-effort and CI only smoke-tests the
  earliest bound plus both channels, deduplicated by version, crossed with
  absent/present hooks dependencies. Do not use an open-ended range or change
  `lib/` merely to widen compatibility. Apply the compatibility policy above
  when changing this range.
  The unchanged bundle patch sets the Connection provider's inject list to
  `[webStartup, webServer]`. Versions from `0.1.7-alpha.1` through
  `0.2.1-alpha.1` still read `webRuntime` in the upstream Connection config
  expression, so this override fails startup with `cannot get property
  "webRuntime" without inject`, even though the consumed Host methods exist.
  Versions before `0.1.7-alpha.1` also lack `settings.configure()`. These are
  the concrete reason the lower bound is `0.2.1-alpha.2`; retain that boundary
  instead of inferring compatibility from API names alone.
  The `alpha.2` and `alpha.3` preflight ignores `engines.dsh`, so do not assume
  older runtimes enforce the declared bounds. The Host must inject both
  `connection` and `webServer`. The bundle patch must also add `webServer` to
  the `connection` provider row while retaining `webStartup`: Connection RPC
  getters retain the provider's shadow context. Test with separate sibling
  Connection and WebServer provider Fibers; providing the WebServer on the root
  Context hides this guard failure.
- Keep each CI smoke installation on one DSH release cohort with
  `.github/pin-dsh.cjs` and a fresh step-local pnpm cache. Initialize the smoke
  profile with the tested DSH CLI before installing dependencies so its pnpm
  linker and peer settings match that release's profile defaults. Apply the
  hook to both `dlx` and profile child installs; wildcard peers and framework
  patch ranges can drift even when the CLI pins its DSH dependencies. Cross
  the smoke targets with absent/present profile-local hooks dependencies, and
  verify actual bridge availability through the authenticated market RPC
  instead of assuming CLI dependencies are importable by profile plugins. Do
  not add the bridge to `dsh.profile.bundles`; it has no bundle declaration.
  Retain Node downgrade tests for bridge unavailability.
  Revalidate the Cordis 4.0.5 / Loader 1.0.6 / Include 1.0.10 companion baseline
  when upgrading DSH; newer framework APIs can break older app-boot consumers.
- Expose tool and prompt switches in the native plugin configuration's
  `Agent 插件市场` / `功能` group, backed by DSH settings. Both preferences
  default to enabled; disabling tools also suppresses their guidance, and home
  sessions receive neither tools nor guidance. Preserve skill loading, hooks,
  and market RPC independently of these switches. Own registrations and
  settings subscriptions through the plugin Fiber and test live toggle disposal.
- Preserve hook safety invariants: hooks are disabled by default, the UI uses
  double confirmation, approvals match the configuration fingerprint, hook
  configuration file paths remain inside the plugin root, and command hooks
  receive only `PLUGIN_ROOT`, `PLUGIN_DATA`, `CLAUDE_PLUGIN_ROOT`, and
  `CLAUDE_PLUGIN_DATA`. Dispose hook Fibers when hooks are disabled, changed,
  updated, or removed.
- Treat market content and hook configuration as untrusted input. Keep path
  containment checks. Bind approvals to verified hook configuration
  fingerprints, not market pull outcomes. Market pulls suspend hook Fibers while
  Git mutates the checkout; reconciliation remounts matching approved
  fingerprints, disposes mismatches, and clears approvals when the current hook
  configuration disappears or becomes unusable.
- Use `@deepseek-ai/dsh-client-ui-primitives` before making a new UI control.
  The page uses `Button`, `Input`, `Pill`, `Menu`, `Tooltip`, and
  `DisclosureRow`. The native plugin configuration card follows the built-in
  PluginCard layout and theme tokens; a bare `DisclosureRow` is a catalog row,
  not a plugin configuration card. Use `--dsw-*` theme tokens for layout or any
  missing-control adapter; never add fixed light/dark colors. The hooks switch
  is a small native button adapter.
- Keep the settings section ID stable as `skills-and-hooks` unless the DSH
  settings integration is intentionally migrated. The visible label is
  `技能与挂钩`. Reuse the same MarketPage for the `agent-plugin-market` main
  panel and settings section. Native `showInSidebar` defaults to enabled and
  controls only the `sidebar.panellist` entry; hiding it must retain settings,
  an already-open panel, skills, hooks, and model-facing feature lifetimes.
- Treat `lib/`, `package.json`, `cordis.patch.yml`, and applicable tests as the
  source of truth for repository behavior. When behavior changes, update every
  tracked Markdown document that describes it; do not describe Codex bridge
  event support beyond the verified installed bridge/protocol contract.
- Use exclusive local debugging: link the Web profile to this repository root
  and develop here. Do not use a separate Git worktree for debugging; switching
  branches in the root checkout is allowed when needed. A linked plugin may
  resolve its bridge from this repository's development dependencies rather
  than the profile's explicit dependencies; verify the actual resolved cohort
  matches the running DSH before reloading it.
- Do not start a replacement Vite server for the existing DSH GUI. Client
  changes need a page refresh unless the DSH checkout's `pnpm run dev:web`
  watcher is running; claim HMR only after verifying that watcher.
- Do not restart DSH autonomously or assume every Host/package edit requires
  one. Verify the installed HMR contract and the actual reload trigger first:
  profile recomposition can replace changed loaded files in installed or linked
  plugins; module watching requires configured roots. Config Editor writes do
  not themselves replace modules. If the runtime reports `restart-required` or
  no supported reload path is active, ask the user to restart and confirm before
  continuing runtime validation.

## Validation

Run the Node unit suite for core behavior before using the real DSH GUI for
end-to-end validation.

```bash
pnpm lint
pnpm test
pnpm typecheck
for file in lib/*.js test/*.test.js; do
  node --check "$file" || exit
done
git diff --check
```

For UI, link this repository root into the target DSH web profile. For Host or
package changes, confirm the live schema/activation after a supported HMR reload;
only when a restart is needed, ask the user to restart and confirm first. Test
the existing GUI at `http://127.0.0.1:3080` with `agent-browser`. Do not use curl
as UI evidence. Check the settings entry, market controls,
disabled/enabled switch contrast, and both light and dark themes after visual
changes.

The Node suite covers configuration, runtime scanning, hook helpers and hook
lifecycle, and catalog-model behavior. For manual hook E2E
verification, create a disposable local Git market fixture under ignored
`test-repos/`, trigger a real DSH tool call, verify enabled delivery and disable
disposal, then update the market to check that unchanged approved fingerprints
remount and changed hook configurations require reapproval. Remove the
registered market and marker data after validation.

## Required Skill Routing

Read the named Harness skill before beginning the matching work:

- Cordis Host/Client, slots, services, or runtime plugin work: read
  `cordis-plugin-development`.
- `cordis.patch.yml`, profile composition, or preset changes: read
  `editing-cordis-compositions`.
- GUI testing or screenshots: read `agent-browser`, then run
  `agent-browser skills get core`.
- DSH package APIs, hook protocol behavior, or version contracts: read
  `contract-verification`.
- Dependency or workspace package-manager changes: read `pnpm`.
- Documentation changes: read `documentation`.
- Creating a commit: read `git-commit`.

## Git Delivery

Review `git status`, the exact diff, and staged contents before committing.
Do not commit `node_modules`, local DSH profile files, generated market data,
temporary hook fixtures, or screenshots. Use a focused Conventional Commit.
Push only when the user requests it; never force-push.
