@leelee592/dsh-obsidian-plugin — User Manual
==========================================
【What it is】
A DeepSeek Harness capability for developing Obsidian plugins, with one knowledge skill and eleven tools:
- obsidian-plugin skill (knowledge): Obsidian plugin development guidelines (naming/submission rules, accessibility, code quality, submission & Scorecard) that guide the agent's workflow.
- obsidian_plugin_scaffold: generate a compliant plugin skeleton from the official obsidian-sample-plugin template (14 files), with built-in naming/submission checks.
- obsidian_plugin_build: bundle the plugin project into a loadable main.js (CommonJS, obsidian externalized) and run static self-checks (tier L1); resolve the entry point (explicit entry → src/main.ts → a repository-root main.ts → the project's own esbuild/rollup/vite config → package.json main) and the artifact location (project root → the config's outfile/outdir/file/dir → the project-local vault layout → a bounded search that also probes
/.obsidian/plugins//), listing everything tried when a lookup fails; outDir pins the artifact directory; three-tier degradation (the project's own production build script — preferred whenever a bundler config exists, because configs carry plugins that cannot be supplied from the command line → direct project-local esbuild, used when there is no config to honour or as an explicit non-production opt-out that warns the project's plugins were not applied → an actionable refusal), never a watch process, and the tier actually used is reported.
- obsidian_plugin_deploy: install the build artifacts into the vault's .obsidian/plugins//, merge the plugin id into that vault's community-plugins.json (existing entries preserved), and remember the vault in dsh.obsidian.json; reports written / enabled / active separately (active stays unknown until a later phase).
- obsidian_plugin_inspect: read-only observation of the running app (it never changes it): status returns the health facts in one shot (app version, registered vaults, which vault actually answered, that vault's restricted-mode state, whether the target plugin is installed/enabled/version-matched, whether the trust modal is pending), plus errors / console / dom / css / screenshot / trustCheck.
- obsidian_plugin_vault: manage the vault used for live verification: status reports registered vaults, the active window and what activation would take; ensure is a two-step confirmation — without confirm it only describes the consequences, with confirm=true it registers/opens the vault (Obsidian switches to the front) and then asks the app which vault is active, reporting the trust modal instead of accepting it; close closes the test window (macOS); prune is not implemented yet.
- obsidian_plugin_reload: make a code change take effect in the running app: reload (default) / enable / disable; rescan refreshes the plugin manifest index (Obsidian scans a vault's plugin directory only at vault load, so a freshly deployed plugin stays invisible to every plugin command until then); unrestrict explicitly turns off that vault's restricted mode (it reloads the window); after reloading it verifies the plugin is really registered and reports what the plugin logged.
- obsidian_plugin_test: offline smoke test (tier L2): load the built bundle in plain Node against a stubbed Obsidian API and exercise the real lifecycle (default export is a Plugin subclass, onload() runs, registrations happen, onunload() cleans up, no unhandled rejections); needs no Obsidian installed; resolves the project's own @codemirror/* and @lezer/* for real and can use the project's own jsdom for DOM-dependent plugins (if jsdom is missing, the report says so and gives the install command); an optional scenario file (dsh/scenarios/.mjs, receiving { plugin, app, stub }) extends it. It does NOT verify runtime behaviour: the report always says it is a stub environment, names what it did not cover (e.g. UI code registered as an editor extension when no DOM host is available), and points at e2e / screenshot for real verification.
- obsidian_plugin_e2e: scaffold sandboxed end-to-end tests (tier L4, it does not touch your Obsidian): init writes a WebdriverIO + wdio-obsidian-service setup (wdio.conf.mts, tsconfig.e2e.json and a starting spec — the scaffold directory is dir, default e2e/) which launches its own Obsidian with an isolated config directory and a copy of the vault, so nothing switches your window or steals focus; it also adds e2e / e2e:watch scripts and appends the downloaded-build directories to .gitignore (idempotent, keeps hand-edited files unless force=true). status reports only what exists and the exact install command, writing nothing; the runner dependencies stay in your project and the project runs the suite itself (pnpm run e2e).
- obsidian_plugin_eval: run JavaScript inside the running app and return the result — the live-state escape hatch for reading what the app really holds (plugin instances, workspace, metadataCache), driving an interaction, or trying a fix without rebuilding. It is the only high-privilege tool (it executes code in your app, so it is approval-gated): the executed code is echoed back in the result as an audit trail, and the result warns when the code touches window focus (e.g. electron.remote.getCurrentWindow().focus()), because that steals your focus. Parameters: code (required), vault (optional target vault), timeoutMs (optional, default 30000). Prefer obsidian_plugin_inspect (free, no approval) whenever a read-only action can answer the question.
- obsidian_plugin_validate: validate the manifest's required fields, naming rules, versions.json mapping, package.json version consistency, and run eslint-plugin-obsidianmd checks.
- obsidian_plugin_version: bump manifest.json / versions.json / package.json together.
【Usage】
Tell DSH "create an Obsidian plugin …" and the agent loads the obsidian-plugin skill, follows the Obsidian Plugin Development Guidelines, and calls the tools along the way for scaffolding, building, offline smoke testing, deploying, sandboxed end-to-end testing, live verification, running code in the app, validating, and versioning.
【Verification tiers】
Four tiers; the default development loop is L1 + L2 + L4:
- L1 static: artifact / module-format / manifest checks inside obsidian_plugin_build; no interference.
- L2 offline smoke: obsidian_plugin_test loads the bundle in plain Node against a stubbed Obsidian API; no Obsidian needed, no interference.
- L3 your Obsidian: obsidian_plugin_vault / obsidian_plugin_reload / obsidian_plugin_inspect / obsidian_plugin_eval act on your own running app through the CLI; this switches your window and steals focus, so it is only for verifying your real environment.
- L4 sandboxed Obsidian: the WebdriverIO suite scaffolded by obsidian_plugin_e2e runs a separate Obsidian (isolated config directory + vault copy); zero interference.
Acceptance rule (mandatory): obsidian_plugin_build passing does not mean the plugin works, and obsidian_plugin_test PASSing does not mean the UI was verified. If a change touches interface, rendering or interaction, it must actually be seen — in the sandboxed e2e tier (obsidian_plugin_e2e), or against the running app (obsidian_plugin_inspect action=screenshot) — and the reply must say what was seen.
Only test vaults created inside the session workspace may be modified; your own vaults are read-only, including CLI-side writes — plugin:enable / unrestrict rewrite whichever vault is in the active window, so the tools refuse to run them against a non-test vault. The default path never switches your window or steals focus.
【Naming rules】(enforced by the tools; use for self-checks too)
- id: lowercase letters/digits/dashes/underscores, no "obsidian", not ending with "plugin".
- name: no "Obsidian", not ending with "Plugin", not starting with "Obsi" or ending with "dian".
- description: no "Obsidian" / "This plugin", must end with . ? ! or ), ≤250 chars.