Skip to main content

dsh-suite/packages/create-dsh-plugin/templates/events

43Stars8Forks27Issues0Watchers

Event/lifecycle template examples in the create-dsh-plugin scaffolding: zero runtime dependencies, demonstrating listening to session/event, tools/change, tools/pre-execute and ctx.effect resource cleanup.

Evidence4/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki

ⓘ This plugin is a sub-package of the whyihaveyou/dsh-suite monorepo — stars and activity count the whole repository.

Language
HTML
License
MIT
Branch
main
agent-frameworkawesome-listcordisdeepseekdeepseek-harnessdeveloper-toolsdshdsh-plugin

Install

cmdweb profile
$ dsh plugin --profile web add github:whyihaveyou/dsh-suite#path:packages/create-dsh-plugin/templates/events

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin whyihaveyou/dsh-suite/packages/create-dsh-plugin/templates/events for me: review the repository at https://github.com/whyihaveyou/dsh-suite first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Description

Embedded event/lifecycle example template within the create-dsh-plugin scaffolding: zero runtime dependencies, pure type imports, demonstrating how to subscribe to session/event, tools/change, tools/pre-execute three events, and wrap a timer with ctx.effect() to prove resource cleanup is reversible. Can serve as a minimal runnable "event plugin" reference, or directly dsh plugin add into a profile to run and observe logs.

Core Capabilities

  • Subscribe to session event bus: When session logs are added (turn/step boundaries, user/assistant messages, tool results, etc.), print the first 5 and throttle logs every 25 by type + count.
  • Subscribe to tool registry changes: Immediately print counts when any tool is registered or unregistered (including registrations from other sibling plugins in the same group).
  • Hook into tool execution pipeline: Print tool name before each tool call, and explicitly pass through with next(); not calling next() will short-circuit and block the tool call.
  • Wrap a 30-second heartbeat timer with ctx.effect(), the returned disposer prints DISPOSED and clears the timer when the plugin unloads, demonstrating how to properly recycle external resources.
  • Declare itself to be injected into the host loader via cordis.patch.yml + dsh.bundle.patch, the template directory itself is a valid bundle, can be directly dsh plugin add installed into a profile.

Technical Implementation

  • Language: TypeScript (ESM, "type": "module" + tsc outputs pure ESM dist/index.js, verbatimModuleSyntax: true ensures import type is erased at compile time)
  • Key dependencies: @deepseek-ai/cordis (peerDependency, injected by host at runtime), @deepseek-ai/dsh-tools (devDependency, only for types ToolExecution / PreToolDecision), @deepseek-ai/dsh-session (devDependency, only for types Session / SessionEvent); the template's own dependencies is empty
  • Architecture pattern: cordis bundle event/lifecycle plugin — host exposes ctx, plugin apply(ctx) subscribes to three event types using ctx.on() + wraps timer with ctx.effect(); package-level declaration dsh.bundle.patch: ./cordis.patch.yml lets host loader insert id: {{PLUGIN_ID}}, name: {{PKG_NAME}} at load time
  • Entry file: templates/events/src/index.ts (compiled by tsc to templates/events/dist/index.js, pointed to by package.json's main / exports)

Use Cases

For those who want to understand how DSH plugins "listen" to events rather than "add" tools—for example, doing telemetry, audit logging, tool call rate limiting, or bridging external webhooks to the session flow. The template code itself is already the minimal runnable event subscription example; you can directly copy it and swap out the listener logic to make it your own event plugin; or when you don't want to start from scratch, you can use the create-dsh-plugin scaffolding with -t events as a starting point.

Prerequisites & Compatibility

DependencyMin VersionDescription
Node.js^22.19.0 || >=24.0.0From create-dsh-plugin root package.json engines; older Node will only get EBADENGINE warning but may hit runtime pitfalls (scaffolding PITFALLS #1)
DSH>=0.1.0-rc.6Implicitly locked by next-tag versions of @deepseek-ai/dsh-tools / @deepseek-ai/dsh-session devDependencies; defaults to 0.1.0-rc.6 for offline generation
@deepseek-ai/cordis^{{CORDIS_VERSION}} (peerDependency, default 4.0.1)Injected by host at runtime, template only import type doesn't require at runtime
PlatformCross-platformNo native modules, pure ESM
Native modulesNoneTemplate dependencies is empty

Installation

dsh plugin --profile web add github:whyihaveyou/dsh-suite/packages/create-dsh-plugin/templates/events

Configuration

This plugin requires no additional configuration. The template doesn't read process.env / options / Schema; all tunable points are in the source code (which events to listen to, timer interval 30_000 ms, throttle thresholds 5/25). To modify behavior, directly edit src/index.ts and rerun pnpm run build.

FAQ

Q: What's the difference between import type and regular import in the template?

A: import type { Context } from '@deepseek-ai/cordis' tells tsc "only take the type, erase at compile time", so the final dist/index.js won't have require('@deepseek-ai/cordis'). This allows the template to keep cordis / dsh-tools / dsh-session as devDependencies without stuffing them into runtime dependencies; when the host loads, it directly feeds ctx to apply(ctx).

Q: What happens if I forget to call next() in tools/pre-execute?

A: The tool call will be short-circuited and never executed. The template source code comments clearly state this is a common pitfall (templates/events/src/index.ts:38), next() is the pass for the pipeline to proceed. To "veto" a call, you should return a PreToolDecision instead of just returning.

Q: Is the 30-second heartbeat in the template mandatory to keep?

A: No. Its sole purpose is to work with ctx.effect() to demonstrate "how resources not managed by the host are cleaned up on unload"—on unload, logs will print DISPOSED — listeners removed, timer cleared. In actual plugins, if you don't need a heartbeat, just delete that ctx.effect() block.

Q: What's the process to add new environment variable configuration items to this template?

A: Not recommended to add them in the template. The event template is designed for "zero runtime dependencies, minimal and readable"; if you really need configuration, you should use the tool template (with defineTool + Schema), or copy the events template and add your own ctx.effect(() => applyConfig(process.env.MY_FLAG)).

Q: What if name: {{PKG_NAME}} in cordis.patch.yml isn't replaced?

A: That means you bypassed the scaffolding and directly copied the template directory. {{PKG_NAME}} / {{PLUGIN_ID}} / {{CORDIS_VERSION}} are all tokens that must be replaced through create-dsh-plugin's render process (packages/create-dsh-plugin/src/generate.js:64-65); the smoke test asserts "no {{残留" (packages/create-dsh-plugin/test/smoke.test.mjs:47-50).

Difficulty

Beginner — only one file src/index.ts (62 lines), three subscription types + one effect example, no runtime dependencies, just copy-paste and rename to make it your own event plugin.

Known Issues & Limitations

  • Must run tsc first to have dist/: Template root only has src/, package.json's main points to dist/index.js; after directly dsh plugin add, the host won't find the entry, need to run pnpm install && pnpm run build in template directory first.
  • {{token}} must be replaced via scaffolding: The {{PKG_NAME}} / {{PLUGIN_ID}} / {{CORDIS_VERSION}} in the bare template are placeholders and won't be parsed by the host; bypassing the scaffolding is like installing a "hole".
  • @deepseek-ai/dsh-tools latest dist-tag is stale 0.0.1-rc.1: The scaffolding forces generated projects to lock dsh-tools / dsh-session to next-tag (default 0.1.0-rc.6), don't manually npm i @deepseek-ai/dsh-tools to override (scaffolding PITFALLS #2).
  • All dsh packages must lock to same version line: All @deepseek-ai/dsh-* packages need unified 0.1.0-rc.x, otherwise pnpm will install two copies of modules causing type inconsistency (scaffolding PITFALLS #3).
  • dsh plugin add <dir> relative path anchors to calling directory: When template is installed as bundle, path resolution goes by package name not relative path, but for local debugging if using ./<dir>, must run from parent directory not inside template (scaffolding PITFALLS #6).
  • cordis.patch.yml name must use package name: Using relative path will make host loader fail to find entry, template top comment specifically documents this pitfall for safety (templates/events/cordis.patch.yml:4-7).

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/whyihaveyou/dsh-suite/packages/create-dsh-plugin/templates/events)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory