@kata-sh/cli 0.1.2 → 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.
- package/README.md +242 -93
- package/dist/cli.js +20 -0
- package/dist/loader.js +10 -0
- package/dist/resource-loader.js +19 -0
- package/package.json +3 -2
- package/pkg/CHANGELOG.md +25 -0
- package/src/resources/AGENTS.md +154 -2
- package/src/resources/extensions/kata/preferences.ts +18 -6
- package/src/resources/extensions/kata/tests/preferences-frontmatter.test.mjs +53 -0
package/README.md
CHANGED
|
@@ -1,155 +1,304 @@
|
|
|
1
1
|
# Kata CLI
|
|
2
2
|
|
|
3
|
-
A terminal coding agent
|
|
3
|
+
A terminal coding agent that decomposes projects into milestones, slices, and tasks — then executes them autonomously with structured planning, verification, and fresh context windows.
|
|
4
|
+
|
|
5
|
+
Built on [pi](https://github.com/badlogic/pi-mono) (`@mariozechner/pi-coding-agent`).
|
|
4
6
|
|
|
5
7
|
## Quick Start
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
|
|
9
|
-
bun install
|
|
10
|
-
cd apps/cli
|
|
11
|
-
npx tsc
|
|
12
|
-
npm run copy-themes
|
|
13
|
-
node dist/loader.js
|
|
10
|
+
npx @kata-sh/cli
|
|
14
11
|
```
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
Or install globally:
|
|
17
14
|
|
|
18
15
|
```bash
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
npm install -g @kata-sh/cli
|
|
17
|
+
kata-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
On first launch, Kata will prompt you to authenticate with an AI provider.
|
|
21
|
+
|
|
22
|
+
## Getting Started
|
|
23
|
+
|
|
24
|
+
### 1. Start Kata
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx @kata-sh/cli
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
### 2. Log in to a provider
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
/login
|
|
34
|
+
```
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
This opens an interactive prompt to authenticate with Anthropic, OpenAI, Google, or any supported provider. You can also set an API key directly:
|
|
26
37
|
|
|
38
|
+
```bash
|
|
39
|
+
ANTHROPIC_API_KEY=sk-ant-... npx @kata-sh/cli
|
|
27
40
|
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
resource-loader.ts — Syncs bundled resources to ~/.kata-cli/agent/
|
|
34
|
-
wizard.ts — First-run setup, env key hydration
|
|
35
|
-
resources/
|
|
36
|
-
KATA-WORKFLOW.md — The Kata planning methodology
|
|
37
|
-
AGENTS.md — System prompt instructions (synced to agent dir)
|
|
38
|
-
agents/ — Agent templates (worker, scout, researcher)
|
|
39
|
-
extensions/ — Bundled extensions (see below)
|
|
40
|
-
skills/ — Bundled skills
|
|
41
|
-
pkg/
|
|
42
|
-
package.json — piConfig shim (name: "kata", configDir: ".kata-cli")
|
|
43
|
-
dist/ — Theme assets copied from pi-coding-agent
|
|
41
|
+
|
|
42
|
+
### 3. Select a model
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
/model
|
|
44
46
|
```
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
Pick from available models across your authenticated providers.
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
2. `loader.ts` sets `KATA_CODING_AGENT_DIR` so pi uses `~/.kata-cli/agent/` instead of `~/.pi/agent/`
|
|
50
|
-
3. `resource-loader.ts` syncs bundled extensions, agents, skills, and `AGENTS.md` to `~/.kata-cli/agent/` on every launch
|
|
51
|
-
4. `cli.ts` calls pi-coding-agent's `main()` — pi handles everything from there
|
|
50
|
+
### 4. Start working
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
Tell Kata what you want to build. Kata has three modes of operation:
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|-----------|-------------|
|
|
57
|
-
| `kata/` | Main extension: `/kata` command, auto-mode, planning, state management |
|
|
58
|
-
| `browser-tools/` | Playwright-based browser automation |
|
|
59
|
-
| `subagent/` | Spawns child Kata processes for parallel work |
|
|
60
|
-
| `slash-commands/` | `/kata-run` and other slash commands |
|
|
61
|
-
| `bg-shell/` | Background shell execution |
|
|
62
|
-
| `context7/` | Context7 library documentation lookup |
|
|
63
|
-
| `search-the-web/` | Web search via Brave API |
|
|
64
|
-
| `mac-tools/` | macOS-specific utilities |
|
|
65
|
-
| `shared/` | Shared UI components (library, not an entry point) |
|
|
54
|
+
**Step mode** — `/kata` — human in the loop (recommended for new or risk-averse users). Kata proposes each step, you approve or redirect.
|
|
66
55
|
|
|
67
|
-
|
|
56
|
+
**Autonomous mode** — `/kata auto` — researches, plans, executes, verifies, commits, and advances through every slice until the milestone is complete.
|
|
68
57
|
|
|
69
|
-
|
|
58
|
+
**Steering mode** — two terminals for supervised autonomy:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
# Terminal 1: autonomous execution
|
|
62
|
+
/kata auto
|
|
63
|
+
|
|
64
|
+
# Terminal 2: observe and steer
|
|
65
|
+
/kata status — check progress
|
|
66
|
+
/kata discuss — discuss decisions
|
|
67
|
+
/kata queue — manage upcoming work
|
|
68
|
+
|
|
69
|
+
# When you need to interrupt and redirect:
|
|
70
|
+
# Terminal 1:
|
|
71
|
+
/kata stop
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## How It Works
|
|
75
|
+
|
|
76
|
+
Kata breaks work into three levels:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Milestone → a shippable version (4–10 slices)
|
|
80
|
+
Slice → one demoable vertical capability (1–7 tasks)
|
|
81
|
+
Task → one context-window-sized unit of work
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Each slice flows through phases automatically:
|
|
85
|
+
|
|
86
|
+
**Research** → **Plan** → **Execute** (per task) → **Complete** → **Reassess** → **Next Slice**
|
|
87
|
+
|
|
88
|
+
- **Research** scouts the codebase and relevant docs
|
|
89
|
+
- **Plan** decomposes the slice into tasks with must-haves — mechanically verifiable outcomes
|
|
90
|
+
- **Execute** runs each task in a fresh context window with only the relevant files pre-loaded
|
|
91
|
+
- **Complete** writes the summary, UAT script, marks the roadmap, and commits
|
|
92
|
+
- **Reassess** checks if the roadmap still makes sense given what was learned
|
|
93
|
+
|
|
94
|
+
All planning state lives in `.kata/` at the project root — human-readable markdown files that track milestones, slices, tasks, decisions, and progress.
|
|
95
|
+
|
|
96
|
+
## Commands
|
|
97
|
+
|
|
98
|
+
### Kata workflow
|
|
70
99
|
|
|
71
100
|
| Command | Description |
|
|
72
101
|
|---------|-------------|
|
|
73
|
-
| `/kata` | Contextual wizard —
|
|
74
|
-
| `/kata auto` | Start
|
|
75
|
-
| `/kata stop` | Stop auto-mode
|
|
102
|
+
| `/kata` | Contextual wizard — suggests next step based on project state |
|
|
103
|
+
| `/kata auto` | Start autonomous mode |
|
|
104
|
+
| `/kata stop` | Stop auto-mode after current task |
|
|
76
105
|
| `/kata status` | Progress dashboard |
|
|
77
|
-
| `/kata queue` | View/manage
|
|
106
|
+
| `/kata queue` | View/manage milestone queue |
|
|
78
107
|
| `/kata discuss` | Discuss gray areas before planning |
|
|
79
|
-
| `/kata prefs` | Manage preferences (global/project
|
|
108
|
+
| `/kata prefs` | Manage preferences (global/project) |
|
|
80
109
|
| `/kata doctor` | Diagnose and fix project state |
|
|
110
|
+
| `/audit` | Audit the codebase against a goal, writes report to `.kata/audits/` |
|
|
81
111
|
|
|
82
|
-
###
|
|
112
|
+
### Session & model
|
|
83
113
|
|
|
84
|
-
|
|
114
|
+
| Command | Description |
|
|
115
|
+
|---------|-------------|
|
|
116
|
+
| `/login` | Authenticate with an AI provider (OAuth) |
|
|
117
|
+
| `/model` | Select a model |
|
|
118
|
+
| `/scoped-models` | Enable/disable models for `Ctrl+P` cycling |
|
|
119
|
+
| `/new` | Start a new session |
|
|
120
|
+
| `/resume` | Resume a previous session |
|
|
121
|
+
| `/compact` | Manually compact the session context |
|
|
122
|
+
| `/fork` | Create a new fork from a previous message |
|
|
123
|
+
| `/tree` | Navigate session tree (switch branches) |
|
|
124
|
+
| `/session` | Show session info and stats |
|
|
125
|
+
|
|
126
|
+
### Utilities
|
|
127
|
+
|
|
128
|
+
| Command | Description |
|
|
129
|
+
|---------|-------------|
|
|
130
|
+
| `/mcp` | Show MCP server status and tools |
|
|
131
|
+
| `/gh` | GitHub helper — issues, PRs, labels, milestones, status |
|
|
132
|
+
| `/subagent` | List available subagents |
|
|
133
|
+
| `/export` | Export session to HTML file |
|
|
134
|
+
| `/share` | Share session as a secret GitHub gist |
|
|
135
|
+
| `/copy` | Copy last agent message to clipboard |
|
|
136
|
+
| `/hotkeys` | Show all keyboard shortcuts |
|
|
137
|
+
| `/create-extension` | Scaffold a new extension with interview-driven setup |
|
|
138
|
+
| `/create-slash-command` | Generate a new slash command from a plain-English description |
|
|
139
|
+
|
|
140
|
+
## Preferences
|
|
141
|
+
|
|
142
|
+
Kata preferences live in `~/.kata-cli/preferences.md` (global) or `.kata-cli/preferences.md` (project-local). Manage with `/kata prefs`.
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
---
|
|
146
|
+
version: 1
|
|
147
|
+
models:
|
|
148
|
+
research: claude-sonnet-4-6
|
|
149
|
+
planning: claude-opus-4-6
|
|
150
|
+
execution: claude-sonnet-4-6
|
|
151
|
+
completion: claude-sonnet-4-6
|
|
152
|
+
skill_discovery: suggest
|
|
153
|
+
auto_supervisor:
|
|
154
|
+
soft_timeout_minutes: 20
|
|
155
|
+
idle_timeout_minutes: 10
|
|
156
|
+
hard_timeout_minutes: 30
|
|
157
|
+
budget_ceiling: 50.00
|
|
158
|
+
---
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Setting | What it controls |
|
|
162
|
+
|---------|-----------------|
|
|
163
|
+
| `models.*` | Per-phase model selection (Opus for planning, Sonnet for execution, etc.) |
|
|
164
|
+
| `skill_discovery` | `auto` / `suggest` / `off` — how Kata finds and applies skills |
|
|
165
|
+
| `auto_supervisor.*` | Timeout thresholds for auto-mode supervision |
|
|
166
|
+
| `budget_ceiling` | USD ceiling — auto mode pauses when reached |
|
|
167
|
+
| `uat_dispatch` | Enable automatic UAT runs after slice completion |
|
|
168
|
+
| `always_use_skills` | Skills to always load when relevant |
|
|
169
|
+
| `skill_rules` | Situational rules for skill routing |
|
|
170
|
+
|
|
171
|
+
## Project State
|
|
172
|
+
|
|
173
|
+
Kata stores all planning artifacts in `.kata/` at the project root:
|
|
85
174
|
|
|
86
175
|
```
|
|
87
176
|
.kata/
|
|
88
|
-
STATE.md
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
REQUIREMENTS.md
|
|
177
|
+
STATE.md — Quick-glance dashboard
|
|
178
|
+
PROJECT.md — What the project is (living doc)
|
|
179
|
+
DECISIONS.md — Append-only architecture decisions
|
|
180
|
+
REQUIREMENTS.md — Requirements tracking
|
|
92
181
|
milestones/
|
|
93
182
|
M001/
|
|
94
|
-
M001-ROADMAP.md
|
|
183
|
+
M001-ROADMAP.md — Slices with risk levels and dependencies
|
|
184
|
+
M001-SUMMARY.md — Milestone rollup
|
|
95
185
|
slices/
|
|
96
186
|
S01/
|
|
97
|
-
S01-PLAN.md
|
|
187
|
+
S01-PLAN.md — Tasks with must-haves and estimates
|
|
188
|
+
S01-SUMMARY.md — What was built, what changed
|
|
98
189
|
tasks/
|
|
99
|
-
T01-PLAN.md
|
|
190
|
+
T01-PLAN.md — Steps, verification, files touched
|
|
100
191
|
T01-SUMMARY.md
|
|
101
192
|
```
|
|
102
193
|
|
|
103
|
-
|
|
194
|
+
Everything is markdown. You can read it, edit it, or use it as context for other tools.
|
|
195
|
+
|
|
196
|
+
## Bundled Tools
|
|
197
|
+
|
|
198
|
+
Kata comes with extensions for:
|
|
199
|
+
|
|
200
|
+
- **Browser automation** — Playwright-based interaction with web pages
|
|
201
|
+
- **Subagents** — Spawn parallel Kata processes for independent tasks
|
|
202
|
+
- **Background shell** — Long-running processes (servers, watchers, builds)
|
|
203
|
+
- **Web search** — Brave Search API for current external facts
|
|
204
|
+
- **Library docs** — Context7 for up-to-date framework/library documentation
|
|
205
|
+
- **macOS tools** — Native app automation via Accessibility APIs
|
|
206
|
+
- **MCP servers** — Connect to any [Model Context Protocol](https://modelcontextprotocol.io/) server
|
|
207
|
+
|
|
208
|
+
## Bundled Agents
|
|
209
|
+
|
|
210
|
+
Three specialized subagents for delegated work:
|
|
211
|
+
|
|
212
|
+
| Agent | Role |
|
|
213
|
+
|-------|------|
|
|
214
|
+
| **Scout** | Fast codebase recon — returns compressed context for handoff |
|
|
215
|
+
| **Researcher** | Web research — finds and synthesizes current information |
|
|
216
|
+
| **Worker** | General-purpose execution in an isolated context window |
|
|
217
|
+
|
|
218
|
+
## MCP Support
|
|
219
|
+
|
|
220
|
+
Kata integrates with MCP servers via [`pi-mcp-adapter`](https://github.com/nicobailon/pi-mcp-adapter), auto-installed on first launch. Connect to Linear, Figma, or any MCP-compatible service.
|
|
221
|
+
|
|
222
|
+
### Adding a server
|
|
223
|
+
|
|
224
|
+
Edit `~/.kata-cli/agent/mcp.json`:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"mcpServers": {
|
|
229
|
+
"linear": {
|
|
230
|
+
"command": "npx",
|
|
231
|
+
"args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"]
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Restart Kata, then connect:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
mcp({ connect: "linear" })
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
OAuth servers (Linear, etc.) open a browser window for authorization on first connect. Tokens are cached for subsequent sessions.
|
|
244
|
+
|
|
245
|
+
### Importing existing configs
|
|
246
|
+
|
|
247
|
+
Pull in MCP configs from other tools:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"imports": ["claude-code", "cursor"],
|
|
252
|
+
"mcpServers": {}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Supported: `cursor`, `claude-code`, `claude-desktop`, `vscode`, `windsurf`, `codex`.
|
|
104
257
|
|
|
105
|
-
|
|
258
|
+
### Usage
|
|
259
|
+
|
|
260
|
+
| Command | Description |
|
|
261
|
+
|---------|-------------|
|
|
262
|
+
| `mcp({ })` | Show server status |
|
|
263
|
+
| `mcp({ server: "name" })` | List tools from a server |
|
|
264
|
+
| `mcp({ search: "query" })` | Search tools across servers |
|
|
265
|
+
| `mcp({ tool: "name", args: '{}' })` | Call a tool |
|
|
266
|
+
| `/mcp` | Interactive panel |
|
|
267
|
+
|
|
268
|
+
## Configuration
|
|
269
|
+
|
|
270
|
+
Kata stores config in `~/.kata-cli/`:
|
|
106
271
|
|
|
107
272
|
```
|
|
108
273
|
~/.kata-cli/
|
|
109
274
|
agent/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
skills/ — Synced from src/resources/skills/
|
|
113
|
-
AGENTS.md — Synced from src/resources/AGENTS.md
|
|
114
|
-
auth.json — API keys
|
|
275
|
+
mcp.json — MCP server configuration
|
|
276
|
+
auth.json — Provider API keys
|
|
115
277
|
settings.json — User settings
|
|
116
|
-
|
|
278
|
+
extensions/ — Bundled extensions (synced on launch)
|
|
279
|
+
skills/ — Bundled skills
|
|
117
280
|
sessions/ — Session history
|
|
118
|
-
preferences.md — Global
|
|
281
|
+
preferences.md — Global preferences
|
|
119
282
|
```
|
|
120
283
|
|
|
121
|
-
## Environment Variables
|
|
122
|
-
|
|
123
|
-
Set by `loader.ts` before pi starts:
|
|
124
|
-
|
|
125
|
-
| Variable | Purpose |
|
|
126
|
-
|----------|---------|
|
|
127
|
-
| `PI_PACKAGE_DIR` | Points to `pkg/` for Kata's piConfig |
|
|
128
|
-
| `KATA_CODING_AGENT_DIR` | Tells pi to use `~/.kata-cli/agent/` |
|
|
129
|
-
| `KATA_VERSION` | Package version for display |
|
|
130
|
-
| `KATA_BIN_PATH` | Absolute path to loader, used by subagent |
|
|
131
|
-
| `KATA_WORKFLOW_PATH` | Absolute path to bundled KATA-WORKFLOW.md |
|
|
132
|
-
| `KATA_BUNDLED_EXTENSION_PATHS` | Colon-joined extension entry points for subagent |
|
|
133
|
-
|
|
134
284
|
## Development
|
|
135
285
|
|
|
286
|
+
For contributing or running from source:
|
|
287
|
+
|
|
136
288
|
```bash
|
|
137
|
-
#
|
|
289
|
+
# From the monorepo root
|
|
290
|
+
bun install
|
|
291
|
+
cd apps/cli
|
|
138
292
|
npx tsc
|
|
139
|
-
|
|
140
|
-
# Copy theme assets (required once, or after pi-coding-agent updates)
|
|
141
293
|
npm run copy-themes
|
|
142
|
-
|
|
143
|
-
# Run
|
|
144
294
|
node dist/loader.js
|
|
145
|
-
|
|
146
|
-
# Test
|
|
147
|
-
npm test
|
|
148
295
|
```
|
|
149
296
|
|
|
150
|
-
|
|
297
|
+
Run tests:
|
|
151
298
|
|
|
152
|
-
|
|
299
|
+
```bash
|
|
300
|
+
cd apps/cli && npm test
|
|
301
|
+
```
|
|
153
302
|
|
|
154
303
|
## License
|
|
155
304
|
|
package/dist/cli.js
CHANGED
|
@@ -36,10 +36,30 @@ if (!settingsManager.getQuietStartup()) {
|
|
|
36
36
|
if (!settingsManager.getCollapseChangelog()) {
|
|
37
37
|
settingsManager.setCollapseChangelog(true);
|
|
38
38
|
}
|
|
39
|
+
// Ensure pi-mcp-adapter is in the packages list so pi auto-installs it on startup.
|
|
40
|
+
// Bootstrap only when packages have never been configured. If users later remove the
|
|
41
|
+
// adapter from settings.json, that opt-out should persist.
|
|
42
|
+
const MCP_ADAPTER_PACKAGE = 'npm:pi-mcp-adapter';
|
|
43
|
+
const globalSettings = settingsManager.getGlobalSettings();
|
|
44
|
+
const globalPackages = [...(globalSettings.packages ?? [])];
|
|
45
|
+
const hasConfiguredPackages = Object.prototype.hasOwnProperty.call(globalSettings, "packages");
|
|
46
|
+
if (!hasConfiguredPackages && !globalPackages.includes(MCP_ADAPTER_PACKAGE)) {
|
|
47
|
+
settingsManager.setPackages([...globalPackages, MCP_ADAPTER_PACKAGE]);
|
|
48
|
+
}
|
|
49
|
+
await settingsManager.flush();
|
|
39
50
|
const sessionManager = SessionManager.create(process.cwd(), sessionsDir);
|
|
40
51
|
initResources(agentDir);
|
|
41
52
|
const resourceLoader = buildResourceLoader(agentDir);
|
|
42
53
|
await resourceLoader.reload();
|
|
54
|
+
// Inject --mcp-config flag value into the extension runtime.
|
|
55
|
+
// pi-mcp-adapter reads this via pi.getFlag("mcp-config") at session_start.
|
|
56
|
+
// Kata doesn't call pi's main() which does the two-pass argv parsing that
|
|
57
|
+
// normally populates flagValues, so we must do it manually here.
|
|
58
|
+
const mcpConfigPath = process.env.KATA_MCP_CONFIG_PATH;
|
|
59
|
+
if (mcpConfigPath) {
|
|
60
|
+
const extResult = resourceLoader.getExtensions();
|
|
61
|
+
extResult.runtime.flagValues.set('mcp-config', mcpConfigPath);
|
|
62
|
+
}
|
|
43
63
|
const { session, extensionsResult } = await createAgentSession({
|
|
44
64
|
authStorage,
|
|
45
65
|
modelRegistry,
|
package/dist/loader.js
CHANGED
|
@@ -91,5 +91,15 @@ process.env.KATA_BUNDLED_EXTENSION_PATHS = [
|
|
|
91
91
|
join(agentDir, "extensions", "ask-user-questions.ts"),
|
|
92
92
|
join(agentDir, "extensions", "get-secrets-from-user.ts"),
|
|
93
93
|
].join(":");
|
|
94
|
+
// KATA_MCP_CONFIG_PATH — absolute path to Kata's MCP config file.
|
|
95
|
+
// pi-mcp-adapter reads --mcp-config from process.argv directly (before session_start fires).
|
|
96
|
+
// We inject it here so the adapter uses ~/.kata-cli/agent/mcp.json instead of the
|
|
97
|
+
// default ~/.pi/agent/mcp.json.
|
|
98
|
+
const mcpConfigPath = join(agentDir, "mcp.json");
|
|
99
|
+
process.env.KATA_MCP_CONFIG_PATH = mcpConfigPath;
|
|
100
|
+
const hasMcpConfigArg = process.argv.some((arg) => arg === "--mcp-config" || arg.startsWith("--mcp-config="));
|
|
101
|
+
if (!hasMcpConfigArg) {
|
|
102
|
+
process.argv.push("--mcp-config", mcpConfigPath);
|
|
103
|
+
}
|
|
94
104
|
// Dynamic import defers ESM evaluation — config.js will see PI_PACKAGE_DIR above
|
|
95
105
|
await import("./cli.js");
|
package/dist/resource-loader.js
CHANGED
|
@@ -2,6 +2,19 @@ import { DefaultResourceLoader } from '@mariozechner/pi-coding-agent';
|
|
|
2
2
|
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/**
|
|
6
|
+
* Starter mcp.json written to agentDir on first launch.
|
|
7
|
+
* Uses the `imports` field so users can pull in their existing Claude/Cursor config.
|
|
8
|
+
* mcpServers is intentionally empty — users add their own servers here.
|
|
9
|
+
*/
|
|
10
|
+
const STARTER_MCP_JSON = JSON.stringify({
|
|
11
|
+
imports: [],
|
|
12
|
+
settings: {
|
|
13
|
+
toolPrefix: 'server',
|
|
14
|
+
idleTimeout: 10,
|
|
15
|
+
},
|
|
16
|
+
mcpServers: {},
|
|
17
|
+
}, null, 2) + '\n';
|
|
5
18
|
// Resolves to the bundled src/resources/ inside the npm package at runtime:
|
|
6
19
|
// dist/resource-loader.js → .. → package root → src/resources/
|
|
7
20
|
const resourcesDir = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources');
|
|
@@ -39,6 +52,12 @@ export function initResources(agentDir) {
|
|
|
39
52
|
if (existsSync(srcAgentsMd)) {
|
|
40
53
|
writeFileSync(destAgentsMd, readFileSync(srcAgentsMd));
|
|
41
54
|
}
|
|
55
|
+
// Scaffold starter mcp.json — only if it doesn't exist yet.
|
|
56
|
+
// Never overwrite: preserve the user's MCP server configuration.
|
|
57
|
+
const mcpConfigPath = join(agentDir, 'mcp.json');
|
|
58
|
+
if (!existsSync(mcpConfigPath)) {
|
|
59
|
+
writeFileSync(mcpConfigPath, STARTER_MCP_JSON, 'utf-8');
|
|
60
|
+
}
|
|
42
61
|
}
|
|
43
62
|
/**
|
|
44
63
|
* Constructs a DefaultResourceLoader with no additionalExtensionPaths.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kata-sh/cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Kata CLI coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"node": ">=20.6.0"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "tsc && npm run copy-themes",
|
|
32
|
+
"build": "tsc && npm run copy-themes && npm run copy-changelog",
|
|
33
|
+
"copy-changelog": "node -e \"require('fs').cpSync('CHANGELOG.md','pkg/CHANGELOG.md')\"",
|
|
33
34
|
"copy-themes": "node -e \"const{mkdirSync,cpSync}=require('fs');const{resolve}=require('path');const candidates=[resolve(__dirname,'node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme'),resolve(__dirname,'..','..','node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/theme')];const src=candidates.find(p=>{try{require('fs').statSync(p);return true}catch{return false}});if(!src)throw new Error('theme dir not found');mkdirSync('pkg/dist/modes/interactive/theme',{recursive:true});cpSync(src,'pkg/dist/modes/interactive/theme',{recursive:true})\"",
|
|
34
35
|
"test": "node --import ./src/resources/extensions/kata/tests/resolve-ts.mjs --experimental-strip-types --test 'src/resources/extensions/kata/tests/*.test.ts' 'src/resources/extensions/kata/tests/*.test.mjs' 'src/tests/*.test.ts'",
|
|
35
36
|
"dev": "tsc --watch",
|
package/pkg/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
- Fix `/changelog` command — symlink `pkg/CHANGELOG.md` so Kata can find it
|
|
6
|
+
- Rewrite README for consumers: quick start with `npx`, getting started flow, how it works, mode comparison, full command reference
|
|
7
|
+
|
|
8
|
+
## 0.2.0
|
|
9
|
+
|
|
10
|
+
- Add MCP (Model Context Protocol) support via `pi-mcp-adapter` — connect to any MCP server (Linear, Figma, custom tools) from Kata
|
|
11
|
+
- Auto-install `pi-mcp-adapter` on startup and scaffold starter `mcp.json` config
|
|
12
|
+
- Inject `mcp-config` flag into extension runtime for seamless MCP server discovery
|
|
13
|
+
- Fix inline `[]` and `{}` literal handling in preferences YAML parser
|
|
14
|
+
- Add comprehensive MCP documentation and setup guide to README
|
|
15
|
+
- Add MCP smoke tests to CI
|
|
16
|
+
- Install `pi-mcp-adapter` globally in CI for test coverage
|
|
17
|
+
|
|
18
|
+
## 0.1.2
|
|
19
|
+
|
|
20
|
+
- Fix `~/.kata/` paths to `~/.kata-cli/` to avoid collision with Kata Desktop config directory
|
|
21
|
+
|
|
22
|
+
## 0.1.1
|
|
23
|
+
|
|
24
|
+
- Rename `@kata/*` to `@kata-sh/*` npm scope
|
|
25
|
+
- Initial public release to npm
|
package/src/resources/AGENTS.md
CHANGED
|
@@ -9,7 +9,7 @@ Kata CLI is a thin wrapper around pi-coding-agent that provides:
|
|
|
9
9
|
- **Branded entry point**: `src/loader.ts` sets env vars and launches `src/cli.ts`
|
|
10
10
|
- **Bundled extensions**: `src/resources/extensions/` contains all built-in extensions
|
|
11
11
|
- **Resource syncing**: `src/resource-loader.ts` copies bundled extensions to `~/.kata-cli/agent/` on startup
|
|
12
|
-
- **Config directory**: `~/.kata-cli/` (not `~/.
|
|
12
|
+
- **Config directory**: `~/.kata-cli/` (not `~/.pi/` to avoid collision with other Kata apps)
|
|
13
13
|
- **Package shim**: `pkg/package.json` provides `piConfig` with `name: "kata"` and `configDir: ".kata-cli"`
|
|
14
14
|
|
|
15
15
|
## Directory Structure
|
|
@@ -18,7 +18,7 @@ Kata CLI is a thin wrapper around pi-coding-agent that provides:
|
|
|
18
18
|
apps/cli/
|
|
19
19
|
src/
|
|
20
20
|
loader.ts — Entry point, sets KATA_* env vars, imports cli.ts
|
|
21
|
-
cli.ts — Thin wrapper that calls
|
|
21
|
+
cli.ts — Thin wrapper that calls createAgentSession() + InteractiveMode
|
|
22
22
|
app-paths.ts — Exports appRoot, agentDir, sessionsDir, authFilePath
|
|
23
23
|
resource-loader.ts — Syncs bundled resources to ~/.kata-cli/agent/
|
|
24
24
|
wizard.ts — First-run setup, env key hydration
|
|
@@ -55,6 +55,7 @@ Kata sets these env vars in `loader.ts` before importing `cli.ts`:
|
|
|
55
55
|
| `KATA_BIN_PATH` | Absolute path to loader, used by subagent to spawn Kata |
|
|
56
56
|
| `KATA_WORKFLOW_PATH` | Absolute path to bundled KATA-WORKFLOW.md |
|
|
57
57
|
| `KATA_BUNDLED_EXTENSION_PATHS` | Colon-joined list of extension entry points |
|
|
58
|
+
| `KATA_MCP_CONFIG_PATH` | Absolute path to `~/.kata-cli/agent/mcp.json` (also injected as `--mcp-config` argv) |
|
|
58
59
|
|
|
59
60
|
## The /kata Command
|
|
60
61
|
|
|
@@ -99,6 +100,156 @@ Kata stores project state in `.kata/` at the project root:
|
|
|
99
100
|
- **Copy themes**: `npm run copy-themes` (copies theme assets from pi-coding-agent)
|
|
100
101
|
- **Dependencies**: Consumed via npm from `@mariozechner/pi-coding-agent` — never fork
|
|
101
102
|
|
|
103
|
+
## MCP Support
|
|
104
|
+
|
|
105
|
+
Kata ships with MCP (Model Context Protocol) support via [`pi-mcp-adapter`](https://github.com/nicobailon/pi-mcp-adapter), auto-installed on first launch. One proxy `mcp` tool (~200 tokens) gives the agent on-demand access to any MCP server's tools without burning context on tool definitions.
|
|
106
|
+
|
|
107
|
+
### How it works
|
|
108
|
+
|
|
109
|
+
There are three integration points that make MCP work in Kata:
|
|
110
|
+
|
|
111
|
+
1. **Package seeding** (`cli.ts`): Seeds `npm:pi-mcp-adapter` into `settingsManager.getPackages()` on every startup. Pi's package manager auto-installs it globally if missing.
|
|
112
|
+
|
|
113
|
+
2. **Config path injection** (`loader.ts` + `cli.ts`): Kata bypasses pi's `main()` and calls `createAgentSession()` directly, which means pi's two-pass argv parsing (that normally populates `runtime.flagValues`) never runs. Two things compensate:
|
|
114
|
+
- `loader.ts` pushes `--mcp-config ~/.kata-cli/agent/mcp.json` into `process.argv` — the adapter reads this at extension load time for `directTools` registration.
|
|
115
|
+
- `cli.ts` manually sets `runtime.flagValues.set('mcp-config', ...)` after `resourceLoader.reload()` — the adapter reads this via `pi.getFlag('mcp-config')` at `session_start` for the main initialization.
|
|
116
|
+
|
|
117
|
+
3. **Config scaffolding** (`resource-loader.ts`): Creates a starter `~/.kata-cli/agent/mcp.json` on first launch. Never overwrites existing config.
|
|
118
|
+
|
|
119
|
+
### Configuring MCP servers
|
|
120
|
+
|
|
121
|
+
Edit `~/.kata-cli/agent/mcp.json` to add servers. Servers can use **stdio** (local process) or **HTTP** (remote endpoint) transport.
|
|
122
|
+
|
|
123
|
+
#### Stdio servers (local process)
|
|
124
|
+
|
|
125
|
+
Most MCP servers run as a local process via `npx`:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"mcpServers": {
|
|
130
|
+
"my-server": {
|
|
131
|
+
"command": "npx",
|
|
132
|
+
"args": ["-y", "some-mcp-server"],
|
|
133
|
+
"env": {
|
|
134
|
+
"API_KEY": "${MY_API_KEY}"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Environment variables support `${VAR}` interpolation from `process.env`.
|
|
142
|
+
|
|
143
|
+
#### HTTP servers with OAuth (e.g. Linear)
|
|
144
|
+
|
|
145
|
+
Many hosted MCP servers (Linear, Figma, etc.) use OAuth 2.1 authentication via the MCP spec. These require [`mcp-remote`](https://github.com/geelen/mcp-remote) as a stdio proxy that handles the OAuth browser flow:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"linear": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
On first connection, `mcp-remote` opens a browser window for OAuth consent. Tokens are cached in `~/.mcp-auth/` for subsequent sessions.
|
|
159
|
+
|
|
160
|
+
**Linear MCP setup (complete example):**
|
|
161
|
+
|
|
162
|
+
1. Add the server to `~/.kata-cli/agent/mcp.json`:
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"settings": { "toolPrefix": "server", "idleTimeout": 10 },
|
|
166
|
+
"mcpServers": {
|
|
167
|
+
"linear": {
|
|
168
|
+
"command": "npx",
|
|
169
|
+
"args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
2. Restart Kata.
|
|
176
|
+
|
|
177
|
+
3. Connect the server (triggers the OAuth flow in your browser):
|
|
178
|
+
```
|
|
179
|
+
mcp({ connect: "linear" })
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
4. Authorize Kata in the browser when prompted by Linear.
|
|
183
|
+
|
|
184
|
+
5. Use Linear tools:
|
|
185
|
+
```
|
|
186
|
+
mcp({ server: "linear" }) — list all Linear tools
|
|
187
|
+
mcp({ search: "issues" }) — search for issue-related tools
|
|
188
|
+
mcp({ tool: "linear_list_teams" }) — call a specific tool
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Troubleshooting OAuth:**
|
|
192
|
+
- If you see `internal server error`, clear cached auth: `rm -rf ~/.mcp-auth` and reconnect.
|
|
193
|
+
- Make sure you're running a recent version of Node.js.
|
|
194
|
+
- Use `/mcp` to check server status interactively.
|
|
195
|
+
|
|
196
|
+
#### HTTP servers with bearer token auth
|
|
197
|
+
|
|
198
|
+
For servers that accept API keys or personal access tokens:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"mcpServers": {
|
|
203
|
+
"my-api": {
|
|
204
|
+
"url": "https://api.example.com/mcp",
|
|
205
|
+
"auth": "bearer",
|
|
206
|
+
"bearerTokenEnv": "MY_API_KEY"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Importing existing configs
|
|
213
|
+
|
|
214
|
+
Pull in your existing Claude Code, Cursor, or VS Code MCP configuration:
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"imports": ["claude-code", "cursor"],
|
|
219
|
+
"mcpServers": {}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Supported sources: `cursor`, `claude-code`, `claude-desktop`, `vscode`, `windsurf`, `codex`.
|
|
224
|
+
|
|
225
|
+
### Server lifecycle
|
|
226
|
+
|
|
227
|
+
| Mode | Behavior |
|
|
228
|
+
|------|----------|
|
|
229
|
+
| `lazy` (default) | Connect on first tool call. Disconnect after idle timeout. Cached metadata keeps search/list working offline. |
|
|
230
|
+
| `eager` | Connect at startup. No auto-reconnect on drop. |
|
|
231
|
+
| `keep-alive` | Connect at startup. Auto-reconnect via health checks. |
|
|
232
|
+
|
|
233
|
+
### Usage
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
mcp({ }) — show server status
|
|
237
|
+
mcp({ server: "linear" }) — list tools from a server
|
|
238
|
+
mcp({ search: "issues create" }) — search tools (space-separated words OR'd)
|
|
239
|
+
mcp({ describe: "linear_save_issue" }) — show tool parameters
|
|
240
|
+
mcp({ tool: "linear_list_teams" }) — call a tool (no args)
|
|
241
|
+
mcp({ tool: "linear_save_issue", args: '{"title": "Bug fix"}' }) — call with args (JSON string)
|
|
242
|
+
mcp({ connect: "linear" }) — force connect/reconnect a server
|
|
243
|
+
/mcp — interactive panel (status, tools, reconnect, OAuth)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Known limitations
|
|
247
|
+
|
|
248
|
+
- **OAuth servers require `mcp-remote`**: The adapter doesn't implement the MCP OAuth browser flow natively. Use `mcp-remote` as a stdio proxy for any server that requires OAuth (Linear, Figma remote, etc.).
|
|
249
|
+
- **Figma remote MCP (`mcp.figma.com`)**: Blocks dynamic client registration — only whitelisted clients (Cursor, Claude Code, VS Code) can connect via OAuth. Use the Figma desktop app's local MCP server instead (`http://127.0.0.1:3845/mcp`), which requires Figma desktop with Dev Mode (paid plan).
|
|
250
|
+
- **Metadata cache path**: `pi-mcp-adapter` caches tool metadata to `~/.pi/agent/mcp-cache.json` (hardcoded). This doesn't affect functionality — just means the cache lives outside Kata's config dir.
|
|
251
|
+
- **OAuth token storage**: `mcp-remote` stores tokens in `~/.mcp-auth/`, separate from Kata's config dir.
|
|
252
|
+
|
|
102
253
|
## Key Conventions
|
|
103
254
|
|
|
104
255
|
- All env var names use `KATA_` prefix (not `GSD_` or `PI_`)
|
|
@@ -106,3 +257,4 @@ Kata stores project state in `.kata/` at the project root:
|
|
|
106
257
|
- Extensions are synced from `src/resources/extensions/` to `~/.kata-cli/agent/extensions/` on every launch
|
|
107
258
|
- The `shared/` extension directory is a library, not an entry point — it's imported by other extensions
|
|
108
259
|
- Branch naming for workflow: `kata/M001/S01` (milestone/slice)
|
|
260
|
+
- MCP config lives at `~/.kata-cli/agent/mcp.json` (not `~/.pi/agent/mcp.json`)
|
|
@@ -398,8 +398,9 @@ function parseFrontmatterBlock(frontmatter: string): KataPreferences {
|
|
|
398
398
|
const valuePart = remainder.trim();
|
|
399
399
|
|
|
400
400
|
if (valuePart === "") {
|
|
401
|
-
const
|
|
402
|
-
|
|
401
|
+
const nextNonEmptyLine =
|
|
402
|
+
lines.slice(i + 1).find((candidate) => candidate.trim() !== "") ?? "";
|
|
403
|
+
const nextTrimmed = nextNonEmptyLine.trim();
|
|
403
404
|
if (nextTrimmed.startsWith("- ")) {
|
|
404
405
|
const items: unknown[] = [];
|
|
405
406
|
let j = i + 1;
|
|
@@ -481,9 +482,16 @@ function parseFrontmatterBlock(frontmatter: string): KataPreferences {
|
|
|
481
482
|
current[key] = items;
|
|
482
483
|
i = j - 1;
|
|
483
484
|
} else {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
// Check if the next non-empty line is actually indented deeper (a real nested block).
|
|
486
|
+
// If not, this key simply has no value — skip it rather than creating an empty object.
|
|
487
|
+
const nextIndent =
|
|
488
|
+
nextNonEmptyLine.match(/^\s*/)?.[0].length ?? indent;
|
|
489
|
+
if (nextIndent > indent) {
|
|
490
|
+
const obj: Record<string, unknown> = {};
|
|
491
|
+
current[key] = obj;
|
|
492
|
+
stack.push({ indent, value: obj });
|
|
493
|
+
}
|
|
494
|
+
// else: key with no value and no nested block — leave it undefined
|
|
487
495
|
}
|
|
488
496
|
continue;
|
|
489
497
|
}
|
|
@@ -494,9 +502,13 @@ function parseFrontmatterBlock(frontmatter: string): KataPreferences {
|
|
|
494
502
|
return root as KataPreferences;
|
|
495
503
|
}
|
|
496
504
|
|
|
497
|
-
function parseScalar(
|
|
505
|
+
function parseScalar(
|
|
506
|
+
value: string,
|
|
507
|
+
): string | number | boolean | unknown[] | Record<string, never> {
|
|
498
508
|
if (value === "true") return true;
|
|
499
509
|
if (value === "false") return false;
|
|
510
|
+
if (value === "[]") return [];
|
|
511
|
+
if (value === "{}") return {};
|
|
500
512
|
if (/^-?\d+$/.test(value)) return Number(value);
|
|
501
513
|
return value.replace(/^['\"]|['\"]$/g, "");
|
|
502
514
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const resolveTsHookPath = fileURLToPath(new URL('./resolve-ts.mjs', import.meta.url));
|
|
10
|
+
const preferencesPath = fileURLToPath(new URL('../preferences.ts', import.meta.url));
|
|
11
|
+
|
|
12
|
+
test('loadEffectiveKataPreferences preserves blank-line-separated skill_rules lists', () => {
|
|
13
|
+
const tmp = mkdtempSync(join(tmpdir(), 'kata-preferences-frontmatter-'));
|
|
14
|
+
const kataDir = join(tmp, '.kata');
|
|
15
|
+
mkdirSync(kataDir, { recursive: true });
|
|
16
|
+
writeFileSync(
|
|
17
|
+
join(kataDir, 'preferences.md'),
|
|
18
|
+
`---
|
|
19
|
+
skill_rules:
|
|
20
|
+
|
|
21
|
+
- when: build
|
|
22
|
+
use:
|
|
23
|
+
- test-driven-development
|
|
24
|
+
---
|
|
25
|
+
`,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const script = `
|
|
29
|
+
import { loadEffectiveKataPreferences } from ${JSON.stringify(preferencesPath)};
|
|
30
|
+
const prefs = loadEffectiveKataPreferences();
|
|
31
|
+
console.log(JSON.stringify(prefs?.preferences.skill_rules ?? null));
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const output = execFileSync(
|
|
35
|
+
'node',
|
|
36
|
+
['--import', resolveTsHookPath, '--experimental-strip-types', '-e', script],
|
|
37
|
+
{
|
|
38
|
+
cwd: tmp,
|
|
39
|
+
env: {
|
|
40
|
+
...process.env,
|
|
41
|
+
HOME: tmp,
|
|
42
|
+
},
|
|
43
|
+
encoding: 'utf-8',
|
|
44
|
+
},
|
|
45
|
+
).trim();
|
|
46
|
+
|
|
47
|
+
assert.deepEqual(JSON.parse(output), [
|
|
48
|
+
{
|
|
49
|
+
when: 'build',
|
|
50
|
+
use: ['test-driven-development'],
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
});
|