{"_id":"@catheadowl/dsh-coggit","_rev":"2-ba24ff718cbc544a629faf657ea1c120","name":"@catheadowl/dsh-coggit","dist-tags":{"latest":"0.2.1"},"versions":{"0.2.1":{"name":"@catheadowl/dsh-coggit","version":"0.2.1","license":"MIT","_id":"@catheadowl/dsh-coggit@0.2.1","maintainers":[{"name":"catheadowl","email":"493020956@qq.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-ui-renderer","@deepseek-ai/dsh-client-ui-session","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-settings-plugins","@deepseek-ai/dsh-client-ui-workspace","@deepseek-ai/dsh-client-locale"],"platform":"web"}},"dist":{"shasum":"80faa79a58f59a790e033e2ca210798cf024256b","tarball":"https://registry.npmjs.org/@catheadowl/dsh-coggit/-/dsh-coggit-0.2.1.tgz","fileCount":29,"integrity":"sha512-CakwmScIIiWcbxH2Ptf2BQdVql+fnJ7yA2JOXn8I41R065ahRcY1TpLnHhqcKn+CH2UzUKDGaOxqQx0FFAq5HQ==","signatures":[{"sig":"MEYCIQCVkOK9wLcM0sjrcbfrhZU6plSky4Mo7x28sEDVS0nnOgIhAIRTUF9SBpNgb8SvzhfZnK0GCh3LshSfdrg6A8B61AXj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":127310},"main":"lib/types/index.js","type":"module","types":"lib/types/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/types/index.js"},"./client":{"types":"./lib/types/client/index.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"scripts":{"eval":"dsh-eval run eval/behavior/real","test":"node --test --test-isolation=none test/shape-and-views.test.mjs test/tools.test.mjs test/service.test.mjs test/cognition-link-provider.test.mjs test/workspace-resolve.test.mjs","build":"tsc -p tsconfig.json","relink":"node scripts/relink-dsh-peers.mjs","verify":"pnpm run check-types && pnpm run build && pnpm run test","eval:mock":"dsh-eval run --mode mock eval/behavior/mock","check-types":"tsc --noEmit -p tsconfig.json","eval:review":"dsh-review eval/comprehension","build:client":"node scripts/build-client.mjs"},"_npmUser":{"name":"catheadowl","email":"493020956@qq.com"},"repository":{"url":"https://github.com/CatheadOwl/coggit.git","type":"git","directory":"adapters/dsh"},"description":"CogGit runtime adapter for dsh: a ctx.coggit service facade and model-facing coggit_* tools over the CogGit SDK.","directories":{},"_nodeVersion":"24.11.1","dependencies":{"@coggit/core":"^0.2.0","@coggit/runtime-node":"^0.2.0","@catheadowl/dsh-extras":"^0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.2.0","typescript":"^5.9.0","@types/node":"^22.0.0","@types/react":"^18.3.0","@catheadowl/dsh-eval":"^0.1.0"},"peerDependencies":{"@deepseek-ai/cordis":"*","@deepseek-ai/dsh-skill":"*","@deepseek-ai/dsh-tools":"*","@deepseek-ai/schemastery":"*","@deepseek-ai/dsh-util-values":"*","@deepseek-ai/dsh-client-locale":"*","@deepseek-ai/dsh-client-ui-slots":"*","@deepseek-ai/dsh-typert-protocol":"*","@deepseek-ai/dsh-client-connection":"*","@deepseek-ai/dsh-client-ui-session":"*","@deepseek-ai/dsh-client-ui-renderer":"*","@deepseek-ai/dsh-client-ui-settings":"*","@deepseek-ai/dsh-client-ui-workspace":"*","@deepseek-ai/dsh-client-ui-primitives":"*","@deepseek-ai/dsh-api-session-controller":"*","@deepseek-ai/dsh-api-workspace-controller":"*","@deepseek-ai/dsh-client-ui-settings-plugins":"*"},"_npmOperationalInternal":{"tmp":"tmp/dsh-coggit_0.2.1_1788607176023_0.5637524058960572","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Renamed to @coggit/dsh — reinstall with: dsh plugin add @coggit/dsh"}},"time":{"created":"2026-09-05T11:19:35.853Z","modified":"2026-09-05T11:31:37.372Z","0.2.1":"2026-09-05T11:19:36.159Z"},"license":"MIT","repository":{"url":"https://github.com/CatheadOwl/coggit.git","type":"git","directory":"adapters/dsh"},"description":"CogGit runtime adapter for dsh: a ctx.coggit service facade and model-facing coggit_* tools over the CogGit SDK.","maintainers":[{"name":"catheadowl","email":"493020956@qq.com"}],"readme":"---\r\ndescription: @catheadowl/dsh-coggit — CogGit runtime adapter for dsh: ctx.coggit service facade + coggit_* tools + handbook skills + top-level system-prompt section\r\n---\r\n\r\n# @catheadowl/dsh-coggit\r\n\r\nCogGit runtime adapter for dsh: a `ctx.coggit` service facade plus model-facing `coggit_*` tools over the CogGit SDK (`@coggit/core`, `@coggit/runtime-node`). It gives a dsh agent the same paired-cognition workflow the CogGit MCP server exposes — discover, diagnose, add, and resolve cognition documents.\r\n\r\n## Install\r\n\r\n```bash\r\ndsh plugin --profile <name> add @catheadowl/dsh-coggit\r\n```\r\n\r\nThe dsh host provides the `@deepseek-ai/*` peer runtime at plugin load; the SDK pair (`@coggit/core`, `@coggit/runtime-node`) installs as regular dependencies. Architecture, configuration, and the model experience live in this README; the SDK's design contracts live in the [coggit repository](https://github.com/CatheadOwl/coggit).\r\n\r\n## What it provides\r\n\r\n- **`ctx.coggit`** — a `CoggitService` (single-package fold) whose methods take the workspace root, discover CogGit projects under it (cached per root), and read fresh state on every call (reconcile-on-read). Methods: `status`, `add`, `resolve`, plus the single-turn batch pair `buildSnapshot` / `statusWithSnapshot` used by the cognition-link enricher (below). The model-facing `snapshot`/`routes` tools remain removed — see [Removed capabilities](#removed-capabilities).\r\n- **cognition-link enricher** — a declarative prompt-middleware provider (`cognition-link-enricher`, kind `cognition-link`, priority `10`, canonical band) that, for each resolved prompt path, emits a `cognition-link` relates item pointing at the paired cognition document with a `stale` meta marker (miss / missing / not-applicable → no item); on an unconfigured workspace it short-circuits before the per-turn snapshot build. It builds one snapshot per turn (`buildSnapshot`) and reuses it across paths (`statusWithSnapshot`), and registers through the `ctx.inject(['promptMiddleware'], ...)` soft dependency — coggit loads and works without prompt-middleware present.\r\n- **Session-scoped workspace** — the workspace is NOT a config: each `coggit_*` tool call resolves CogGit projects under the CALLING session's workspace (`SessionHeader.cwd`), mirroring dsh-tool-fs/dsh-tool-bash; discovery results are cached per workspace root. Every face still registers unconditionally; the MODEL-VISIBLE surface (the `coggit:overview` section and the `coggit_*` tool schemas) is gated lazily per session — a workspace with no `.coggit/config.yaml` at its exact root hides them (root-only: the gate does not walk up to ancestor configs, unlike the SDK's own discovery), while the execution face still reports empty state if reached directly.\r\n- **Handbook skills** — the dsh analog of the MCP server's `coggit://handbook/<kind>` resources: the node-kind handbooks register as runtime skills (`coggit-handbook-leaf`, `coggit-handbook-skeleton`) via `ctx.skills`. They are **model-only** (`invocation: { modelInvocable: true, userInvocable: false }`): the model sees them in the skill catalog and loads a body with the `skill` tool, but a user `/name` gesture never injects one — only a `coggit_*` tool result's `surfaceHints` routes the agent to load the handbook. The aggregate `all` handbook stays out of the catalog, mirroring the MCP server's model-facing choice.\r\n- **Top-level guidance section** — a `system-prompt` section (`coggit:overview`, order 117) carrying the SDK's surface-neutral `minimal` form (`getCoggitSystemPrompt('minimal').content`), the dsh analog of the MCP server's `instructions`. Conditional injection: the `text` is a lazy provider that renders only when the calling session's workspace has `.coggit/config.yaml`; otherwise it returns empty text and `renderPrompt` drops the section. The fuller `standard` form is still a TODO upstream.\r\n- **Surface-hint translation** — core hints are surface-neutral: operation ids (`snapshot`/`status`/`add`/`resolve`/`routes`) and opaque `handbookId` (the coggit core boundary rule). The adapter owns the mapping to this surface (`views.ts::operationToolName` / `handbookSkillName`) and appends a `surfaceHints` array to every operation result: `coggit_*` tool calls for next-step actions and the matching handbook skill for authoring guidance. Nothing in the projection relies on naming coincidence.\r\n- **Web init UI** — when the plugin is present in a Web profile, the browser contributes a `CogGit` tab under Settings → Plugins addressing the workspace the user is looking at: the workspace owning the **currently selected session** first, then the most recently active workspace, then the server cwd (`workspace-resolve.ts`, mirroring the ui-workspace navigation convention). If that workspace is not initialized, the tab offers a one-time initializer for `source_root` and `cognition_root`; if it is already initialized, it renders the ready state.\r\n- **Three model-facing tools**, mirroring the CogGit MCP names so agent habits transfer:\r\n\r\n| Tool | Parameters | Effect |\r\n|---|---|---|\r\n| `coggit_status` | `sourcePath?` (default `.`) | Diagnose one node (or the whole root): canonical compact status view — issue/action-tag rows, legends, own/descendant counts. |\r\n| `coggit_add` | `sourcePath` (required), `kind?` (`auto`/`leaf`/`skeleton`), `overwrite?` | Create a missing cognition doc and register it. |\r\n| `coggit_resolve` | `sourcePath` (required) | Accept a stale source/cognition pair as reviewed. |\r\n\r\nAll tools return a **JSON-safe projection** of the SDK operation result (the model sees `render` = pretty-printed JSON text) plus the adapter-computed `surfaceHints`. Each tool condenses the SDK result into a **branch payload** rather than passing it through. `coggit_status` splits hit/miss:\r\n\r\n- **Hit** — a matched node omits `found` (implied), `nodeKind`, `project`, and `handbookId` (no next-step signal; the last is redundant with the literal `surfaceHints`), and carries core's **canonical `StatusAgentPresentation`** —the same structured projection the upstream CLI and MCP text render (`statusAgentPresentation.ts`, upstream `d30249a`): `sourcePath`/`cognitionPath`, `cognitionPresence`, the whole-node `status`, the split counts `ownIssueCount`/`descendantIssueCount`, log-style issue rows split into `ownIssues`/`descendantIssues` (`{ sourcePath, level, issueTags, actionTags, optionalActionTags }`), and `issueLegend`/`actionLegend` defining each issue/action tag once. Descendant next steps appear in the descendant rows' `actionTags` (defined once in `actionLegend`) — not in the top-level `surfaceHints`, which carries only the current node's steps.\r\n- **Miss** — an unmatched path carries `found: false` and `pathHints` (the fuzzy source-path candidates, only when non-empty). The SDK's descriptive miss prose (`pathMissMessage`/`pathHintMessage`) is dropped — `found: false` already says \"no match\", and the candidates are the actionable signal. A miss with candidates turns them into a `Try one of these source-root-relative paths: ...` `surfaceHints` line (no re-check — re-running status on a missed path just misses again); a miss with no candidates returns an empty `surfaceHints`.\r\n\r\nA hit's next step comes from core's surface-neutral `suggestedActions`, not from adapter branching on the issue `code` or `status: null`. Core synthesizes a `create-cognition` action (operation `add`) when the node has no paired cognition yet (`cognitionPresence === 'missing'` — the **materialization branch** of core's status design: missing cognition is a normal precondition, not an issue, so under the default maintained-issue visibility an uncognized node carries empty rows/legends), and for maintained stale cognition an **ordered pair**: a handbook-bearing `sync-cognition-with-source` step first, then a `resolve-stale-cognition` action (operation `resolve`). The adapter maps each to a `surfaceHints` line — the sync step becomes the handbook-skill hint (it leads the resolve call), an operation action becomes `Call coggit_<op> with sourcePath=\"<path>\".`. Resolve success is itself the confirmation of fresh, so no re-check follows.\r\n\r\n**Descendant next steps live in the descendant issue rows, not in the top-level `surfaceHints`** — core keeps the top-level `suggestedActions` channel own-node-only and dedupes descendant actions into the triage channel (upstream `6620c1f`+), and `statusAgentPresentation` renders them as the descendant rows' `actionTags` with the tags defined once in `actionLegend`. So a folder whose own README is fresh but has one stale descendant carries no top-level resolve hint; the descendant's sync+resolve pair appears in its `descendantIssues` row.\r\n\r\nThis is **full alignment with the upstream status format**: the hit view is core's canonical `StatusAgentPresentation` verbatim — the same shape the CLI (`renderStatusAgentInspectionText`) and MCP text render, delivered as JSON instead of text. The adapter only appends its `surfaceHints` addressing (the \"keep your own surface addresses\" rule of core's adapter contract / the compact action-tag FR); nothing here is re-derived from issue `code` or `status: null`, and the diagnostic `code` stays in core's raw result. `sourcePath` is always **source-root-relative** (e.g. `src/main.ts`, `src/app`, `.`), never an absolute filesystem path.\r\n\r\n`coggit_add` and `coggit_resolve` split success/failure the same way:\r\n\r\n- **Add success** — `{ success: true, created, kind, sourcePath, cognitionPath }`. `created: false` means \"already exists\" (not a failure). Dropped: the `project` URI context and `handbookId` (carried by `surfaceHints`), plus the failure null-fillers (`created`/`kind`/`cognitionPath` = `null`). Success is self-confirming — the returned `cognitionPath` proves the write, so no re-check follows.\r\n- **Resolve success** — `{ success: true, sourcePath, cognitionPath }`. The registry `sourceKey` and `verificationTimeMs` are receipt data, not next-step signals, so they are dropped with the `project` URI context. `surfaceHints` is `[]` — resolve re-records the pair as accepted, which is already the confirmation of fresh.\r\n- **Failure (both)** — `{ success: false, sourcePath, error: { code, message }, pathHints? }`. The error `code`/`message` is the signal; `pathHints` appears only on a `path-not-found` miss with fuzzy candidates. A miss with candidates turns them into the same `Try one of these source-root-relative paths: ...` `surfaceHints` line (no re-check — re-running status on a missed path just misses again); any other failure emits one re-check action (`Call coggit_status with sourcePath=\"…\".`) so the model re-inspects current state. The re-check is **failure-only** — never attached to a success.\r\n\r\n## Model experience\r\n\r\nThe intended loop, matching the CogGit MCP guidance:\r\n\r\n1. `any_routes` over the workspace/cognition root → find the document to read or the surface to look at.\r\n2. `coggit_status` for that `sourcePath` → read the status, issue/action-tag rows, and legends *before* explaining or editing, and *again after* editing. Omitting `sourcePath` diagnoses the whole project (the root's own status plus every issue-bearing subtree node), so it also serves as the entry point; an uncognized path inspected directly reports `cognitionPresence: \"missing\"` with the `create-cognition` add action.\r\n3. If cognition is missing → `coggit_add` (keep `overwrite` false unless the user asks to regenerate), then load the handbook skill named in `surfaceHints` with the `skill` tool before completing the template.\r\n4. If cognition is stale → load the handbook skill named in `surfaceHints` (it leads the resolve call), sync the paired doc, then `coggit_resolve`.\r\n\r\nA status/read operation never mutates; only `coggit_add` (writes a file) and `coggit_resolve` (re-records acceptance) change state.\r\n\r\n## Configuration\r\n\r\nThe plugin takes **no configuration** (the `Config` schema is empty, reserved for future deployment-wide options). The workspace deliberately follows runtime facts instead of config:\r\n\r\n- Model-facing tools: the calling session's `SessionHeader.cwd` (the workspace the GUI session was created in).\r\n- Web init UI: the browser passes the workspace of the currently selected session (most recently active workspace as fallback) over the `coggitInit/*` Remote; absent selection falls back to the server cwd.\r\n\r\n## Limitations (v1)\r\n\r\n- Output is a JSON-safe projection (JSON text), not the CLI/MCP text rendering; the model reads the JSON directly. `coggit_status` returns the canonical `StatusAgentPresentation` as JSON (same shape the CLI text renders, per the status section above), not the raw SDK operation result, and does not adopt the text formatter (`renderStatusAgentInspectionText`).\r\n- Conditional injection is per-session lazy, not boot-time: the section and `coggit_*` tool schemas appear/disappear on the next assembly (next model step) when `.coggit/config.yaml` is created or removed — in native tool mode. Under Code Mode (`mode: code`/`both`) the generated `tools:sdk` section text is built from the tool registry before the assemble waterfall, so it still lists the `coggit_*` bindings; the waterfall filter removes only the native schemas. Config CONTENT edits (`source_root`/`cognition_root`) mid-session are NOT re-discovered — the service caches discovered projects per workspace root, so changing roots requires a profile restart.\r\n\r\n## Removed capabilities\r\n\r\n`coggit_snapshot` and `coggit_routes` are **removed** from this surface (2026-08), not just unregistered:\r\n\r\n- `coggit_snapshot` (scope-tree view, tracked/untracked counts, `nextScopes`) —the model-facing scope-tree view is not adopted: `coggit_status` with default `.` diagnoses the whole project (own status + every issue-bearing subtree node), and an uncognized path inspected directly reports the materialization branch (`cognitionPresence: \"missing\"` + `create-cognition` add action), which covers the discovery need without the scope-tree view. The underlying snapshot mechanism is nonetheless reused today, but only as a **service batch surface** (`buildSnapshot` / `statusWithSnapshot`) behind the cognition-link enricher — never as a model-facing tool.\r\n- `coggit_routes` (flat route index of tracked pairs) — redundant with `any_routes` for navigation, and its v1 projection duplicated `entries`/`diagnostics` inside the `routes` field without sourcePath/depth/ format refinement.\r\n\r\nIf either is needed again, restore from git history (they were deleted, not commented — the pre-removal commit `0c2c0aa` still carries their implementations). The decision record lives in `dsh-plugin-dev_cognition/coggit/src/README.md`.\r\n\r\n## Development\r\n\r\nThis package is the **dsh adapter of the CogGit SDK** and lives in the coggit\r\nrepo as an **independent sibling project** (the upstream sibling-project decision): it is NOT part of the\r\nroot pnpm workspace (`packages/*` stays pure-registry and clean-machine\r\ngreen); it owns its install, lockfile, and host resolution layer. It is\r\ninstalled into a profile with `dsh plugin add <path>` (bare path = `link:`\r\nsymlink).\r\n\r\nDependency faces (asymmetric by rule):\r\n\r\n- **Host face (runtime + types)** — every `@deepseek-ai/*` import is a\r\n  **peerDependency** provided by the dsh host; `autoInstallPeers` stays off\r\n  (the host's prerelease closure deadlocks registry resolution). Dev-time\r\n  resolution is one machine-local, uncommitted **scope junction**\r\n  `node_modules/@deepseek-ai` → `~/.dsh/profiles/node_modules/@deepseek-ai`\r\n  (the host-maintained install closure — this package is an installed-closure\r\n  consumer, not a source consumer). Rebuild: `pnpm --dir . relink`. A bare\r\n  `pnpm install` purges the junction — always re-run `relink` after install.\r\n- **Library face** — `@coggit/core` + `@coggit/runtime-node` as registry\r\n  versions (`^0.2.0`, installed from npm; no `link:` into `../../packages/*`).\r\n  `@catheadowl/dsh-extras` and dev-only `@catheadowl/dsh-eval` are registry\r\n  versions too.\r\n- **Host source (the only residual)** — `build:client` uses the host's tsdown\r\n  and the unpublished `clientBundle` preset via the machine-level `DSH_REPO`\r\n  anchor (no committed path carries it; the script fails loud with remedy when\r\n  the anchor is absent). Everything else — typecheck, build, tests, eval —\r\n  runs without any host source checkout.\r\n\r\nThen install into a profile and smoke-load:\r\n\r\n```bash\r\ndsh plugin --profile <name> add <path-to>/coggit/adapters/dsh\r\ndsh --profile <name> --dump-config | grep dsh-coggit\r\n```\r\n\r\nRebuild loop: `pnpm --dir . build` (tsc → `lib/types`), then restart the\r\nprofile (plugins load at boot). The browser bundle additionally needs\r\n`pnpm --dir . build:client` (tsdown → `lib/client.js`) — the web profile\r\nserves `lib/client.js`, not sources; a rebuilt bundle reaches a running GUI on\r\npage refresh. `lib/index.js` is a legacy tsdown artifact the patched manifest\r\nlookup still needs (kept until upstream fixes the out-of-tree manifest\r\nlookup); the test suite asserts its presence — copy it from a previous\r\nbuild site or run `build:client` once with `DSH_REPO` set.\r\n\r\n## Tests\r\n\r\nVerification does not need a dsh server. The suite exercises the **built `lib/` artifacts** with `node --test`, so tool-surface and business-logic changes are checked in-process and in seconds, not by restarting the profile and eyeballing the GUI:\r\n\r\n```bash\r\npnpm --dir . build   # first: the tests import lib/, so rebuilt artifacts are required\r\npnpm --dir . test\r\n# one-shot: typecheck + build + test\r\npnpm --dir . verify\r\n```\r\n\r\nCoverage:\r\n\r\n- `test/shape-and-views.test.mjs` — function-plugin shape (no default export), and the pure view functions (`handbookSkillName`, `operationToolName`, `renderJson`, `toJsonValue`, `statusView`, `surfaceHints`).\r\n- `test/workspace-resolve.test.mjs` — the init tab's workspace-target resolution (`resolveWorkspacePath`): selected-session ownership, recent fallback, pending-phase gating, host-order tie-break.\r\n- `test/tools.test.mjs` — mock `ctx.tools.register` capture: exactly three `coggit_*` tools registered, removed tools absent, and `execute` passthrough.\r\n- `test/service.test.mjs` — real `CoggitService` (constructed over a real cordis `Context`) against an on-disk temp fixture: status discovery, path-miss, add writes a cognition doc, resolve re-records, per-root project caching, and the `buildSnapshot` + `statusWithSnapshot` batch surface matching independent status calls.\r\n- `test/cognition-link-provider.test.mjs` — the `resolveCognitionLink` pure projection (fresh/stale/miss/missing/not-applicable), the per-turn snapshot reuse in `createCognitionLinkProvider`, and the `registerRelates` soft-dependency registration via a mock `ctx`.\r\n\r\nThe `--test-isolation=none` flag is required in this environment: `node --test` spawns a child process per file by default, which the dsh file sandbox blocks (`spawn EPERM` on piped stdio). It also means the test entry points are explicit file paths, never a directory.\r\n\r\n## Agent eval\r\n\r\nAgent-level verification uses the shared `@catheadowl/dsh-eval` framework (registry devDependency; host CLI located through the node_modules resolution layer). Behavior cases check tool choice and real tool round-trips; the comprehension review asks whether a fresh model can understand the projected output and infer the next action:\r\n\r\n```bash\r\npnpm --dir . eval:mock   # deterministic layer, no API key: scripted model drives the real tool pipeline\r\npnpm --dir . eval        # real-model intent cases (skips without a credential)\r\npnpm --dir . eval:review # repeated fresh-model design review, human-graded against rubric\r\n```\r\n\r\nThe normalized layout is documented in the `eval/README.md` file in the repository (not shipped in the npm tarball): behavior cases live under `eval/behavior/{real,mock}/`, while the separate `eval/comprehension/` experiment keeps frozen raw inputs, a blind prompt, and a hidden rubric. Generated artifacts stay under nearby `.runs/` directories. A rebuilt `lib/` is required first (`pnpm --dir . build`).\r\n\r\n## What still needs a dsh profile (rare)\r\n\r\nThe suite covers every layer up to — but not including — a real Cordis boot: resolving `inject`, `cordis.patch.yml` composition, and profile config. Those matter only when the *structural* surface changes (tool names, `inject`, `Config`, the patch file, plugin name) and are verified by a one-shot headless boot, not a long-lived web server (see the dsh plugin-dev handbook's debug topic, Part 6, in the dsh-extra repo). Routine business-logic and tool-surface edits do not reach this layer.\r\n","readmeFilename":""}