supipowers 1.0.0 → 1.1.0

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.
Files changed (51) hide show
  1. package/README.md +152 -60
  2. package/bin/.omp/SYSTEM.md +77 -0
  3. package/bin/.omp/supipowers/sessions/events.db +0 -0
  4. package/bin/.omp/supipowers/sessions/events.db-shm +0 -0
  5. package/bin/.omp/supipowers/sessions/events.db-wal +0 -0
  6. package/bin/install.ts +150 -64
  7. package/bin/local-install.sh +39 -0
  8. package/package.json +10 -4
  9. package/skills/planning/SKILL.md +6 -1
  10. package/skills/qa-strategy/SKILL.md +86 -63
  11. package/skills/release/SKILL.md +62 -0
  12. package/src/bootstrap.ts +29 -0
  13. package/src/commands/config.ts +12 -21
  14. package/src/commands/fix-pr.ts +18 -0
  15. package/src/commands/model-picker.ts +339 -0
  16. package/src/commands/model.ts +247 -0
  17. package/src/commands/plan.ts +18 -0
  18. package/src/commands/qa.ts +9 -39
  19. package/src/commands/release.ts +201 -27
  20. package/src/commands/review.ts +18 -0
  21. package/src/commands/run.ts +195 -28
  22. package/src/config/defaults.ts +2 -1
  23. package/src/config/loader.ts +13 -4
  24. package/src/config/model-config.ts +135 -0
  25. package/src/config/model-registry-instance.ts +4 -0
  26. package/src/config/model-registry.ts +58 -0
  27. package/src/config/model-resolver.ts +113 -0
  28. package/src/deps/registry.ts +41 -7
  29. package/src/orchestrator/dispatcher.ts +279 -71
  30. package/src/orchestrator/progress-renderer.ts +114 -5
  31. package/src/orchestrator/run-progress.ts +18 -1
  32. package/src/planning/prompt-builder.ts +2 -2
  33. package/src/platform/omp.ts +24 -3
  34. package/src/platform/pi.ts +17 -2
  35. package/src/platform/types.ts +13 -0
  36. package/src/qa/config.ts +0 -1
  37. package/src/qa/prompt-builder.ts +47 -24
  38. package/src/qa/scripts/run-e2e-tests.sh +46 -14
  39. package/src/qa/types.ts +0 -1
  40. package/src/release/changelog.ts +163 -0
  41. package/src/release/detector.ts +69 -0
  42. package/src/release/executor.ts +134 -0
  43. package/src/release/prompt.ts +71 -0
  44. package/src/release/version.ts +54 -0
  45. package/src/storage/plans.ts +7 -1
  46. package/src/storage/runs.ts +1 -1
  47. package/src/types.ts +80 -2
  48. package/src/qa/scripts/ensure-playwright.sh +0 -38
  49. package/src/release/analyzer.ts +0 -22
  50. package/src/release/notes.ts +0 -26
  51. package/src/release/publisher.ts +0 -33
package/README.md CHANGED
@@ -1,8 +1,18 @@
1
- <img width="1584" height="672" alt="image" src="https://github.com/user-attachments/assets/ec0f3658-54d7-4471-91ba-39297191f055" />
1
+ <img width="1584" height="672" alt="supipowers" src="https://github.com/user-attachments/assets/ec0f3658-54d7-4471-91ba-39297191f055" />
2
+
3
+ <div align="center">
2
4
 
3
5
  # Supipowers
4
6
 
5
- Agentic workflows for [OMP](https://github.com/can1357/oh-my-pi). Plan features, orchestrate sub-agents, run quality gates, and ship releases — all from slash commands.
7
+ [![npm version](https://img.shields.io/npm/v/supipowers?style=flat-square)](https://www.npmjs.com/package/supipowers)
8
+ [![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
9
+
10
+ Agentic workflows for [Pi](https://github.com/mariozechner/pi-coding-agent) and [OMP](https://github.com/can1357/oh-my-pi) coding agents.
11
+ Plan features, orchestrate sub-agents, run quality gates, fix PRs, manage MCP servers, and ship releases. All from slash commands.
12
+
13
+ [Install](#install) · [Commands](#commands) · [How it works](#how-it-works) · [Configuration](#configuration) · [Development](#development)
14
+
15
+ </div>
6
16
 
7
17
  ## Install
8
18
 
@@ -10,33 +20,64 @@ Agentic workflows for [OMP](https://github.com/can1357/oh-my-pi). Plan features,
10
20
  bunx supipowers@latest
11
21
  ```
12
22
 
13
- The installer checks for OMP, helps you install it if needed, copies supipowers into `~/.omp/agent/`, and optionally installs LSP servers for better code intelligence.
14
-
15
- Re-running the installer updates supipowers if a newer version is available. Already up-to-date installs are detected and skipped.
23
+ The installer detects which agent you're running (Pi or OMP), copies supipowers into the right directory, and optionally sets up LSP servers for better code intelligence. Re-running the installer upgrades to the latest version if one is available.
16
24
 
17
- ### Update from inside OMP
25
+ ### Update from inside your agent
18
26
 
19
27
  ```
20
28
  /supi:update
21
29
  ```
22
30
 
23
- Checks npm for the latest version, downloads and installs it no prompts, no restart needed.
31
+ Checks npm for the latest version, downloads and installs it. No prompts, no restart needed.
24
32
 
25
- ## Commands
33
+ ## Requirements
34
+
35
+ ### Required
36
+
37
+ | Dependency | What it's for |
38
+ | --- | --- |
39
+ | [Pi](https://github.com/mariozechner/pi-coding-agent) or [OMP](https://github.com/can1357/oh-my-pi) | The coding agent that supipowers extends |
40
+ | [Bun](https://bun.sh) | Runtime (provides bun:sqlite with FTS5 for full-text search) |
41
+ | [Git](https://git-scm.com) | Version control (used by the installer and context-mode setup) |
42
+
43
+ ### Optional
44
+
45
+ The installer scans for these and offers to install any that are missing. Everything works without them, but each one unlocks additional capabilities.
46
+
47
+ | Dependency | Category | What it enables | Install command |
48
+ | --- | --- | --- | --- |
49
+ | [mcpc](https://github.com/apify/mcpc) | MCP | MCP server management via `/supi:mcp` | `npm install -g @apify/mcpc` |
50
+ | [context-mode](https://github.com/mksglu/context-mode) | MCP | Context window protection (auto-routes large outputs through sandboxed execution) | Installed as extension via `git clone` + `npm install` |
51
+ | [typescript-language-server](https://github.com/typescript-language-server/typescript-language-server) | LSP | TypeScript/JavaScript diagnostics, references, completions | `bun add -g typescript-language-server typescript` |
52
+ | [Pyright](https://github.com/microsoft/pyright) | LSP | Python type checking and language features | `pip install pyright` |
53
+ | [rust-analyzer](https://rust-analyzer.github.io) | LSP | Rust language server | `rustup component add rust-analyzer` |
54
+ | [gopls](https://pkg.go.dev/golang.org/x/tools/gopls) | LSP | Go language server | `go install golang.org/x/tools/gopls@latest` |
55
+ | [playwright-cli](https://github.com/microsoft/playwright-cli) | Testing | Interactive browser exploration for E2E flow discovery via `/supi:qa --e2e` | `npm install -g @playwright/cli@latest` |
56
+ | [Playwright Test](https://playwright.dev) | Testing | Test runner for E2E test execution via `run-e2e-tests.sh` | `npm install -g @playwright/cli@latest` |
26
57
 
27
- | Command | What it does |
28
- | ---------------- | ------------------------------------------------ |
29
- | `/supi` | Interactive menu — commands and project status |
30
- | `/supi:plan` | Collaborative planning with task breakdown |
31
- | `/supi:run` | Execute a plan with parallel sub-agents |
32
- | `/supi:review` | Quality gates at chosen depth |
33
- | `/supi:qa` | Run test suite and E2E pipeline |
34
- | `/supi:release` | Version bump, release notes, publish |
35
- | `/supi:config` | Interactive settings (TUI) |
36
- | `/supi:status` | Check running sub-agents and progress |
37
- | `/supi:update` | Update supipowers to latest version |
58
+ LSP servers are language-specific. You only need the ones matching the languages in your project. Sub-agents use them to check diagnostics and find references before making changes.
38
59
 
39
- Commands like `/supi`, `/supi:config`, `/supi:status`, and `/supi:update` open native OMP TUI dialogs — they don't send chat messages or trigger the AI.
60
+ > [!TIP]
61
+ > Run `/supi:doctor` at any time to check which dependencies are installed and which are missing.
62
+
63
+ ## Commands
64
+
65
+ | Command | What it does |
66
+ | --------------- | ----------------------------------------------------- |
67
+ | `/supi` | Interactive menu with commands and project status |
68
+ | `/supi:plan` | Collaborative planning with structured task breakdown |
69
+ | `/supi:run` | Execute a plan with parallel sub-agents |
70
+ | `/supi:review` | Quality gates at chosen depth |
71
+ | `/supi:qa` | E2E testing pipeline with playwright-cli |
72
+ | `/supi:release` | Version bump, release notes, publish |
73
+ | `/supi:fix-pr` | Assess and fix PR review comments |
74
+ | `/supi:mcp` | Manage MCP servers (connect, disconnect, list) |
75
+ | `/supi:config` | Interactive settings (TUI) |
76
+ | `/supi:status` | Check running sub-agents and progress |
77
+ | `/supi:doctor` | Diagnose extension health and configuration |
78
+ | `/supi:update` | Update supipowers to latest version |
79
+
80
+ Commands like `/supi`, `/supi:config`, `/supi:status`, and `/supi:update` open native TUI dialogs. They don't send chat messages or trigger the AI.
40
81
 
41
82
  ### Planning
42
83
 
@@ -44,7 +85,7 @@ Commands like `/supi`, `/supi:config`, `/supi:status`, and `/supi:update` open n
44
85
  /supi:plan add authentication to the API
45
86
  ```
46
87
 
47
- Starts an interactive planning session: clarifying questions, approach proposals, then a structured task breakdown saved to `.omp/supipowers/plans/`.
88
+ Starts an interactive session: clarifying questions, approach proposals, then a structured task breakdown saved to `.omp/supipowers/plans/` (or the Pi equivalent).
48
89
 
49
90
  For simple tasks, skip the brainstorming:
50
91
 
@@ -60,7 +101,7 @@ For simple tasks, skip the brainstorming:
60
101
 
61
102
  Loads the latest plan and executes it with sub-agent orchestration. Tasks marked `[parallel-safe]` run concurrently (up to the configured limit). Sequential tasks respect their dependency chains.
62
103
 
63
- The orchestration loop: dispatch batch collect results detect conflicts retry failures next batch. If interrupted, re-running picks up where it left off.
104
+ The orchestration loop: dispatch batch, collect results, detect conflicts, retry failures, next batch. If interrupted, re-running picks up where it left off.
64
105
 
65
106
  ### Quality review
66
107
 
@@ -81,7 +122,16 @@ When no flag is provided, a TUI picker lets you choose the review profile intera
81
122
  /supi:qa --e2e # Playwright / E2E only
82
123
  ```
83
124
 
84
- Detects your test framework on first run (vitest, jest, pytest, cargo test, go test) and caches it. When no flag is provided, a TUI picker lets you choose the scope.
125
+ Detects your test framework on first run (vitest, jest, pytest, cargo test, go test) and caches it. E2E mode (`--e2e`) uses `playwright-cli` to run browser tests autonomously. When no flag is provided, a TUI picker lets you choose the scope.
126
+
127
+ ### Fix PR
128
+
129
+ ```
130
+ /supi:fix-pr # auto-detects current branch PR
131
+ /supi:fix-pr 42 # targets PR #42
132
+ ```
133
+
134
+ Pulls review comments from GitHub, assesses each one (some comments deserve pushback, not code changes), then fixes what needs fixing. Tracks sessions so you can pick up where you left off.
85
135
 
86
136
  ### Release
87
137
 
@@ -91,13 +141,35 @@ Detects your test framework on first run (vitest, jest, pytest, cargo test, go t
91
141
 
92
142
  Analyzes commits since last tag, suggests a version bump, generates release notes, and publishes. On first run, a TUI picker lets you choose your pipeline (npm, GitHub release, or manual).
93
143
 
144
+ ### MCP servers
145
+
146
+ ```
147
+ /supi:mcp
148
+ ```
149
+
150
+ Register, connect, and manage MCP (Model Context Protocol) servers through supipowers. Each server gets auto-generated trigger rules so the agent knows when to use its tools without being told explicitly.
151
+
152
+ ## How it works
153
+
154
+ Supipowers runs as an extension inside Pi or OMP. A platform abstraction layer handles the API differences between the two agents, so every command works the same regardless of which agent you're using.
155
+
156
+ **Sub-agent orchestration.** Plans are broken into batches of parallel-safe tasks. Each batch dispatches sub-agents with full tool access (file editing, bash, LSP). After a batch completes, the orchestrator checks for file conflicts, retries failures, and moves to the next batch.
157
+
158
+ **Quality gates.** Composable checks selected by profile. LSP diagnostics surface real type errors. AI review catches logic issues. Test gates run your actual test suite. Gates report issues with severity levels (error, warning, info).
159
+
160
+ **LSP integration.** Sub-agents query LSP before making changes (find references, check diagnostics). If no LSP is active, everything still works, just with less precision. The installer offers to set up LSP servers during installation.
161
+
162
+ **Context-mode integration.** When the [context-mode](https://github.com/ogrodev/context-mode) MCP server is detected, supipowers injects routing hooks that protect the agent's context window. Large command outputs, file reads, and HTTP calls are automatically routed through sandboxed execution so only summaries enter the conversation.
163
+
164
+ **Update checking.** On session start, supipowers checks npm for a newer version in the background. If one is available, a notification tells you to run `/supi:update`.
165
+
94
166
  ## Configuration
95
167
 
96
168
  ```
97
169
  /supi:config
98
170
  ```
99
171
 
100
- Opens an interactive settings screen with all configuration options. Select a setting to change its value toggles flip instantly, selects open a picker, text fields open an input dialog.
172
+ Opens an interactive settings screen. Select a setting to change its value: toggles flip instantly, selects open a picker, text fields open an input dialog.
101
173
 
102
174
  ### Profiles
103
175
 
@@ -118,65 +190,83 @@ Create custom profiles in `.omp/supipowers/profiles/`.
118
190
  "defaultProfile": "thorough",
119
191
  "orchestration": {
120
192
  "maxParallelAgents": 3, // concurrent sub-agents per batch
121
- "maxFixRetries": 2, // retry failed tasks
122
- "maxNestingDepth": 2, // sub-agent nesting limit
123
- "modelPreference": "auto"
193
+ "maxFixRetries": 2, // retry failed tasks
194
+ "maxNestingDepth": 2, // sub-agent nesting limit
195
+ "modelPreference": "auto",
124
196
  },
125
197
  "lsp": {
126
- "setupGuide": true
198
+ "setupGuide": true,
127
199
  },
128
200
  "qa": {
129
201
  "framework": null, // auto-detected and cached
130
- "command": null
131
- }
202
+ "command": null,
203
+ },
132
204
  }
133
205
  ```
134
206
 
135
- Config is stored in `~/.omp/agent/extensions/supipowers/` and managed entirely through `/supi:config`.
136
-
137
- ## How it works
207
+ Config lives in `~/.omp/agent/extensions/supipowers/` (OMP) or `~/.pi/agent/extensions/supipowers/` (Pi) and is managed entirely through `/supi:config`.
138
208
 
139
- Supipowers is built on OMP's extension API. Every command is an immediate action — no state machine, no workflow phases.
209
+ ## Skills
140
210
 
141
- **Sub-agent orchestration**: Plans are broken into batches of parallel-safe tasks. Each batch dispatches sub-agents with full OMP tool access (file editing, bash, LSP). After a batch completes, the orchestrator checks for file conflicts, retries failures, and moves to the next batch.
211
+ Supipowers ships with prompt skills that commands load at runtime to steer AI sessions:
142
212
 
143
- **Quality gates**: Composable checks selected by profile. LSP diagnostics feed real type errors. AI review catches logic issues. Test gates run your actual test suite. Gates report issues with severity levels (error/warning/info).
213
+ | Skill | Used by |
214
+ | ----------------------- | -------------------------------------- |
215
+ | `planning` | `/supi:plan` |
216
+ | `code-review` | `/supi:review` |
217
+ | `debugging` | Failure retry loop |
218
+ | `qa-strategy` | `/supi:qa` |
219
+ | `fix-pr` | `/supi:fix-pr` |
220
+ | `tdd` | Plan tasks with test-first annotations |
221
+ | `verification` | Pre-completion checks |
222
+ | `receiving-code-review` | Review comment assessment |
223
+ | `context-mode` | Context-mode routing hooks |
144
224
 
145
- **LSP integration**: Sub-agents query LSP before making changes (find references, check diagnostics). If no LSP is active, everything still works — just better with it. The installer offers to set up LSP servers during installation.
146
-
147
- **Update checking**: On session start, supipowers checks npm for a newer version in the background. If one is available, a notification tells you to run `/supi:update`.
225
+ Skills are markdown files in `skills/`. They're loaded on demand, not bundled at build time.
148
226
 
149
227
  ## Project structure
150
228
 
151
229
  ```
152
230
  src/
153
- index.ts # extension entry point + update checker
154
- commands/ # slash command handlers
231
+ index.ts # extension entry + platform detection
232
+ bootstrap.ts # command registration orchestrator
233
+ platform/ # dual-platform abstraction (Pi + OMP)
234
+ detect.ts, types.ts, pi.ts, omp.ts
235
+ commands/ # one file per slash command
155
236
  supi.ts, plan.ts, run.ts, review.ts, qa.ts, release.ts,
156
- config.ts, status.ts, update.ts
237
+ fix-pr.ts, mcp.ts, config.ts, status.ts, doctor.ts, update.ts
157
238
  orchestrator/ # sub-agent dispatch & coordination
158
239
  batch-scheduler.ts, dispatcher.ts, result-collector.ts,
159
240
  conflict-resolver.ts, prompts.ts
241
+ planning/ # plan writing & review prompts
242
+ plan-writer-prompt.ts, plan-reviewer.ts,
243
+ spec-reviewer.ts, prompt-builder.ts
160
244
  quality/ # composable quality gates
161
245
  gate-runner.ts, lsp-gate.ts, ai-review-gate.ts, test-gate.ts
162
246
  qa/ # QA pipeline
163
- detector.ts, runner.ts, report.ts
247
+ session.ts, matrix.ts, prompt-builder.ts, config.ts
248
+ fix-pr/ # PR comment assessment & fixing
249
+ prompt-builder.ts, config.ts, types.ts
250
+ mcp/ # MCP server gateway
251
+ gateway.ts, registry.ts, activation.ts, triggers.ts,
252
+ lifecycle.ts, manager-tool.ts, mcpc.ts, config.ts
253
+ context-mode/ # context-mode integration
254
+ hooks.ts, routing.ts, detector.ts, installer.ts,
255
+ compressor.ts, event-store.ts, event-extractor.ts,
256
+ snapshot-builder.ts
164
257
  lsp/ # LSP integration
165
258
  detector.ts, bridge.ts, setup-guide.ts
166
- notifications/ # rich inline notifications
167
- renderer.ts, types.ts
168
- config/ # configuration & profiles
169
- loader.ts, profiles.ts, defaults.ts, schema.ts
170
- storage/ # persistence
171
- plans.ts, runs.ts, reports.ts
172
259
  release/ # release automation
173
260
  analyzer.ts, notes.ts, publisher.ts
261
+ config/ # configuration & profiles
262
+ loader.ts, profiles.ts, defaults.ts, schema.ts
263
+ storage/ # persistence layer
264
+ plans.ts, runs.ts, reports.ts, specs.ts,
265
+ qa-sessions.ts, fix-pr-sessions.ts
266
+ notifications/ # rich inline notifications
267
+ renderer.ts, types.ts
174
268
  types.ts # shared type definitions
175
- skills/
176
- planning/SKILL.md
177
- code-review/SKILL.md
178
- debugging/SKILL.md
179
- qa-strategy/SKILL.md
269
+ skills/ # runtime-loaded prompt skills
180
270
  bin/
181
271
  install.mjs # bunx installer
182
272
  ```
@@ -187,15 +277,17 @@ bin/
187
277
  git clone https://github.com/ogrodev/supipowers.git
188
278
  cd supipowers
189
279
  bun install
190
- bun run test # run tests
191
- bun run typecheck # type checking
192
- bun run test:watch # watch mode
280
+ bun test # run all tests
281
+ bun run typecheck # type checking
282
+ bun run test:watch # watch mode
283
+ bun run build # emit to dist/
193
284
  ```
194
285
 
195
- ## Requirements
286
+ The test suite mirrors the `src/` structure under `tests/`. Tests use Vitest with global imports and inline mocks (no module-level `vi.mock` calls). Filesystem tests use temp directories created in `beforeEach`.
287
+
288
+ > [!NOTE]
289
+ > Supipowers works with both Pi and OMP. The platform abstraction in `src/platform/` normalizes API differences (event names, tool registration, message delivery) so you can develop against either agent.
196
290
 
197
- - [OMP](https://github.com/can1357/oh-my-pi) (oh-my-pi)
198
- - [Bun](https://bun.sh) runtime
199
291
 
200
292
  ## License
201
293
 
@@ -0,0 +1,77 @@
1
+ # context-mode — MANDATORY routing rules
2
+
3
+ You have context-mode MCP tools available. These rules are NOT optional — they protect your context window from flooding. A single unrouted command can dump 56 KB into context and waste the entire session.
4
+
5
+ ## BLOCKED commands — do NOT attempt these
6
+
7
+ ### curl / wget — BLOCKED
8
+ Any Bash command containing `curl` or `wget` is intercepted and replaced with an error message. Do NOT retry.
9
+ Instead use:
10
+ - `ctx_fetch_and_index(url, source)` to fetch and index web pages
11
+ - `ctx_execute(language: "javascript", code: "const r = await fetch(...)")` to run HTTP calls in sandbox
12
+
13
+ ### Inline HTTP — BLOCKED
14
+ Any Bash command containing `fetch('http`, `requests.get(`, `requests.post(`, `http.get(`, or `http.request(` is intercepted and replaced with an error message. Do NOT retry with Bash.
15
+ Instead use:
16
+ - `ctx_execute(language, code)` to run HTTP calls in sandbox — only stdout enters context
17
+
18
+ ### WebFetch / Fetch — BLOCKED
19
+ WebFetch and Fetch calls are denied entirely.
20
+ Instead use:
21
+ - `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` to query the indexed content
22
+
23
+ ### Grep — BLOCKED
24
+ Grep calls are intercepted and blocked. Do NOT retry with Grep.
25
+ Instead use:
26
+ - `ctx_search(queries: ["<pattern>"])` to search indexed content
27
+ - `ctx_batch_execute(commands, queries)` to run searches and return compressed results
28
+ - `ctx_execute(language: "shell", code: "grep ...")` to run searches in sandbox
29
+
30
+ ### Find / Glob — BLOCKED
31
+ Find/Glob calls are intercepted and blocked. Do NOT retry with Find/Glob.
32
+ Instead use:
33
+ - `ctx_execute(language: "shell", code: "find ...")` to run in sandbox
34
+ - `ctx_batch_execute(commands, queries)` for multiple searches
35
+
36
+ ### Read (full-file, no limit) — BLOCKED
37
+ Reading an entire file without a `limit` parameter is blocked.
38
+ - If you need to **Edit** the file → re-call Read with `limit` parameter (e.g., `limit: 200`)
39
+ - If you need to **analyze or explore** → use `ctx_execute_file(path, language, code)` instead. Only your printed summary enters context.
40
+
41
+ ## REDIRECTED tools — use sandbox equivalents
42
+
43
+ ### Bash (>20 lines output)
44
+ Bash is ONLY for: `git`, `mkdir`, `rm`, `mv`, `cd`, `ls`, `npm install`, `pip install`, and other short-output commands.
45
+ For everything else, use:
46
+ - `ctx_batch_execute(commands, queries)` — run multiple commands + search in ONE call
47
+ - `ctx_execute(language: "shell", code: "...")` — run in sandbox, only stdout enters context
48
+
49
+ ### Read (for analysis)
50
+ If you are reading a file to **Edit** it → Read with `limit` is correct (Edit needs content in context).
51
+ If you are reading to **analyze, explore, or summarize** → use `ctx_execute_file(path, language, code)` instead. Only your printed summary enters context. The raw file content stays in the sandbox.
52
+
53
+ ## Tool selection hierarchy
54
+
55
+ 1. **GATHER**: `ctx_batch_execute(commands, queries)` — Primary tool. Runs all commands, auto-indexes output, returns search results. ONE call replaces 30+ individual calls.
56
+ 2. **FOLLOW-UP**: `ctx_search(queries: ["q1", "q2", ...])` — Query indexed content. Pass ALL questions as array in ONE call.
57
+ 3. **PROCESSING**: `ctx_execute(language, code)` | `ctx_execute_file(path, language, code)` — Sandbox execution. Only stdout enters context.
58
+ 4. **WEB**: `ctx_fetch_and_index(url, source)` then `ctx_search(queries)` — Fetch, chunk, index, query. Raw HTML never enters context.
59
+ 5. **INDEX**: `ctx_index(content, source)` — Store content in FTS5 knowledge base for later search.
60
+
61
+ ## Subagent routing
62
+
63
+ When spawning subagents (Agent/Task tool), the routing block is automatically injected into their prompt. Bash-type subagents are upgraded to general-purpose so they have access to MCP tools. You do NOT need to manually instruct subagents about context-mode.
64
+
65
+ ## Output constraints
66
+
67
+ - Keep responses under 500 words.
68
+ - Write artifacts (code, configs, PRDs) to FILES — never return them as inline text. Return only: file path + 1-line description.
69
+ - When indexing content, use descriptive source labels so others can `ctx_search(source: "label")` later.
70
+
71
+ ## ctx commands
72
+
73
+ | Command | Action |
74
+ |---------|--------|
75
+ | `ctx stats` | Call the `ctx_stats` MCP tool and display the full output verbatim |
76
+ | `ctx doctor` | Call the `ctx_doctor` MCP tool, run the returned shell command, display as checklist |
77
+ | `ctx upgrade` | Call the `ctx_upgrade` MCP tool, run the returned shell command, display as checklist |
File without changes
package/bin/install.ts CHANGED
@@ -186,65 +186,139 @@ function installToPlatform(platformDir: string, packageRoot: string): string {
186
186
  }
187
187
 
188
188
  /**
189
- * Register context-mode MCP server in the given platform's mcp.json.
189
+ * Install context-mode as a platform extension and register MCP server.
190
+ *
191
+ * Per upstream docs (Pi Coding Agent):
192
+ * 1. git clone → ~/<platformDir>/extensions/context-mode
193
+ * 2. npm install && npm run build
194
+ * 3. Register MCP in ~/<platformDir>/settings/mcp.json
195
+ *
196
+ * Build requires Node.js 18+ (tsc, esbuild, node -e in build script).
197
+ * Runtime uses bun to leverage bun:sqlite — context-mode auto-detects
198
+ * Bun and skips better-sqlite3 entirely.
190
199
  */
191
- function registerContextMode(platformDir: string, extDir: string): void {
192
- const ctxSpinner = spinner();
193
- ctxSpinner.start(`Checking for context-mode (${platformDir})...`);
194
-
195
- // Find context-mode installation (Claude Code plugin cache)
196
- const ctxCacheBase = join(
197
- homedir(),
198
- ".claude",
199
- "plugins",
200
- "cache",
201
- "context-mode",
202
- "context-mode",
203
- );
204
- let ctxInstallPath: string | null = null;
205
- if (existsSync(ctxCacheBase)) {
206
- const versions = readdirSync(ctxCacheBase, { withFileTypes: true })
207
- .filter((d) => d.isDirectory())
208
- .map((d) => d.name)
209
- .sort()
210
- .reverse();
211
- if (versions.length > 0) {
212
- const candidate = join(ctxCacheBase, versions[0], "start.mjs");
213
- if (existsSync(candidate)) {
214
- ctxInstallPath = join(ctxCacheBase, versions[0]);
215
- }
216
- }
200
+ async function installContextMode(platformDir: string): Promise<void> {
201
+ const extDir = join(homedir(), platformDir, "extensions", "context-mode");
202
+ const startMjs = join(extDir, "start.mjs");
203
+
204
+ // Check if already installed and built
205
+ if (existsSync(startMjs)) {
206
+ // Already installed — just ensure MCP registration is up to date
207
+ registerContextModeMcp(platformDir, startMjs);
208
+ return;
217
209
  }
218
210
 
219
- if (ctxInstallPath) {
220
- const mcpConfigPath = join(homedir(), platformDir, "agent", "mcp.json");
221
- let mcpConfig: { mcpServers: Record<string, unknown> } = { mcpServers: {} };
222
- if (existsSync(mcpConfigPath)) {
223
- try {
224
- mcpConfig = JSON.parse(readFileSync(mcpConfigPath, "utf8"));
225
- if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
226
- } catch {
227
- mcpConfig = { mcpServers: {} };
228
- }
229
- }
211
+ const shouldInstall = await confirm({
212
+ message: `Install context-mode extension for context window protection? (${platformDir})`,
213
+ });
214
+ if (isCancel(shouldInstall) || !shouldInstall) {
215
+ note(
216
+ `Skipped. You can install later:\n` +
217
+ ` git clone https://github.com/mksglu/context-mode.git ~/${platformDir}/extensions/context-mode\n` +
218
+ ` cd ~/${platformDir}/extensions/context-mode && npm install && npm run build`,
219
+ `context-mode (${platformDir})`,
220
+ );
221
+ return;
222
+ }
230
223
 
231
- const startMjs = join(ctxInstallPath, "start.mjs");
232
- // Use our wrapper script that captures cwd as CLAUDE_PROJECT_DIR
233
- // before context-mode's start.mjs clobbers it with process.chdir(__dirname)
234
- const wrapperMjs = join(extDir, "bin", "ctx-mode-wrapper.mjs");
235
- mcpConfig.mcpServers["context-mode"] = {
236
- command: "node",
237
- args: [wrapperMjs, startMjs],
238
- };
239
-
240
- mkdirSync(join(homedir(), platformDir, "agent"), { recursive: true });
241
- writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
242
- ctxSpinner.stop(`context-mode registered in ~/${platformDir}/agent/mcp.json`);
243
- } else {
244
- ctxSpinner.stop(
245
- `context-mode not found install it as a Claude Code plugin for context window protection (${platformDir})`,
224
+ // Check Node.js 18+ (required for build: tsc, esbuild, node -e in build script)
225
+ const nodeCheck = run("node", ["--version"]);
226
+ if (nodeCheck.error || nodeCheck.status !== 0) {
227
+ note(
228
+ "Node.js 18+ is required to build context-mode.\n" +
229
+ "Install from https://nodejs.org then re-run the installer.",
230
+ "context-mode requires Node.js",
231
+ );
232
+ return;
233
+ }
234
+ const nodeVersion = parseInt((nodeCheck.stdout ?? "").replace(/^v/, ""), 10);
235
+ if (nodeVersion < 18) {
236
+ note(
237
+ `Found Node.js v${nodeCheck.stdout?.trim()} but context-mode requires v18+.\n` +
238
+ "Update Node.js from https://nodejs.org then re-run the installer.",
239
+ "context-mode requires Node.js 18+",
240
+ );
241
+ return;
242
+ }
243
+
244
+ const s = spinner();
245
+ s.start(`Cloning context-mode to ~/${platformDir}/extensions/context-mode...`);
246
+
247
+ // Clone
248
+ const cloneResult = run("git", [
249
+ "clone",
250
+ "https://github.com/mksglu/context-mode.git",
251
+ extDir,
252
+ ]);
253
+ if (cloneResult.status !== 0) {
254
+ s.stop(`Failed to clone context-mode`);
255
+ note(
256
+ cloneResult.stderr?.trim() || "Unknown git clone error",
257
+ "context-mode install failed",
258
+ );
259
+ return;
260
+ }
261
+
262
+ // npm install (builds better-sqlite3 native bindings for Node.js fallback;
263
+ // at runtime under Bun, bun:sqlite is used instead via auto-detection)
264
+ s.message("Installing context-mode dependencies...");
265
+ const npmInstall = run("npm", ["install"], { cwd: extDir });
266
+ if (npmInstall.status !== 0) {
267
+ s.stop(`Failed to install context-mode dependencies`);
268
+ note(
269
+ npmInstall.stderr?.trim() || "Unknown npm install error",
270
+ "context-mode install failed",
271
+ );
272
+ return;
273
+ }
274
+
275
+ // npm run build (requires tsc + esbuild from devDeps, runs under Node.js)
276
+ s.message("Building context-mode...");
277
+ const npmBuild = run("npm", ["run", "build"], { cwd: extDir });
278
+ if (npmBuild.status !== 0) {
279
+ s.stop(`Failed to build context-mode`);
280
+ note(
281
+ npmBuild.stderr?.trim() || "Unknown build error",
282
+ "context-mode install failed",
246
283
  );
284
+ return;
285
+ }
286
+
287
+ s.stop(`context-mode installed to ~/${platformDir}/extensions/context-mode`);
288
+
289
+ // Register MCP server
290
+ registerContextModeMcp(platformDir, startMjs);
291
+ }
292
+
293
+ /**
294
+ * Register context-mode MCP entry in the platform's settings/mcp.json.
295
+ *
296
+ * Uses "bun" as the command so context-mode auto-detects Bun runtime
297
+ * and uses bun:sqlite — no better-sqlite3 native bindings needed at runtime.
298
+ */
299
+ function registerContextModeMcp(platformDir: string, startMjs: string): void {
300
+ const mcpConfigPath = join(homedir(), platformDir, "settings", "mcp.json");
301
+ let mcpConfig: { mcpServers: Record<string, unknown> } = { mcpServers: {} };
302
+ if (existsSync(mcpConfigPath)) {
303
+ try {
304
+ mcpConfig = JSON.parse(readFileSync(mcpConfigPath, "utf8"));
305
+ if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
306
+ } catch {
307
+ mcpConfig = { mcpServers: {} };
308
+ }
247
309
  }
310
+
311
+ mcpConfig.mcpServers["context-mode"] = {
312
+ command: "bun",
313
+ args: [startMjs],
314
+ };
315
+
316
+ mkdirSync(dirname(mcpConfigPath), { recursive: true });
317
+ writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
318
+ note(
319
+ `Registered in ~/${platformDir}/settings/mcp.json`,
320
+ `context-mode (${platformDir})`,
321
+ );
248
322
  }
249
323
 
250
324
  // ── Main ─────────────────────────────────────────────────────
@@ -332,10 +406,10 @@ async function main(): Promise<void> {
332
406
  const packageRoot = resolve(__dirname, "..");
333
407
 
334
408
  for (const target of targets) {
335
- const extDir = installToPlatform(target.dir, packageRoot);
409
+ installToPlatform(target.dir, packageRoot);
336
410
 
337
- // ── Step 3b: Register context-mode MCP server ───────────
338
- registerContextMode(target.dir, extDir);
411
+ // ── Step 3b: Install context-mode extension + register MCP ──
412
+ await installContextMode(target.dir);
339
413
  }
340
414
 
341
415
  // ── Step 4: Unified dependency check (--skip-deps to skip) ──
@@ -365,21 +439,33 @@ async function main(): Promise<void> {
365
439
  );
366
440
  }
367
441
 
368
- // Offer to install missing deps that have an installCmd
442
+ // Offer to install missing deps let user choose which ones
369
443
  const installable = statuses.filter(
370
444
  (s) => !s.installed && s.installCmd !== null,
371
445
  );
372
446
 
373
447
  if (installable.length > 0) {
374
- const depList = installable
375
- .map((s) => ` • ${s.name} (${s.installCmd})`)
376
- .join("\n");
377
- const shouldInstall = await confirm({
378
- message: `Install ${installable.length} missing tool(s)?\n${depList}`,
448
+ const categoryLabels: Record<string, string> = {
449
+ core: "Core",
450
+ mcp: "MCP",
451
+ lsp: "Language Server",
452
+ };
453
+
454
+ const selected = await multiselect({
455
+ message: "Select tools to install (space to toggle, enter to confirm):",
456
+ options: installable.map((s) => ({
457
+ value: s.name,
458
+ label: s.name,
459
+ hint: `${categoryLabels[s.category] ?? s.category} — ${s.description}`,
460
+ })),
461
+ required: false,
379
462
  });
380
463
 
381
- if (!isCancel(shouldInstall) && shouldInstall) {
382
- for (const dep of installable) {
464
+ if (!isCancel(selected) && (selected as string[]).length > 0) {
465
+ const toInstall = installable.filter((s) =>
466
+ (selected as string[]).includes(s.name),
467
+ );
468
+ for (const dep of toInstall) {
383
469
  const s = spinner();
384
470
  s.start(`Installing ${dep.name}...`);
385
471
  const result = await installDep(exec, dep.name);