Resolves conflicts against the harness build-on-demand refactor (#321),
the develop/main deploy split (#317), and the flowmark reformat (#315/#316):
- harnesses/index.ts: register the two OpenCode harnesses inside
buildHarnesses() and drop their module-level constants, matching the
single-construction-path refactor
- deploy-plugins.yml: keep main's develop/main branch semantics with the
job counts updated for six plugin repos
- AGENTS.md / READMEs: fold the OpenCode V1/V2 mentions into main's
reflowed prose
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Our plugin reaches Claude two ways. The installer uses Anthropic's
official catalog, which pins getsentry/plugin-claude; adding our own
catalog by hand installs the same repo under a second id. Claude holds
both happily, so two plugins end up serving the same skills and both
resolve.
Claude had no cleanup hook, so nothing dropped the copy the installer
does not manage. It gets one, checking only whether the other id is
present -- a no-op for anyone who has only ever run the installer.
The direction is not the same as the other harnesses and is not meant to
be: Grok evicts the vendor catalog's copy to keep its direct-repo
install, because its marketplace install is TUI-only. The rule they share
is to keep whatever the harness installs and evict every other sentry.
The four harnesses were module-level constants, so importing the barrel
constructed all of them as a side effect and there were two ways to get
one: the singleton or the factory it was built from. A caller that needs
them configured differently could only use the factories and rebuild the
list by hand.
buildHarnesses() replaces the constant, leaving a single construction
path and no work at import time.
Skill and reference prose is the product here, and it had drifted into three
different wrapping styles. This is the mechanical pass that settles it: flowmark
with semantic line breaks, an 88-column wrap, typographic quotes and ellipses in
prose, and its safe cleanups. Fenced code is untouched. The tooling that keeps
it this way lands separately; this commit is the one-time reformat, so it can be
read as noise and skipped.
Two parts of it are not noise. Thirteen table rows across eight SDK references
held a code span with a raw `|` or a nested backtick, which GFM does not allow
and no formatter can round-trip: the pipe ends the cell early, so the
`tracePropagationTargets` row was quietly losing its description. Pipes are
escaped now, and the cells that showed a template literal name it in prose --
every one of those files already shows the real syntax in a fenced block
nearby.
The other part is file hygiene, off the Markdown path: a final newline on
.gitattributes and the two SVG assets, and a trailing blank line dropped from
skill-drift.yml.
Let callers pass an instruction after the install command and offer a
prefixed version on the clipboard once installation succeeds.
Co-authored-by: GPT-5 <noreply@openai.com>
The /seer command only wrapped what users can already do by asking the agent
natural-language questions directly against the Sentry MCP server, so it earned
its own maintenance surface (a command file, build wiring, and docs) for no real
capability. Remove the command along with the commands/ build plumbing
(copy_commands, per-agent build.sh calls, the deploy-plugins path trigger) and
every /seer reference across the READMEs, AGENTS.md, TELEMETRY.md, plugin
manifests, and concept docs.
After a successful install, ask one final question defaulting to yes and
copy a "Use the `sentry-get-started` skill for this project." prompt to
the clipboard so the user has an obvious first thing to try.
Install-only and gated on at least one agent being acted on, so remove
and no-op runs stay quiet. Clipboard copy is cross-platform (pbcopy,
clip, and wl-copy/xclip/xsel on Linux) and never throws -- when no
clipboard tool is available it falls back to printing the prompt.
Installing the Sentry plugin was a one-way door — there was no built-in
way to take it back out. Add a `remove` subcommand that mirrors install:
it reuses the detect and select steps, then uninstalls the plugin from
each chosen agent (claude plugin uninstall, codex plugin remove, grok
plugin uninstall, and deleting the Cursor checkout).
Removal only takes out our own plugin. Any marketplace we registered is
left in place — Claude's is Anthropic's shared official one, so
deregistering it could pull it out from under other plugins — and the
install-time cleanup of conflicting plugins does not run.
The UI is factored into a shared runFlow driven by a FlowMode descriptor
so install and remove share detection, selection, concurrency, and
output streaming while differing only in their tagline, prompt copy,
per-agent action, and closing line. The remove flow leads with a static
"Neuralyzing your agents of Sentry." header (no shimmer).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ships the updated installer README (install command + demo) to the npm
package page. craft's "simple" changelog policy requires the entry to exist
before prepare.
Add a tagline under the banner and rework the closing line so the run
opens and closes on the same beat ("teaching your agents to speak
Sentry" -> "your agents now speak Sentry") instead of a flat restart
hint.
On a color terminal the tagline animates: a bright band shimmers across
"speak Sentry" while the install runs, then settles to a static line.
It is painted as a header by a custom listr renderer (ShimmerRenderer)
so the step list renders normally beneath it; off a TTY (CI, pipes,
NO_COLOR) it stays a plain static line. The shimmer effect lives in its
own module, text-shimmer.ts.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When an install streams through an output sink, runStreaming piped the
command's stderr to the live view but never captured it, so a failure
fell through to runInstallCommand's generic "exit code N" message. The
interactive UI always passes a sink, so Listr failure text was almost
always that generic message instead of the agent's actual error.
Tee stderr: keep piping it to the sink for the live view, and also
buffer it into the result so the thrown error carries the real text.
Show what each agent is actually doing instead of a static spinner. An
optional output sink threads from the install task down through
install/update/cleanup to the shell runner; the real system spawns the
command and pipes its stdout/stderr into the task's stream, so progress
appears live under each agent's row. Detection probes still buffer and
parse as before — only the mutating commands stream.
Theme the renderer to match the Sentry banner: diamond task icons with a
small-to-large pulsing diamond spinner, streamed output grayed (per line,
so blank lines stay empty and removeEmptyLines can drop them) and kept on
screen via persistentOutput, an arrow prompt cursor with the gap moved
onto the checkbox icons to preserve alignment, and a blue hollow-diamond
prompt prefix. Also drop the Cursor restart note now that the closing
line covers it.
The install subtasks run under a parent "Installing plugins" task, which
collapses its children once it completes — folding away each agent's
resolved command and cleanup note. Set collapseSubtasks: false so the
per-agent rows and their output stay visible after the group finishes.
The closing line said "Restart your AI tools to load the Sentry plugin",
which is vague when only some of the detected agents were installed.
List the agents that actually received the plugin instead, e.g. "Restart
Claude Code and Codex to use Sentry with AI". Blocked or failed agents
are excluded since there is nothing to restart for them.
Switch every harness's installed-probe from substring-grepping plain
`plugin list` output to parsing the `--json` variant and matching on the
plugin's real identity. Claude and Codex match a marketplace-qualified
id; Grok matches our repo source with no marketplace, since the source
alone cannot tell a direct repo install from one made through the "xAI
Official" marketplace.
Add an optional `cleanup` step that runs before install to remove a
conflicting or legacy Sentry plugin that would otherwise shadow ours:
Codex removes the curated `sentry@openai-curated`, and Grok uninstalls a
marketplace-installed sentry so our direct-repo install resolves.
`cleanup` returns a short description of what it removed, which the
installer surfaces as persistent task output so the removal is visible
rather than silent.
Split the single `install` method into explicit `install` and `update`
so the orchestrator picks based on what detection already found, instead
of each harness re-probing its own listing.
Add the Craft release pipeline so packages/installer can be published to
npm as @sentry/ai.
- .craft.yml configures a single npm target (public scoped access) with a
tarball-name guard. There is deliberately no github target, so a release
creates no git tags and no GitHub releases -- nothing repo-wide implying
the skills/plugins are versioned by it.
- The release branch is scoped to `release-installer/<version>` via
releaseBranchPrefix, so it reads as a package release. craft creates it
during prepare and deletes it after publish, so it is transient.
- changelogPolicy is `simple` (matching sentry-javascript) and the
changelog lives with the package at packages/installer/CHANGELOG.md. The
entry is written by hand before releasing; `auto` would sweep this repo's
skill-drift and plugin churn into the installer changelog.
- release.yml runs `craft prepare` via the Sentry release bot App token.
It must be an App token rather than GITHUB_TOKEN so the pushed release
branch triggers release-build.yml, which packs the tarball and uploads
it as the SHA-named artifact Craft's GitHub provider expects.
- The package gains `files: ["dist", "CHANGELOG.md"]`, publishConfig.access
public, and an explicit LICENSE so the published tarball is complete
without relying on pnpm copying the root LICENSE.
Publishing runs from getsentry/publish after a team lead approves the
release issue; this repo only prepares the release and builds the artifact.
Add a pnpm workspace with a `packages/installer` package (`@sentry/ai`)
that provides a single CLI for installing the Sentry plugin into any
supported AI coding assistant: Claude Code, Codex, Cursor, and Grok.
The CLI (built on citty) exposes an `install` subcommand. By default it
shows an interactive selector pre-selecting the detected agents;
`--no-interactive`/`--yes` skips the prompt and installs every detected
agent — used for CI and unattended runs.
Each agent is a self-contained harness implementing a common strategy
interface — detect, isInstalled, canInstall, install — so adding a new
agent is just another module. System access (shell, fs, platform,
homedir) is injected through a SystemDeps seam, keeping every harness
unit-testable without side effects.
Behavior:
- Already-installed agents update in place rather than erroring or
no-opping: Cursor pulls, Grok/Claude use their update commands, Codex
re-adds (idempotent; it has no update command).
- Claude refreshes its marketplace index before installing, since a fresh
CLI ships a stale index that cannot resolve the plugin.
- canInstall gates prerequisites (Cursor needs git) and reports a clear
skip instead of a cryptic failure.
- One agent failing does not abort the rest, and the CLI exits non-zero
if any selected agent failed or was blocked.
- Cross-platform: binary detection uses where/which per OS, Cursor is
located via its per-OS install path, and git paths are quoted for
Windows spaces.
Distribution:
- rolldown bundles the npm package (deps external).
- fossilize builds standalone Node SEA binaries; --hole-punch drops
non-English ICU data to cut the download ~30%.
CI:
- A smoke-test matrix (Linux, macOS, Windows) installs the real agent
CLIs and runs the installer non-interactively, asserting the plugin
lands for every detected agent.
Instrumented with the Sentry Node SDK.