slidemind 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "slidemind",
3
+ "owner": {
4
+ "name": "statworx",
5
+ "url": "https://www.statworx.com"
6
+ },
7
+ "description": "slidemind — on-brand PowerPoint decks from your coding agent, via the slidemind add-in",
8
+ "plugins": [
9
+ {
10
+ "name": "slidemind",
11
+ "source": {
12
+ "source": "npm",
13
+ "package": "slidemind"
14
+ },
15
+ "description": "Build and edit native, on-brand PowerPoint decks against the active corporate design. Ships the slidemind CLI (on PATH inside Claude Code sessions) and both skills.",
16
+ "author": {
17
+ "name": "statworx"
18
+ },
19
+ "homepage": "https://github.com/STATWORX/intern-slidemind-cli",
20
+ "repository": "https://github.com/STATWORX/intern-slidemind-cli",
21
+ "license": "UNLICENSED",
22
+ "category": "productivity"
23
+ }
24
+ ]
25
+ }
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "slidemind",
3
- "version": "0.0.24",
4
- "description": "Connect Claude Code, Codex & opencode to the slidemind PowerPoint add-in to build and edit native, on-brand PowerPoint decks against the active corporate design.",
3
+ "version": "0.2.1",
4
+ "description": "Connect Claude Code to the slidemind PowerPoint add-in — build and edit native, on-brand PowerPoint decks against the active corporate design, from the terminal.",
5
5
  "author": {
6
- "name": "statworx"
6
+ "name": "statworx",
7
+ "url": "https://www.statworx.com"
7
8
  },
8
9
  "homepage": "https://github.com/STATWORX/intern-slidemind-cli",
10
+ "repository": "https://github.com/STATWORX/intern-slidemind-cli",
11
+ "license": "UNLICENSED",
9
12
  "keywords": [
10
13
  "presentation",
11
14
  "slides",
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "slidemind",
3
+ "version": "0.2.1",
4
+ "description": "Connect Codex to the slidemind PowerPoint add-in — build and edit native, on-brand PowerPoint decks against the active corporate design. Requires the slidemind CLI (npm install -g slidemind); the skills explain the install when it is missing.",
5
+ "author": {
6
+ "name": "statworx",
7
+ "url": "https://www.statworx.com"
8
+ },
9
+ "homepage": "https://github.com/STATWORX/intern-slidemind-cli",
10
+ "repository": "https://github.com/STATWORX/intern-slidemind-cli",
11
+ "license": "UNLICENSED",
12
+ "keywords": [
13
+ "presentation",
14
+ "slides",
15
+ "powerpoint",
16
+ "office-addin",
17
+ "slidemind"
18
+ ],
19
+ "skills": "./skills",
20
+ "interface": {
21
+ "displayName": "slidemind",
22
+ "shortDescription": "On-brand PowerPoint decks from Codex",
23
+ "developerName": "statworx",
24
+ "category": "Productivity",
25
+ "capabilities": [
26
+ "Skills"
27
+ ]
28
+ }
29
+ }
package/CLAUDE.md CHANGED
@@ -24,9 +24,18 @@ npm install -g slidemind
24
24
  slidemind init --for all # claude | codex | opencode | all | none
25
25
  ```
26
26
 
27
- `npx slidemind <command>` runs it without a global install. `slidemind update` is a thin wrapper over `npm install -g slidemind@latest` (`--ref <version>` to pin, `--for <target>` to control the redeploy). The `files` whitelist in `package.json` controls what ships (`bin/ src/ skills/ .claude-plugin/ CLAUDE.md README.md`); `archive/`, `docs/`, `scripts/`, and `test/` are excluded.
27
+ `npx slidemind <command>` runs it without a global install. `slidemind update` is a thin wrapper over `npm install -g slidemind@latest` (`--ref <version>` to pin, `--for <target>` to control the redeploy). The `files` whitelist in `package.json` controls what ships (`bin/ src/ skills/ .claude-plugin/ .codex-plugin/ CLAUDE.md README.md`); `archive/`, `docs/`, `scripts/`, `test/`, and `.agents/` are excluded.
28
28
 
29
- > The previous account-free channel (a private Azure Blob container + shared read SAS + `scripts/install.sh` curl-bootstrap) has been **retired** — see `archive/scripts/install.sh`. npm is the sole channel now.
29
+ Both agent harnesses can also install slidemind as a **plugin** — this private repo doubles as the marketplace (a public marketplace repo can be split out later; the files move as-is). The marketplace is named `slidemind`, NOT `statworx`: the team already registers a `statworx` marketplace from `STATWORX/intern-marketplace-test`, and both harnesses allow only one marketplace per name.
30
+
31
+ - **Claude Code** (one step, no `npm -g`): `/plugin marketplace add STATWORX/intern-slidemind-cli` → `/plugin install slidemind@slidemind`. The marketplace entry (`.claude-plugin/marketplace.json`) points at the **public npm package, unpinned** — Claude installs the latest tarball and the installed version comes from the tarball's `.claude-plugin/plugin.json`, so only the marketplace add needs repo access. The tarball's `bin/slidemind` + `bin/slidemind.cmd` shims land on PATH inside plugin sessions, so the plugin carries the CLI too.
32
+ - **Codex**: `codex plugin marketplace add STATWORX/intern-slidemind-cli` → `codex plugin add slidemind@slidemind`. Codex clones the repo (marketplace file `.agents/plugins/marketplace.json`; plugin manifest `.codex-plugin/plugin.json`; plugin source = repo root) and carries the skills only — the CLI still arrives via `npm install -g slidemind`, which the skills' remediation covers.
33
+
34
+ `slidemind init --for <target>` remains the universal fallback on all three harnesses; the Claude installer prints a dedup hint when it detects the plugin is also installed.
35
+
36
+ **Updating a plugin-installed CLI is `/plugin`, not `slidemind update`.** The Claude plugin ships its own copy of the CLI on the session's PATH, so `npm install -g slidemind@latest` drops a second, unrelated global and the session keeps running the old binary — a user following that advice would watch the update succeed and stay blocked on the add-in's version floor. `src/install-channel.mjs` detects the channel from the running code's path (plus `CLAUDE_PLUGIN_ROOT`) and every too-old-CLI remediation ends with `updateCliInstruction()`, so the message names the updater that actually replaces this binary; the `cli_update_required` rung of the readiness ladder also flips `actor` to `user` there, because the agent cannot drive `/plugin`.
37
+
38
+ > The previous account-free channel (a private Azure Blob container + shared read SAS + `scripts/install.sh` curl-bootstrap) has been **retired** — see `archive/scripts/install.sh`. npm is the sole binary channel now; the plugin marketplaces layer on top of it.
30
39
 
31
40
  ## Releasing
32
41
 
@@ -36,6 +45,8 @@ Releases are **automatic on every push to `main`**. The workflow at `.github/wor
36
45
  2. Otherwise → bumps the patch by 1, commits the bumped `package.json` back to `main`, then tags the new version. (No infinite loop: GitHub doesn't trigger workflows from commits made with the default `GITHUB_TOKEN`, and the workflow also skips if the actor is `github-actions[bot]`.)
37
46
  3. In both cases → creates a GitHub Release with auto-generated notes, then **`npm publish --access public`**.
38
47
 
48
+ Before tagging/publishing the workflow runs `scripts/sync-plugin-manifests.mjs`, which copies `package.json`'s version into `.claude-plugin/plugin.json` and `.codex-plugin/plugin.json` (Claude Code keys plugin updates off that version; Codex keys its plugin cache off it — the marketplace entries deliberately carry no version so they never drift). `scripts/release.mjs` runs the same sync locally, and `test/plugin-manifests.test.mjs` fails CI on drift.
49
+
39
50
  The publish step is gated on the `NPM_TOKEN` repo secret (an npm automation token with publish rights to `slidemind`): until it's set the workflow warns and skips publish (so tagging/releases keep working during rollout); once set, a publish failure fails the build. So most of the time you just merge to `main` and a new patch release falls out to npm.
40
51
 
41
52
  For a **minor or major** bump, run the local helper before pushing:
@@ -64,9 +75,15 @@ slidemind/
64
75
  ├── README.md end-user quickstart
65
76
  ├── CLAUDE.md this file
66
77
  ├── .claude-plugin/
67
- │ └── plugin.json Claude Code plugin manifest
78
+ │ ├── plugin.json Claude Code plugin manifest (version release-synced to package.json)
79
+ │ └── marketplace.json Claude Code marketplace — serves the plugin from public npm, unpinned
80
+ ├── .codex-plugin/
81
+ │ └── plugin.json Codex plugin manifest (version release-synced)
82
+ ├── .agents/
83
+ │ └── plugins/marketplace.json Codex marketplace — serves this repo (git clone) as the plugin; NOT in the npm tarball
68
84
  ├── bin/
69
- │ └── slidemind.mjs CLI dispatcher (ready, doctor, presentations, read, download-bundle, new, init, build, build-pptx, view-draft, push, ls engines, search, insert-slide, add-slide, install, pair/whoami/use/logout)
85
+ │ ├── slidemind.mjs CLI dispatcher (ready, doctor, presentations, read, download-bundle, new, init, build, build-pptx, view-draft, push, ls engines, search, insert-slide, add-slide, install, pair/whoami/use/logout)
86
+ │ └── slidemind + slidemind.cmd PATH shims for Claude Code plugin sessions (npm links slidemind.mjs itself)
70
87
  ├── skills/ canonical, installable skill payload — thin CLI workflow glue only
71
88
  │ ├── create-slides/
72
89
  │ │ └── SKILL.md authoring skill: stage-todo bootstrap + host gate + intake/plan + create flow +
@@ -86,7 +103,7 @@ slidemind/
86
103
  ├── archive/ retired code/assets (local exporter, icon library, brand design files) — NOT shipped
87
104
  ├── decks/ the user's working decks; sources are slides/*.jsx, design via .bundle-ref.json
88
105
  ├── docs/slidemind-cli-connect/ the connect architecture (bridge contract, bundle, engine, phasing)
89
- └── test/ node:test suites (bridge client/bundle/build-and-push/resolve-skill/lint-wrapper/packaging/engine-search/native-slides/cli-dispatch/cli-download-result)
106
+ └── test/ node:test suites (bridge client/bundle/build-and-push/resolve-skill/lint-wrapper/packaging/plugin-manifests/engine-search/native-slides/cli-dispatch/cli-download-result)
90
107
  ```
91
108
 
92
109
  The skills at the **root** of `skills/` are deliberate: that's the layout Claude Code, Codex (0.128+), and opencode all expect for skill auto-discovery — `<harness-root>/skills/<name>/SKILL.md`. There are **two** skills, each auto-discovered by `listSkills()` (no installer change to add one): `create-slides` (installs as `slidemind-create-slides`) owns the user-facing plan / create / edit / render workflow, and `search` (installs as `slidemind-search`) owns engine discovery + slide reuse (search → insert live / fold into a deck). Both are **brand-agnostic** — every brand rule lives in the per-CD bundle's `design.md` / `workflow/*.md`, which the skills point the agent at. (Pre-skills opencode versions used an `agent/` shim under `~/.config/opencode/`; the installer removes any leftover from those installs on every run.)
package/README.md CHANGED
@@ -133,6 +133,30 @@ Run any command without installing globally:
133
133
  npx slidemind <command>
134
134
  ```
135
135
 
136
+ ### Install as a plugin (Claude Code / Codex)
137
+
138
+ Both harnesses can install slidemind as a **plugin** from this repo's marketplace instead of the two-command npm flow. The repo is private, so the one-time `marketplace add` uses your existing GitHub credentials (`gh auth login`, a git credential helper, or SSH).
139
+
140
+ **Claude Code — fully self-contained (no `npm install -g` needed):**
141
+
142
+ ```
143
+ /plugin marketplace add STATWORX/intern-slidemind-cli
144
+ /plugin install slidemind@slidemind
145
+ ```
146
+
147
+ The plugin ships both skills *and* the CLI: under the hood Claude Code installs the public npm package and puts `slidemind` on `PATH` inside its sessions (the headless-Chrome heads-up above applies to this install too). Outside Claude Code sessions the command is not on your `PATH` — add the global install if you also want to drive the CLI by hand. Updates ship with every release; apply them via `/plugin`. If background marketplace refreshes fail against the private repo, use SSH for the marketplace add or set `CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE=1`.
148
+
149
+ **Codex — skills via plugin, CLI via npm:**
150
+
151
+ ```bash
152
+ codex plugin marketplace add STATWORX/intern-slidemind-cli
153
+ codex plugin add slidemind@slidemind
154
+ ```
155
+
156
+ Codex plugins carry the skills only — the CLI still comes from `npm install -g slidemind` (the skills walk you through it if it's missing). `slidemind init --for codex` remains the most robust path; it additionally writes an `~/.codex/AGENTS.md` pointer.
157
+
158
+ > Already ran `slidemind init` and switching to a plugin? Drop the copied skills once with `slidemind uninstall --for claude` (or `--for codex`) so they don't duplicate the plugin's.
159
+
136
160
  ---
137
161
 
138
162
  ## Connect to PowerPoint
package/bin/slidemind ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ # PATH shim for plugin sessions: Claude Code adds the plugin's bin/ to PATH, so
3
+ # this makes the command literally `slidemind` (bin/slidemind.mjs would resolve
4
+ # as `slidemind.mjs`). npm installs never use this file — npm links
5
+ # bin/slidemind.mjs itself via package.json "bin".
6
+ dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
7
+ exec node "$dir/slidemind.mjs" "$@"
@@ -0,0 +1,2 @@
1
+ @ECHO OFF
2
+ node "%~dp0slidemind.mjs" %*
package/bin/slidemind.mjs CHANGED
@@ -26,6 +26,13 @@ import os from "node:os";
26
26
  import path from "node:path";
27
27
  import { fileURLToPath, pathToFileURL } from "node:url";
28
28
 
29
+ // The only eager `src/` import: node-builtins only, and the version-floor
30
+ // ladder below is sync, so it cannot be lazily loaded like the rest.
31
+ import {
32
+ isClaudePluginInstall,
33
+ updateCliInstruction,
34
+ } from "../src/install-channel.mjs";
35
+
29
36
  const __filename = fileURLToPath(import.meta.url);
30
37
  const __dirname = path.dirname(__filename);
31
38
  const PACKAGE_ROOT = path.resolve(__dirname, "..");
@@ -1777,9 +1784,13 @@ function publicConnectionStatus(status, client) {
1777
1784
  // unmet precondition, or null when the connection is fully ready. `code` is the
1778
1785
  // machine-copeable reason an agent switches on; `actor` says who can clear it —
1779
1786
  // only `cli_update_required` is the AGENT's to fix (it can run `slidemind
1780
- // update`), every other rung needs a human at the add-in. The `message` strings
1781
- // are BYTE-IDENTICAL to the old connectionNextAction ladder so doctor's printed
1782
- // output never churns (connectionNextAction is now a thin projection over this).
1787
+ // update`), every other rung needs a human at the add-in. The one exception is
1788
+ // a plugin-installed CLI: `/plugin` is the only updater that replaces the
1789
+ // binary on the session's PATH, and the agent cannot drive it, so that rung
1790
+ // hands back to the user (see src/install-channel.mjs). The `message` strings
1791
+ // are otherwise BYTE-IDENTICAL to the old connectionNextAction ladder so
1792
+ // doctor's printed output never churns (connectionNextAction is now a thin
1793
+ // projection over this).
1783
1794
  // `slidemind ready` layers `ambiguous_design` on top and treats `pane_suspended`
1784
1795
  // as non-blocking (a render-ready-but-suspended window is still a design source).
1785
1796
  function connectionBlocker(pub) {
@@ -1805,11 +1816,11 @@ function connectionBlocker(pub) {
1805
1816
  if (outdated) {
1806
1817
  return {
1807
1818
  code: "cli_update_required",
1808
- actor: "agent",
1819
+ actor: isClaudePluginInstall() ? "user" : "agent",
1809
1820
  message:
1810
1821
  `This CLI is older than the minimum the '${outdated.env}' add-in supports` +
1811
1822
  `${outdated.minCliVersion ? ` (${outdated.minCliVersion})` : ""}. ` +
1812
- "Run `slidemind update` (or `npm install -g slidemind@latest`), then retry.",
1823
+ updateCliInstruction(),
1813
1824
  };
1814
1825
  }
1815
1826
  if ((pub.presentations ?? []).length === 0) {
@@ -2926,6 +2937,20 @@ async function cmdUpdate(rest) {
2926
2937
  const ui = await loadInstallerUi();
2927
2938
  ui.banner(pkg.version, "update");
2928
2939
 
2940
+ // A plugin-installed CLI cannot update itself this way: npm would drop a
2941
+ // second copy into the global prefix while the plugin session keeps running
2942
+ // its own. Say so instead of letting the user believe they are now current —
2943
+ // the global install is still worth doing (it is what a plain terminal
2944
+ // outside Claude Code picks up), so this warns and continues.
2945
+ if (isClaudePluginInstall()) {
2946
+ ui.step({
2947
+ status: "warn",
2948
+ label: "plugin",
2949
+ value:
2950
+ "this slidemind came from the Claude Code plugin — update it with `/plugin` → slidemind → update; the global install below does NOT replace it inside plugin sessions",
2951
+ });
2952
+ }
2953
+
2929
2954
  // Upgrade the global install straight from public npm. `@latest` (or a pinned
2930
2955
  // version) lets npm resolve + verify the tarball — no SAS, no checksum dance.
2931
2956
  const spec = ref
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidemind",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Connect Claude Code, Codex & opencode to the slidemind PowerPoint add-in — let your coding agent build and edit native, on-brand PowerPoint decks against your active corporate design, from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,6 +19,7 @@
19
19
  "src/",
20
20
  "skills/",
21
21
  ".claude-plugin/",
22
+ ".codex-plugin/",
22
23
  "CLAUDE.md",
23
24
  "README.md"
24
25
  ],
@@ -52,6 +52,7 @@ import {
52
52
  getDesignBundleForBrand,
53
53
  getDesignBundleForBrandAnyBackend,
54
54
  } from "./client.mjs";
55
+ import { updateCliInstruction } from "../install-channel.mjs";
55
56
 
56
57
  // Highest bundle wire-contract version this CLI understands. The add-in stamps
57
58
  // `schemaVersion` on every bundle; a higher value means the CLI is too old.
@@ -278,7 +279,7 @@ export async function materializeBundle(
278
279
  throw new Error(
279
280
  `This corporate design needs a newer slidemind (bundle schemaVersion ` +
280
281
  `${wire.schemaVersion}; this CLI supports ${CLI_MAX_BUNDLE_SCHEMA}).\n` +
281
- ` Run 'slidemind update' (or re-run the install one-liner), then retry.`,
282
+ ` ${updateCliInstruction()}`,
282
283
  );
283
284
  }
284
285
  const presFP = wire.presFP;
@@ -17,6 +17,7 @@ import {
17
17
  getSessionFor,
18
18
  readSessions,
19
19
  } from "./config.mjs";
20
+ import { updateCliInstruction } from "../install-channel.mjs";
20
21
 
21
22
  // This CLI's own version, for the add-in's minCliVersion floor (see
22
23
  // assertCliVersionSupported). Read lazily from the package manifest so the
@@ -57,8 +58,7 @@ export function compareCliVersions(a, b) {
57
58
  function cliUpdateRequiredError(min) {
58
59
  const err = new Error(
59
60
  `slidemind CLI ${cliVersion()} is older than the minimum this add-in ` +
60
- `supports (${min}). Run \`slidemind update\` (or ` +
61
- "`npm install -g slidemind@latest`), then retry.",
61
+ `supports (${min}). ${updateCliInstruction()}`,
62
62
  );
63
63
  err.code = "cli_update_required";
64
64
  return err;
@@ -0,0 +1,61 @@
1
+ // Which channel installed the CLI that is running right now?
2
+ //
3
+ // npm (`npm install -g slidemind`, or `npx`) is the default and the one every
4
+ // "your CLI is too old" remediation used to assume. Claude Code's plugin
5
+ // channel breaks that assumption: the plugin ships its OWN copy of the CLI and
6
+ // puts it on the plugin session's PATH, so `npm install -g slidemind@latest`
7
+ // installs a second, unrelated global and the session keeps running the old
8
+ // plugin copy. A plugin user following the npm remediation would watch the
9
+ // update succeed and stay blocked on the add-in's version floor forever.
10
+ //
11
+ // Detection is by the path this file lives at — where the running code came
12
+ // from — not by env, so it holds for any process the plugin session spawns.
13
+ // `CLAUDE_PLUGIN_ROOT` is honoured as a secondary signal when Claude Code
14
+ // exports it.
15
+ //
16
+ // Codex is deliberately NOT detected: Codex plugins carry the skills only (they
17
+ // cannot put a bin on PATH), so a Codex-plugin session always runs the npm CLI
18
+ // and the npm remediation is already correct there.
19
+
20
+ import path from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+
23
+ const PACKAGE_ROOT = path.resolve(
24
+ path.dirname(fileURLToPath(import.meta.url)),
25
+ "..",
26
+ );
27
+
28
+ // `~/.claude/plugins/cache/<marketplace>/<plugin>/…` — a `plugins` segment
29
+ // directly under `.claude`. Matching the pair (not either half alone) keeps a
30
+ // user's own `~/dev/.claude/plugins`-shaped checkout from being the only thing
31
+ // that can false-positive.
32
+ function underClaudePlugins(root) {
33
+ const segs = path.resolve(root).split(/[\\/]+/);
34
+ for (let i = 1; i < segs.length; i += 1) {
35
+ if (segs[i] === "plugins" && segs[i - 1] === ".claude") return true;
36
+ }
37
+ return false;
38
+ }
39
+
40
+ export function isClaudePluginInstall(root = PACKAGE_ROOT) {
41
+ const resolved = path.resolve(root);
42
+ if (underClaudePlugins(resolved)) return true;
43
+ const declared = process.env.CLAUDE_PLUGIN_ROOT;
44
+ if (declared) {
45
+ const rel = path.relative(path.resolve(declared), resolved);
46
+ if (rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel))) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+
53
+ // The one sentence every version-floor / too-old-CLI message ends with, so the
54
+ // remediation always names the updater that actually replaces THIS binary.
55
+ export function updateCliInstruction() {
56
+ return isClaudePluginInstall()
57
+ ? "This CLI came from the slidemind Claude Code plugin, so update it there: " +
58
+ "`/plugin` → slidemind → update (a global `npm install -g slidemind@latest` " +
59
+ "installs a separate copy and will NOT change the `slidemind` this session runs)."
60
+ : "Run `slidemind update` (or `npm install -g slidemind@latest`), then retry.";
61
+ }
@@ -78,6 +78,19 @@ function unregisterMcpServer() {
78
78
  return false;
79
79
  }
80
80
 
81
+ // ~/.claude/plugins/cache/<marketplace>/slidemind/ — presence means the Claude
82
+ // Code plugin is also installed; skills copied by `init` duplicate its skills.
83
+ function pluginInstallDetected() {
84
+ const cacheRoot = path.join(claudeRoot(), "plugins", "cache");
85
+ try {
86
+ return fs
87
+ .readdirSync(cacheRoot)
88
+ .some((mp) => fs.existsSync(path.join(cacheRoot, mp, NAMESPACE)));
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
81
94
  export async function install({ packageRoot, flags }) {
82
95
  const link = isLinkMode(flags);
83
96
  const force = isForce(flags);
@@ -108,6 +121,15 @@ export async function install({ packageRoot, flags }) {
108
121
  if (unregisterMcpServer()) {
109
122
  ui.step({ status: "remove", label: "mcp server", value: "removed legacy registration (slidemind is a CLI)" });
110
123
  }
124
+
125
+ if (pluginInstallDetected()) {
126
+ ui.step({
127
+ status: "info",
128
+ label: "plugin",
129
+ value:
130
+ "the slidemind Claude Code plugin is also installed — these copied skills duplicate its skills; plugin users can drop them with `slidemind uninstall --for claude`",
131
+ });
132
+ }
111
133
  }
112
134
 
113
135
  export async function uninstall() {