DSH HUB
首页插件商店插件包社区排行榜资源发布指南
插件源码
返回插件目录

YYC-JNU /

YYC-JNU/dsh-skill-invocation-monitor

已验证

Read-only skill invocation monitor for DeepSeek Harness — which Agents are running, which Skill each is calling, status and elapsed time, live in the Web GUI sidebar. · 只读技能调用监控:侧边栏实时展示活动 Agent 正在调用的 Skill、状态与耗时。

★ 0 Stars0 Forks0 IssuesN/A 社区评分0 已确认安装
查看 GitHub
README来源: main@3453ceec

dsh-skill-invocation-monitor

English | 简体中文

npm version license GitHub stars

A read-only DeepSeek Harness (DSH) plugin that puts every skill invocation on one screen: which Agents are running, which Skill each one is calling, whether it is running / finished / failed, and how long it has been going — live, in the Web GUI sidebar.

The Skill Monitor panel: two sessions, the first one running a skill the user invoked

Captured from the running plugin: the sidebar entry opens a panel listing every Agent, and each row is one skill call with its status, elapsed time and start clock.

What changes after you install it

Skill invocation in DSH is invisible. The model loads a skill, and you see the answer — not the call, not the timing, not the one that never came back. After installing this plugin:

  • the sidebar gains a 技能监控 / Skill Monitor entry, with a live badge showing how many calls are running;
  • the panel lists every live Agent, and under each one every skill call with its status and elapsed time;
  • both ways a skill can be reached are covered and told apart — the model calling the skill tool, and you triggering a skill yourself, which carries a 用户触发 badge on its row;
  • nothing is written anywhere: no tool registered, no session state touched, no call intercepted or delayed.

Install

# from npm (recommended — prebuilt, so no build-script permission is needed)
dsh plugin --profile web add @yyc-jnu/dsh-skill-invocation-monitor

# or straight from GitHub (plain ESM JavaScript: no build step, so pnpm never asks for allowBuilds)
dsh plugin --profile web add github:YYC-JNU/dsh-skill-invocation-monitor

Then restart DSH and refresh the page. Both halves — the host observers plus the read-only route, and the browser bundle — are scanned during host start-up, so no sidebar entry appears before that restart.

Verify the layer before booting:

dsh --profile web --dump-config     # look for: # == @yyc-jnu/dsh-skill-invocation-monitor

If that layer is missing, the package installed as a plain dependency and the plugin never activated.

Uninstall:

dsh plugin --profile web remove @yyc-jnu/dsh-skill-invocation-monitor

Features

Live Agent list Every live Agent, its session title, and whether it is running or idle
Per-call rows Skill name, status (运行中 / 已完成 / 失败 / 未观测到结果), elapsed time, start clock
Both invocation paths The model's skill tool call, and a human triggering a skill — marked 用户触发
Ticking durations The elapsed time updates every second while a call is running
Sidebar badge The running-call count sits on the sidebar entry, so you can see activity without opening the panel
Honest failures A failed call shows a truncated reason, e.g. skill "…" is unknown or no longer available
Self-check diagnostics Every response carries counters describing what the plugin observed, so a wrong assumption is visible rather than silent
Zero dependencies Neither half imports a third-party package (the browser half uses only react from the host module table)

Permissions and data

This plugin exists to observe, and its whole design is built around not participating.

Observes (read-only) Five Cordis events: tools/pre-execute, tools/result, session/event, agent/status, agent/disposed
Reads The live Agent list, session titles, and the durable session-event feed as it is appended
Does not write No session state, no session log, nothing on disk, no config, no tool, no command
Does not interfere The tools/pre-execute listener returns next() unchanged and never denies, cancels, rewrites or delays a call; every observer is wrapped so a bug in this plugin cannot break a dispatch
HTTP surface Exactly one route, GET /api/plugins/skill-monitor/state — no body, no mutation, cache-control: no-store
Network exposure Loopback only: a non-loopback peer, a cross-site fetch marker or a foreign Origin gets 403; any non-GET method gets 405
Where the data lives One Map in host memory. Records are capped (200 by default) and expire (10 minutes after they settle); restarting DSH clears everything
Not collected Prompt text, model output, file contents, credentials, or anything else the plugin never reads

Compatibility

DSH Verified against 0.2.0-rc.2 (the build this plugin was developed and tested on). The seams it uses are documented core surfaces, so other 0.2.x builds are expected to work
Node.js Declared >=20. The plugin runs inside the DSH host, so the host's own Node requirement is what matters
Surface Web GUI (dsh.client.platform: "web"). Uses only official Slots — sidebar.panellist for the entry and main for the panel — never DOM injection
Skill paths Uses the durable contracts for both paths: tool calls on tools/pre-execute / tools/result, and human invocations through the skill-invocation message source declared by the skills seam

How it works

The two invocation paths — and why the human one is read from a message source

A skill can be reached two structurally different ways in DSH, and the plugin observes both.

Model path User path
Trigger The model calls the skill tool You invoke a skill (e.g. /grill-me)
What DSH does Runs the tool pipeline and produces a tool result Appends the skill's instructions to the conversation as a user/message — no tool call and no command event
Pairing key callId the message id
Duration measured tools/result − pre-execute turn/end − injection (see the note below)
Row marker none 用户触发

The human path is read from the structured source the skills seam itself attaches (SkillInvocationSource, in the persistence catalog):

{ "type": "user/message", "data": {
    "source": { "kind": "skill-invocation", "name": "grill-me", "form": "instructions" },
    "role": "user", "id": "7c2e0f5a-3b9d-4e18-9a6c-1d2f3a4b5c6d" } }

The name comes straight from source.name, so no skill-catalog lookup and no text parsing is involved. That is a measured result, not a guess: an earlier implementation assumed the human path went through command/run / command/done, and a real session log disproved it — a human-invoked skill produces no command event at all, which removed an entire catalog cache and its 60-second TTL.

One deliberate choice: a human skill has no result event of its own, so its duration is the turn window (injection until turn/end), not the skill's own execution time. That is a stated convention, not a measurement — if you would rather see an instantaneous event with a duration of 0, only the settling point changes.

Status semantics
Status Meaning
运行中 A start was observed (a pre-execute or a skill message) and no ending event has arrived; the duration grows live
已完成 The tool reported isError === false, or the turn that carried the skill ended normally
失败 The tool reported isError === true; the row shows a truncated reason
未观测到结果 No ending event arrived within 15 minutes (the call was denied before dispatch, its parent was cancelled, the host crashed). This is a derived status and is never written back into the record
The read-only contract

This is the plugin's core constraint, and there are tests asserting each row.

Constraint How it is implemented
Registers no writable tool Never touches ctx.tools — no register, restrict or guard; apply() adds no member to ctx (asserted by a test)
Modifies no session state Never appends a session event, never writes a session log, never calls a service method; only reads agents.list() / sessions.get() / sessionTitle.get()
Intercepts nothing The tools/pre-execute listener returns next() untouched and never denies, cancels, rewrites or measures; a hostile arguments Proxy cannot make it block a call (asserted by a test)
Writes nothing to disk All state is one in-memory Map, capped and expiring; no history, no persistence, no alerting
One read-only route GET /api/plugins/skill-monitor/state only — no POST, no request body, no write path
Zero runtime dependencies Neither half imports a third-party package
Diagnostics — how a wrong assumption stays visible instead of silent

Every state response carries a diagnostics object describing what the plugin actually saw:

Field What it tells you
sessionEvents The durable event feed did reach the plugin
skillInjections / trackedInjections Human skill messages were seen and recorded
unmatchedInjections A skill-invocation message arrived whose name could not be read
turnEnds / settledByTurnEnd Turn endings arrived, and how many human records they closed

This is not decoration: it is what caught the disproved command-path assumption in the first place.

Configuration (optional)
- id: skill-invocation-monitor
  name: '@yyc-jnu/dsh-skill-invocation-monitor'
  config:
    maxRecords: 200          # in-memory record cap
    retentionMs: 600000      # keep settled records for 10 minutes
    staleMs: 900000          # no outcome within 15 minutes → 未观测到结果
    maxCallsPerAgent: 20     # rows shown per Agent in the panel

Development

Tests, scripts and repository layout — for contributors
cd dsh-skill-invocation-monitor
npm run verify   # node --check on all three entry files
npm test         # 72 offline tests: node --test

72 offline tests cover three layers: the pure aggregation model (test/tracker.test.mjs, 36 — duration settling for both paths, pairing keys, staleness, eviction and caps, Agent merging, field-name parsing of the durable payload), the read-only contract itself (test/host-plugin.test.mjs, 25 — exactly five events, exactly one GET route, a pure passthrough pre-execute listener, loopback fencing, disposal), and the browser bundle (test/client-bundle.test.mjs, 11 — loaded the way the shell loads it, asserting the slot registrations and the rendered output).

The plugin is plain ESM JavaScript: lib/ is the source, there is no build step and no src/.

dsh-skill-invocation-monitor/
├── package.json          # name / exports / dsh.bundle.patch / dsh.client
├── cordis.patch.yml      # the one profile row both halves hang off
├── lib/
│   ├── host/
│   │   ├── index.js      # host half: 5 read-only observers + 1 GET route
│   │   └── tracker.js    # pure aggregation model (no Cordis, no I/O, explicit timestamps)
│   └── client.js         # browser half: ModuleLoader bundle, 2 slot registrations
├── docs/
│   ├── screenshot.png             # the screenshot above
│   └── skill-monitor-flow.json    # archify sequence-diagram source
└── test/                 # 72 offline tests

License

MIT

Acknowledgements

The code in this plugin was written with AI assistance: the author defined the requirements, reviewed the results and accepted them, while the AI produced the implementation and the documentation. Every behaviour was verified against a running DSH instance; session titles, message ids and timestamps in tests and examples are synthetic and contain no real user data.

—/ 5

暂无评分

已验证 DSH bundle

Commit 3453ceec7894

社区评论

还没有评论,来写第一条。

DSH HUB

社区维护的 DSH 插件索引。不是 GitHub 或 DeepSeek AI 的官方产品。

社区资源API关于