Add Herdr plugin manifest and launcher - #90
Conversation
Herdr Studio can now be installed and managed with herdr plugin install powerfooI/herdr-studio. The thin-launcher manifest builds the standalone binary with Bun and exposes start, restart, status, url, version, and uninstall actions on Linux, macOS, and Windows, delegating to the binary's service CLI. prepare-release now keeps the manifest version in sync with the package versions.
There was a problem hiding this comment.
🟡 Changes recommended
The new URL action currently includes the auth token even for loopback binds (leak risk) and the manifest version parsing/replacement is unnecessarily brittle compared to the existing package.json version logic.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds Herdr plugin packaging for Herdr Studio by introducing a plugin manifest and a thin “launcher” script that maps Herdr action verbs to the standalone herdr-gui binary’s service CLI, and updates release tooling/docs so the manifest version is bumped alongside existing release files.
Changes:
- Add
herdr-plugin.tomldefining build + action commands (thin-launcher pattern viascripts/studio-plugin.ts). - Add
scripts/studio-plugin.tsto build on demand and delegatestart|restart|status|version|uninstalltoherdr-gui service ..., plus aurlhelper. - Update
scripts/prepare-release.ts+ tests and docs/changelog to include bumpingherdr-plugin.tomlduring release prep.
File summaries
| File | Description |
|---|---|
| scripts/studio-plugin.ts | New plugin shim that builds the standalone binary when needed and dispatches plugin verbs to herdr-gui service / URL printing. |
| scripts/prepare-release.ts | Extends release prep to validate and bump herdr-plugin.toml version alongside package versions and changelog rotation. |
| scripts/prepare-release.test.ts | Adds unit coverage for parsing/replacing manifest version fields. |
| herdr-plugin.toml | New Herdr plugin manifest defining platforms, build command, and action verb mappings. |
| CHANGELOG.md | Notes the new plugin install/manage capability under Unreleased. |
| AGENTS.md | Updates release process docs to include bumping herdr-plugin.toml. |
Review details
Suppressed comments (1)
scripts/prepare-release.ts:73
- replaceManifestVersion has the same column-0-only limitation as parseManifestVersion, and it also hardcodes the replacement without preserving any indentation. Use a whitespace-tolerant regex, compare against the right capture group, and reuse the captured indentation when writing the replacement line.
const match = /^version = "([^"]+)"/m.exec(manifestText);
if (!match || match.index === undefined) {
throw new Error('herdr-plugin.toml has no top-level "version" field');
}
if (match[1] !== expectedCurrent) {
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The panel entrypoint opens a popup terminal pane inside the Herdr TUI showing service status, the login URL, and the version, with single-key start, restart, and uninstall controls. Unlike fire-and-forget plugin actions, pane commands own their terminal, so output is visible directly.
README quick start mentions herdr plugin install alongside the release installer, which now reads platform-neutral with Windows archives as a first-class option. The deployment guide gains a Herdr plugin section covering actions, the async command log, and the interactive panel pane including the popup vs. regular-pane placement distinction.
Only append the login token to the url action for non-loopback binds, matching the server's authRequired rule, and URL-encode it. Make the manifest version parser whitespace-tolerant like the package.json parser.
There was a problem hiding this comment.
🟡 Changes recommended
The new plugin shim has verified correctness issues (env parsing mismatch and panel lifecycle cleanup) that can lead to wrong URLs and hung processes in real plugin usage.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 3
- Review effort level: Lite
computeUrl now parses the service environment with the same rules as the server's own loader (export prefix, whitespace, quoted values). The panel restores the terminal and exits on stdin end/close and SIGTERM/SIGINT, with idempotent cleanup, and the header comment describes which verbs build and which only read on-disk state.
There was a problem hiding this comment.
🟡 Changes recommended
The new plugin build verb currently installs dependencies only at the repo root, which is likely to break clean plugin installs because web/ and server/ have their own package.json dependencies.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Review effort level: Lite
The repo is not a Bun workspace, so the plugin build now installs dependencies in the root, web, and server package trees, matching the documented dev setup. Pure shim logic (readServiceEnv, computeUrl token and host rules) is exported behind an import.meta.main guard and covered by filesystem-fixture tests.
There was a problem hiding this comment.
🟢 Approval recommended
The changes are coherent and well-tested for the newly introduced parsing/URL logic, and the plugin launcher aligns with the server’s established service config/token conventions.
Review details
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Lite
The plugin path builds from source and requires Bun on the user's machine, which is the wrong bar for the primary install audience. The deployment guide keeps the full plugin section for those who look for it.
There was a problem hiding this comment.
🔵 Needs a closer look
The new statusText() logic in scripts/studio-plugin.ts misclassifies installed-but-inactive services as “not installed” by treating any non-zero service status exit code as absence, which will mislead users in the panel/action output.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
scripts/studio-plugin.ts:187
- statusText() treats any non-zero exit code from
herdr-gui service statusas "not installed", but on systemd (and potentially other service managers)statusreturns non-zero for installed-but-inactive/failed services while still printing useful status output. This makes the panel/action status misleading and hides stderr/stdout details that could help users diagnose the service state.
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Lite
Summary
herdr-plugin.tomlso Herdr Studio is installable viaherdr plugin install powerfooI/herdr-studioand discoverable in the Herdr plugin marketplace (thin-launcher pattern, same as collie)scripts/studio-plugin.tsshim:build(Bun) plusstart/restart/status/url/version/uninstallactions delegating to the compiled binary's service CLI (systemd, launchd, Windows Task Scheduler); the verb set is a frozen contractpanelpopup pane inside the Herdr TUI: service status, login URL, version, and single-key start/restart/uninstall — pane commands own their terminal, so unlike async plugin actions the output is visible directlyprepare-releasenow bumps the manifest version alongside the three package.json versionsmin_herdr_version = "0.7.2"(terminal observe/control + snapshot surface)Verification
bun run format/lint/typecheck/test— 862 tests passherdr plugin link+plugin action list: manifest registers, all actions presentherdr plugin pane open --plugin herdr.studio --entrypoint panelreturns ok and the panel renders in the TUIbuildverb produces a working standalone binary