@kata-sh/cli 0.1.0 → 0.1.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/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/app-paths.d.ts +4 -0
- package/dist/app-paths.js +6 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +56 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +95 -0
- package/dist/resource-loader.d.ts +18 -0
- package/dist/resource-loader.js +50 -0
- package/dist/wizard.d.ts +15 -0
- package/dist/wizard.js +159 -0
- package/package.json +50 -21
- package/pkg/dist/modes/interactive/theme/dark.json +85 -0
- package/pkg/dist/modes/interactive/theme/light.json +84 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.js +949 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -0
- package/pkg/package.json +8 -0
- package/scripts/postinstall.js +45 -0
- package/src/resources/AGENTS.md +108 -0
- package/src/resources/KATA-WORKFLOW.md +661 -0
- package/src/resources/agents/researcher.md +29 -0
- package/src/resources/agents/scout.md +56 -0
- package/src/resources/agents/worker.md +31 -0
- package/src/resources/extensions/ask-user-questions.ts +200 -0
- package/src/resources/extensions/bg-shell/index.ts +2758 -0
- package/src/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
- package/src/resources/extensions/browser-tools/core.js +1057 -0
- package/src/resources/extensions/browser-tools/index.ts +4916 -0
- package/src/resources/extensions/browser-tools/package.json +20 -0
- package/src/resources/extensions/context7/index.ts +428 -0
- package/src/resources/extensions/context7/package.json +11 -0
- package/src/resources/extensions/get-secrets-from-user.ts +352 -0
- package/src/resources/extensions/github/formatters.ts +207 -0
- package/src/resources/extensions/github/gh-api.ts +537 -0
- package/src/resources/extensions/github/index.ts +778 -0
- package/src/resources/extensions/kata/activity-log.ts +88 -0
- package/src/resources/extensions/kata/auto.ts +2786 -0
- package/src/resources/extensions/kata/commands.ts +355 -0
- package/src/resources/extensions/kata/crash-recovery.ts +85 -0
- package/src/resources/extensions/kata/dashboard-overlay.ts +516 -0
- package/src/resources/extensions/kata/docs/preferences-reference.md +103 -0
- package/src/resources/extensions/kata/doctor.ts +683 -0
- package/src/resources/extensions/kata/files.ts +730 -0
- package/src/resources/extensions/kata/gitignore.ts +165 -0
- package/src/resources/extensions/kata/guided-flow.ts +976 -0
- package/src/resources/extensions/kata/index.ts +556 -0
- package/src/resources/extensions/kata/metrics.ts +397 -0
- package/src/resources/extensions/kata/observability-validator.ts +408 -0
- package/src/resources/extensions/kata/package.json +11 -0
- package/src/resources/extensions/kata/paths.ts +346 -0
- package/src/resources/extensions/kata/preferences.ts +695 -0
- package/src/resources/extensions/kata/prompt-loader.ts +50 -0
- package/src/resources/extensions/kata/prompts/complete-milestone.md +25 -0
- package/src/resources/extensions/kata/prompts/complete-slice.md +27 -0
- package/src/resources/extensions/kata/prompts/discuss.md +151 -0
- package/src/resources/extensions/kata/prompts/doctor-heal.md +29 -0
- package/src/resources/extensions/kata/prompts/execute-task.md +64 -0
- package/src/resources/extensions/kata/prompts/guided-complete-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-milestone.md +3 -0
- package/src/resources/extensions/kata/prompts/guided-discuss-slice.md +59 -0
- package/src/resources/extensions/kata/prompts/guided-execute-task.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-plan-milestone.md +23 -0
- package/src/resources/extensions/kata/prompts/guided-plan-slice.md +1 -0
- package/src/resources/extensions/kata/prompts/guided-research-slice.md +11 -0
- package/src/resources/extensions/kata/prompts/guided-resume-task.md +1 -0
- package/src/resources/extensions/kata/prompts/plan-milestone.md +47 -0
- package/src/resources/extensions/kata/prompts/plan-slice.md +63 -0
- package/src/resources/extensions/kata/prompts/queue.md +85 -0
- package/src/resources/extensions/kata/prompts/reassess-roadmap.md +48 -0
- package/src/resources/extensions/kata/prompts/replan-slice.md +39 -0
- package/src/resources/extensions/kata/prompts/research-milestone.md +37 -0
- package/src/resources/extensions/kata/prompts/research-slice.md +28 -0
- package/src/resources/extensions/kata/prompts/run-uat.md +109 -0
- package/src/resources/extensions/kata/prompts/system.md +341 -0
- package/src/resources/extensions/kata/session-forensics.ts +550 -0
- package/src/resources/extensions/kata/skill-discovery.ts +137 -0
- package/src/resources/extensions/kata/state.ts +509 -0
- package/src/resources/extensions/kata/templates/context.md +76 -0
- package/src/resources/extensions/kata/templates/decisions.md +8 -0
- package/src/resources/extensions/kata/templates/milestone-summary.md +73 -0
- package/src/resources/extensions/kata/templates/plan.md +133 -0
- package/src/resources/extensions/kata/templates/preferences.md +15 -0
- package/src/resources/extensions/kata/templates/project.md +31 -0
- package/src/resources/extensions/kata/templates/reassessment.md +28 -0
- package/src/resources/extensions/kata/templates/requirements.md +81 -0
- package/src/resources/extensions/kata/templates/research.md +46 -0
- package/src/resources/extensions/kata/templates/roadmap.md +118 -0
- package/src/resources/extensions/kata/templates/slice-context.md +58 -0
- package/src/resources/extensions/kata/templates/slice-summary.md +99 -0
- package/src/resources/extensions/kata/templates/state.md +19 -0
- package/src/resources/extensions/kata/templates/task-plan.md +52 -0
- package/src/resources/extensions/kata/templates/task-summary.md +57 -0
- package/src/resources/extensions/kata/templates/uat.md +54 -0
- package/src/resources/extensions/kata/tests/activity-log-prune.test.ts +327 -0
- package/src/resources/extensions/kata/tests/auto-preflight.test.ts +97 -0
- package/src/resources/extensions/kata/tests/auto-supervisor.test.mjs +53 -0
- package/src/resources/extensions/kata/tests/complete-milestone.test.ts +317 -0
- package/src/resources/extensions/kata/tests/cost-projection.test.ts +160 -0
- package/src/resources/extensions/kata/tests/derive-state-deps.test.ts +477 -0
- package/src/resources/extensions/kata/tests/derive-state.test.ts +1013 -0
- package/src/resources/extensions/kata/tests/doctor.test.ts +718 -0
- package/src/resources/extensions/kata/tests/idle-recovery.test.ts +490 -0
- package/src/resources/extensions/kata/tests/metrics-io.test.ts +254 -0
- package/src/resources/extensions/kata/tests/metrics.test.ts +217 -0
- package/src/resources/extensions/kata/tests/must-have-parser.test.ts +309 -0
- package/src/resources/extensions/kata/tests/parsers.test.ts +1257 -0
- package/src/resources/extensions/kata/tests/plan-milestone.test.ts +185 -0
- package/src/resources/extensions/kata/tests/plan-quality-validator.test.ts +386 -0
- package/src/resources/extensions/kata/tests/reassess-prompt.test.ts +208 -0
- package/src/resources/extensions/kata/tests/replan-slice.test.ts +686 -0
- package/src/resources/extensions/kata/tests/requirements.test.ts +151 -0
- package/src/resources/extensions/kata/tests/resolve-ts-hooks.mjs +17 -0
- package/src/resources/extensions/kata/tests/resolve-ts.mjs +11 -0
- package/src/resources/extensions/kata/tests/run-uat.test.ts +383 -0
- package/src/resources/extensions/kata/tests/unit-runtime.test.ts +388 -0
- package/src/resources/extensions/kata/tests/workspace-index.test.ts +118 -0
- package/src/resources/extensions/kata/tests/worktree.test.ts +222 -0
- package/src/resources/extensions/kata/types.ts +159 -0
- package/src/resources/extensions/kata/unit-runtime.ts +163 -0
- package/src/resources/extensions/kata/workspace-index.ts +203 -0
- package/src/resources/extensions/kata/worktree.ts +182 -0
- package/src/resources/extensions/mac-tools/index.ts +852 -0
- package/src/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
- package/src/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
- package/src/resources/extensions/search-the-web/cache.ts +78 -0
- package/src/resources/extensions/search-the-web/format.ts +258 -0
- package/src/resources/extensions/search-the-web/http.ts +238 -0
- package/src/resources/extensions/search-the-web/index.ts +68 -0
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +519 -0
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +404 -0
- package/src/resources/extensions/search-the-web/tool-search.ts +503 -0
- package/src/resources/extensions/search-the-web/url-utils.ts +91 -0
- package/src/resources/extensions/shared/confirm-ui.ts +126 -0
- package/src/resources/extensions/shared/interview-ui.ts +822 -0
- package/src/resources/extensions/shared/next-action-ui.ts +235 -0
- package/src/resources/extensions/shared/progress-widget.ts +282 -0
- package/src/resources/extensions/shared/thinking-widget.ts +107 -0
- package/src/resources/extensions/shared/ui.ts +400 -0
- package/src/resources/extensions/shared/wizard-ui.ts +551 -0
- package/src/resources/extensions/slash-commands/audit.ts +92 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +375 -0
- package/src/resources/extensions/slash-commands/create-slash-command.ts +280 -0
- package/src/resources/extensions/slash-commands/index.ts +12 -0
- package/src/resources/extensions/slash-commands/kata-run.ts +34 -0
- package/src/resources/extensions/subagent/agents.ts +126 -0
- package/src/resources/extensions/subagent/index.ts +1293 -0
- package/src/resources/skills/debug-like-expert/SKILL.md +231 -0
- package/src/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
- package/src/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
- package/src/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
- package/src/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
- package/src/resources/skills/frontend-design/SKILL.md +45 -0
- package/src/resources/skills/swiftui/SKILL.md +208 -0
- package/src/resources/skills/swiftui/references/animations.md +921 -0
- package/src/resources/skills/swiftui/references/architecture.md +1561 -0
- package/src/resources/skills/swiftui/references/layout-system.md +1186 -0
- package/src/resources/skills/swiftui/references/navigation.md +1492 -0
- package/src/resources/skills/swiftui/references/networking-async.md +214 -0
- package/src/resources/skills/swiftui/references/performance.md +1706 -0
- package/src/resources/skills/swiftui/references/platform-integration.md +204 -0
- package/src/resources/skills/swiftui/references/state-management.md +1443 -0
- package/src/resources/skills/swiftui/references/swiftdata.md +297 -0
- package/src/resources/skills/swiftui/references/testing-debugging.md +247 -0
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
- package/src/resources/skills/swiftui/workflows/add-feature.md +191 -0
- package/src/resources/skills/swiftui/workflows/build-new-app.md +311 -0
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
- package/src/resources/skills/swiftui/workflows/ship-app.md +203 -0
- package/src/resources/skills/swiftui/workflows/write-tests.md +235 -0
- package/dist/commands/task.d.ts +0 -9
- package/dist/commands/task.d.ts.map +0 -1
- package/dist/commands/task.js +0 -129
- package/dist/commands/task.js.map +0 -1
- package/dist/commands/task.test.d.ts +0 -2
- package/dist/commands/task.test.d.ts.map +0 -1
- package/dist/commands/task.test.js +0 -169
- package/dist/commands/task.test.js.map +0 -1
- package/dist/e2e/task-e2e.test.d.ts +0 -2
- package/dist/e2e/task-e2e.test.d.ts.map +0 -1
- package/dist/e2e/task-e2e.test.js +0 -173
- package/dist/e2e/task-e2e.test.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -93
- package/dist/index.js.map +0 -1
- package/dist/slug.d.ts +0 -2
- package/dist/slug.d.ts.map +0 -1
- package/dist/slug.js +0 -12
- package/dist/slug.js.map +0 -1
- package/dist/slug.test.d.ts +0 -2
- package/dist/slug.test.d.ts.map +0 -1
- package/dist/slug.test.js +0 -32
- package/dist/slug.test.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lex Christopherson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Kata CLI
|
|
2
|
+
|
|
3
|
+
A terminal coding agent built on [pi](https://github.com/badlogic/pi-mono) (`@mariozechner/pi-coding-agent`). Kata CLI bundles a curated set of extensions for structured planning, browser automation, web search, subagent orchestration, and more.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# From the monorepo root
|
|
9
|
+
bun install
|
|
10
|
+
cd apps/cli
|
|
11
|
+
npx tsc
|
|
12
|
+
npm run copy-themes
|
|
13
|
+
node dist/loader.js
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Authenticate with an API key:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
20
|
+
node dist/loader.js
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
Kata CLI is a thin wrapper around pi-coding-agent. It does not fork pi — it consumes it as an npm dependency and layers on branding, config, and bundled extensions.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
apps/cli/
|
|
29
|
+
src/
|
|
30
|
+
loader.ts — Entry point: sets KATA_* env vars, imports cli.ts
|
|
31
|
+
cli.ts — Calls pi-coding-agent's main()
|
|
32
|
+
app-paths.ts — ~/.kata-cli/ path constants
|
|
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
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### How It Works
|
|
47
|
+
|
|
48
|
+
1. `loader.ts` sets `PI_PACKAGE_DIR` to `pkg/` so pi reads Kata's branding config
|
|
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
|
|
52
|
+
|
|
53
|
+
## Bundled Extensions
|
|
54
|
+
|
|
55
|
+
| Extension | Description |
|
|
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) |
|
|
66
|
+
|
|
67
|
+
## The /kata Command
|
|
68
|
+
|
|
69
|
+
The main extension registers `/kata` with subcommands:
|
|
70
|
+
|
|
71
|
+
| Command | Description |
|
|
72
|
+
|---------|-------------|
|
|
73
|
+
| `/kata` | Contextual wizard — smart entry point based on project state |
|
|
74
|
+
| `/kata auto` | Start auto-mode (loops fresh sessions until milestone complete) |
|
|
75
|
+
| `/kata stop` | Stop auto-mode gracefully |
|
|
76
|
+
| `/kata status` | Progress dashboard |
|
|
77
|
+
| `/kata queue` | View/manage work queue |
|
|
78
|
+
| `/kata discuss` | Discuss gray areas before planning |
|
|
79
|
+
| `/kata prefs` | Manage preferences (global/project/status) |
|
|
80
|
+
| `/kata doctor` | Diagnose and fix project state |
|
|
81
|
+
|
|
82
|
+
### Project State
|
|
83
|
+
|
|
84
|
+
Kata stores planning state in `.kata/` at the project root:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
.kata/
|
|
88
|
+
STATE.md — Dashboard (read first)
|
|
89
|
+
DECISIONS.md — Append-only decisions register
|
|
90
|
+
PROJECT.md — Project description
|
|
91
|
+
REQUIREMENTS.md — Requirements tracking
|
|
92
|
+
milestones/
|
|
93
|
+
M001/
|
|
94
|
+
M001-ROADMAP.md — Milestone plan with slices
|
|
95
|
+
slices/
|
|
96
|
+
S01/
|
|
97
|
+
S01-PLAN.md — Task decomposition
|
|
98
|
+
tasks/
|
|
99
|
+
T01-PLAN.md
|
|
100
|
+
T01-SUMMARY.md
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Config Directory
|
|
104
|
+
|
|
105
|
+
Kata uses `~/.kata-cli/` (not `~/.kata/`) to avoid collision with other Kata apps (desktop, etc.):
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
~/.kata-cli/
|
|
109
|
+
agent/
|
|
110
|
+
extensions/ — Synced from src/resources/extensions/
|
|
111
|
+
agents/ — Synced from src/resources/agents/
|
|
112
|
+
skills/ — Synced from src/resources/skills/
|
|
113
|
+
AGENTS.md — Synced from src/resources/AGENTS.md
|
|
114
|
+
auth.json — API keys
|
|
115
|
+
settings.json — User settings
|
|
116
|
+
models.json — Custom model definitions
|
|
117
|
+
sessions/ — Session history
|
|
118
|
+
preferences.md — Global Kata preferences
|
|
119
|
+
```
|
|
120
|
+
|
|
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
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Build
|
|
138
|
+
npx tsc
|
|
139
|
+
|
|
140
|
+
# Copy theme assets (required once, or after pi-coding-agent updates)
|
|
141
|
+
npm run copy-themes
|
|
142
|
+
|
|
143
|
+
# Run
|
|
144
|
+
node dist/loader.js
|
|
145
|
+
|
|
146
|
+
# Test
|
|
147
|
+
npm test
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Key Dependency
|
|
151
|
+
|
|
152
|
+
`@mariozechner/pi-coding-agent` is consumed via npm (hoisted to monorepo root `node_modules/`). Never fork — run `npm update` to pick up upstream changes.
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
MIT
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
export const appRoot = join(homedir(), '.kata-cli');
|
|
4
|
+
export const agentDir = join(appRoot, 'agent');
|
|
5
|
+
export const sessionsDir = join(appRoot, 'sessions');
|
|
6
|
+
export const authFilePath = join(agentDir, 'auth.json');
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { AuthStorage, ModelRegistry, SettingsManager, SessionManager, createAgentSession, InteractiveMode, } from '@mariozechner/pi-coding-agent';
|
|
2
|
+
import { agentDir, sessionsDir, authFilePath } from './app-paths.js';
|
|
3
|
+
import { buildResourceLoader, initResources } from './resource-loader.js';
|
|
4
|
+
import { loadStoredEnvKeys, runWizardIfNeeded } from './wizard.js';
|
|
5
|
+
const authStorage = AuthStorage.create(authFilePath);
|
|
6
|
+
loadStoredEnvKeys(authStorage);
|
|
7
|
+
await runWizardIfNeeded(authStorage);
|
|
8
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
9
|
+
const settingsManager = SettingsManager.create(agentDir);
|
|
10
|
+
// Always ensure defaults: anthropic/claude-sonnet-4-6, thinking off.
|
|
11
|
+
// Validates on every startup — catches stale settings from prior installs
|
|
12
|
+
// (e.g. grok-2 which no longer exists) and fresh installs with no settings.
|
|
13
|
+
const configuredProvider = settingsManager.getDefaultProvider();
|
|
14
|
+
const configuredModel = settingsManager.getDefaultModel();
|
|
15
|
+
const allModels = modelRegistry.getAll();
|
|
16
|
+
const configuredExists = configuredProvider && configuredModel &&
|
|
17
|
+
allModels.some((m) => m.provider === configuredProvider && m.id === configuredModel);
|
|
18
|
+
if (!configuredModel || !configuredExists) {
|
|
19
|
+
// Preferred default: anthropic/claude-sonnet-4-6
|
|
20
|
+
const preferred = allModels.find((m) => m.provider === 'anthropic' && m.id === 'claude-sonnet-4-6') ||
|
|
21
|
+
allModels.find((m) => m.provider === 'anthropic' && m.id.includes('sonnet')) ||
|
|
22
|
+
allModels.find((m) => m.provider === 'anthropic');
|
|
23
|
+
if (preferred) {
|
|
24
|
+
settingsManager.setDefaultModelAndProvider(preferred.provider, preferred.id);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Default thinking level: off (always reset if not explicitly set)
|
|
28
|
+
if (settingsManager.getDefaultThinkingLevel() !== 'off' && !configuredExists) {
|
|
29
|
+
settingsManager.setDefaultThinkingLevel('off');
|
|
30
|
+
}
|
|
31
|
+
// Quiet startup — the kata extension renders its own branded header
|
|
32
|
+
if (!settingsManager.getQuietStartup()) {
|
|
33
|
+
settingsManager.setQuietStartup(true);
|
|
34
|
+
}
|
|
35
|
+
// Collapse changelog by default — avoid wall of text on updates
|
|
36
|
+
if (!settingsManager.getCollapseChangelog()) {
|
|
37
|
+
settingsManager.setCollapseChangelog(true);
|
|
38
|
+
}
|
|
39
|
+
const sessionManager = SessionManager.create(process.cwd(), sessionsDir);
|
|
40
|
+
initResources(agentDir);
|
|
41
|
+
const resourceLoader = buildResourceLoader(agentDir);
|
|
42
|
+
await resourceLoader.reload();
|
|
43
|
+
const { session, extensionsResult } = await createAgentSession({
|
|
44
|
+
authStorage,
|
|
45
|
+
modelRegistry,
|
|
46
|
+
settingsManager,
|
|
47
|
+
sessionManager,
|
|
48
|
+
resourceLoader,
|
|
49
|
+
});
|
|
50
|
+
if (extensionsResult.errors.length > 0) {
|
|
51
|
+
for (const err of extensionsResult.errors) {
|
|
52
|
+
process.stderr.write(`[kata] Extension load error: ${err.error}\n`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const interactiveMode = new InteractiveMode(session);
|
|
56
|
+
await interactiveMode.run();
|
package/dist/loader.d.ts
ADDED
package/dist/loader.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import { dirname, resolve, join } from "path";
|
|
4
|
+
import { existsSync, readFileSync } from "fs";
|
|
5
|
+
import { agentDir, appRoot } from "./app-paths.js";
|
|
6
|
+
// pkg/ is a shim directory: contains kata's piConfig (package.json) and pi's
|
|
7
|
+
// theme assets (dist/modes/interactive/theme/) without a src/ directory.
|
|
8
|
+
// This allows config.js to:
|
|
9
|
+
// 1. Read piConfig.name → "kata" (branding)
|
|
10
|
+
// 2. Resolve themes via dist/ (no src/ present → uses dist path)
|
|
11
|
+
const pkgDir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "pkg");
|
|
12
|
+
// MUST be set before any dynamic import of pi SDK fires — this is what config.js
|
|
13
|
+
// reads to determine APP_NAME and CONFIG_DIR_NAME
|
|
14
|
+
process.env.PI_PACKAGE_DIR = pkgDir;
|
|
15
|
+
process.env.PI_SKIP_VERSION_CHECK = "1";
|
|
16
|
+
process.title = "kata";
|
|
17
|
+
// Print branded banner on first launch (before ~/.kata-cli/ exists)
|
|
18
|
+
if (!existsSync(appRoot)) {
|
|
19
|
+
const cyan = "\x1b[36m";
|
|
20
|
+
const green = "\x1b[32m";
|
|
21
|
+
const dim = "\x1b[2m";
|
|
22
|
+
const reset = "\x1b[0m";
|
|
23
|
+
let version = "";
|
|
24
|
+
try {
|
|
25
|
+
const pkgJson = JSON.parse(readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
26
|
+
version = pkgJson.version ?? "";
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* ignore */
|
|
30
|
+
}
|
|
31
|
+
process.stderr.write("\n" +
|
|
32
|
+
cyan +
|
|
33
|
+
" ██╗ ██╗ █████╗ ████████╗ █████╗ \n" +
|
|
34
|
+
" ██║ ██╔╝██╔══██╗╚══██╔══╝██╔══██╗\n" +
|
|
35
|
+
" █████╔╝ ███████║ ██║ ███████║\n" +
|
|
36
|
+
" ██╔═██╗ ██╔══██║ ██║ ██╔══██║\n" +
|
|
37
|
+
" ██║ ██╗██║ ██║ ██║ ██║ ██║\n" +
|
|
38
|
+
" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝" +
|
|
39
|
+
reset +
|
|
40
|
+
"\n\n" +
|
|
41
|
+
` Kata CLI ${dim}v${version}${reset}\n` +
|
|
42
|
+
` ${green}Welcome.${reset} Setting up your environment...\n\n`);
|
|
43
|
+
}
|
|
44
|
+
// KATA_CODING_AGENT_DIR — tells pi's getAgentDir() to return ~/.kata-cli/agent/
|
|
45
|
+
process.env.KATA_CODING_AGENT_DIR = agentDir;
|
|
46
|
+
// NODE_PATH — make kata's own node_modules available to extensions loaded via jiti.
|
|
47
|
+
// Without this, extensions (e.g. browser-tools) can't resolve dependencies like
|
|
48
|
+
// `playwright` because jiti resolves modules from pi-coding-agent's location, not kata's.
|
|
49
|
+
const kataRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
50
|
+
const kataNodeModules = join(kataRoot, "node_modules");
|
|
51
|
+
process.env.NODE_PATH = process.env.NODE_PATH
|
|
52
|
+
? `${kataNodeModules}:${process.env.NODE_PATH}`
|
|
53
|
+
: kataNodeModules;
|
|
54
|
+
// Force Node to re-evaluate module search paths with the updated NODE_PATH.
|
|
55
|
+
// Must happen synchronously before cli.js imports → extension loading.
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
57
|
+
const { Module } = await import("module");
|
|
58
|
+
Module._initPaths?.();
|
|
59
|
+
// KATA_VERSION — expose package version so extensions can display it
|
|
60
|
+
try {
|
|
61
|
+
const kataPkg = JSON.parse(readFileSync(join(kataRoot, "package.json"), "utf-8"));
|
|
62
|
+
process.env.KATA_VERSION = kataPkg.version || "0.0.0";
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
process.env.KATA_VERSION = "0.0.0";
|
|
66
|
+
}
|
|
67
|
+
// KATA_BIN_PATH — absolute path to this loader (dist/loader.js), used by subagent
|
|
68
|
+
// to spawn kata instead of pi when dispatching workflow tasks
|
|
69
|
+
process.env.KATA_BIN_PATH = process.argv[1];
|
|
70
|
+
// KATA_WORKFLOW_PATH — absolute path to bundled KATA-WORKFLOW.md
|
|
71
|
+
// when dispatching workflow prompts
|
|
72
|
+
const resourcesDir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "src", "resources");
|
|
73
|
+
process.env.KATA_WORKFLOW_PATH = join(resourcesDir, "KATA-WORKFLOW.md");
|
|
74
|
+
// KATA_BUNDLED_EXTENSION_PATHS — colon-joined list of all bundled extension entry point absolute
|
|
75
|
+
// paths, used by subagent to pass --extension <path> to spawned processes.
|
|
76
|
+
// IMPORTANT: paths point to agentDir (~/.kata-cli/agent/extensions/) NOT src/resources/extensions/.
|
|
77
|
+
// initResources() syncs bundled extensions to agentDir before any extension loading occurs,
|
|
78
|
+
// so these paths are always valid at runtime. Using agentDir paths matches what buildResourceLoader
|
|
79
|
+
// discovers (it scans agentDir), so pi's deduplication works correctly and extensions are not
|
|
80
|
+
// double-loaded in subagent child processes.
|
|
81
|
+
// Note: shared/ is NOT included — it's a library imported by kata and ask-user-questions, not an entry point.
|
|
82
|
+
process.env.KATA_BUNDLED_EXTENSION_PATHS = [
|
|
83
|
+
join(agentDir, "extensions", "kata", "index.ts"),
|
|
84
|
+
join(agentDir, "extensions", "bg-shell", "index.ts"),
|
|
85
|
+
join(agentDir, "extensions", "browser-tools", "index.ts"),
|
|
86
|
+
join(agentDir, "extensions", "context7", "index.ts"),
|
|
87
|
+
join(agentDir, "extensions", "search-the-web", "index.ts"),
|
|
88
|
+
join(agentDir, "extensions", "slash-commands", "index.ts"),
|
|
89
|
+
join(agentDir, "extensions", "subagent", "index.ts"),
|
|
90
|
+
join(agentDir, "extensions", "mac-tools", "index.ts"),
|
|
91
|
+
join(agentDir, "extensions", "ask-user-questions.ts"),
|
|
92
|
+
join(agentDir, "extensions", "get-secrets-from-user.ts"),
|
|
93
|
+
].join(":");
|
|
94
|
+
// Dynamic import defers ESM evaluation — config.js will see PI_PACKAGE_DIR above
|
|
95
|
+
await import("./cli.js");
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DefaultResourceLoader } from '@mariozechner/pi-coding-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Syncs all bundled resources to agentDir (~/.kata-cli/agent/) on every launch.
|
|
4
|
+
*
|
|
5
|
+
* - extensions/ → ~/.kata-cli/agent/extensions/ (always overwrite)
|
|
6
|
+
* - agents/ → ~/.kata-cli/agent/agents/ (always overwrite)
|
|
7
|
+
* - AGENTS.md → ~/.kata-cli/agent/AGENTS.md (always overwrite)
|
|
8
|
+
* - KATA-WORKFLOW.md is read directly from bundled path via KATA_WORKFLOW_PATH env var
|
|
9
|
+
*
|
|
10
|
+
* Always-overwrite ensures updates take effect immediately.
|
|
11
|
+
*/
|
|
12
|
+
export declare function initResources(agentDir: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a DefaultResourceLoader with no additionalExtensionPaths.
|
|
15
|
+
* Extensions are synced to agentDir by initResources() and pi auto-discovers
|
|
16
|
+
* them from ~/.kata-cli/agent/extensions/ via its normal agentDir scan.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildResourceLoader(agentDir: string): DefaultResourceLoader;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { DefaultResourceLoader } from '@mariozechner/pi-coding-agent';
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
// Resolves to the bundled src/resources/ inside the npm package at runtime:
|
|
6
|
+
// dist/resource-loader.js → .. → package root → src/resources/
|
|
7
|
+
const resourcesDir = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources');
|
|
8
|
+
const bundledExtensionsDir = join(resourcesDir, 'extensions');
|
|
9
|
+
/**
|
|
10
|
+
* Syncs all bundled resources to agentDir (~/.kata-cli/agent/) on every launch.
|
|
11
|
+
*
|
|
12
|
+
* - extensions/ → ~/.kata-cli/agent/extensions/ (always overwrite)
|
|
13
|
+
* - agents/ → ~/.kata-cli/agent/agents/ (always overwrite)
|
|
14
|
+
* - AGENTS.md → ~/.kata-cli/agent/AGENTS.md (always overwrite)
|
|
15
|
+
* - KATA-WORKFLOW.md is read directly from bundled path via KATA_WORKFLOW_PATH env var
|
|
16
|
+
*
|
|
17
|
+
* Always-overwrite ensures updates take effect immediately.
|
|
18
|
+
*/
|
|
19
|
+
export function initResources(agentDir) {
|
|
20
|
+
mkdirSync(agentDir, { recursive: true });
|
|
21
|
+
// Sync extensions — always overwrite so updates land on next launch
|
|
22
|
+
const destExtensions = join(agentDir, 'extensions');
|
|
23
|
+
cpSync(bundledExtensionsDir, destExtensions, { recursive: true, force: true });
|
|
24
|
+
// Sync agents
|
|
25
|
+
const destAgents = join(agentDir, 'agents');
|
|
26
|
+
const srcAgents = join(resourcesDir, 'agents');
|
|
27
|
+
if (existsSync(srcAgents)) {
|
|
28
|
+
cpSync(srcAgents, destAgents, { recursive: true, force: true });
|
|
29
|
+
}
|
|
30
|
+
// Sync skills — always overwrite so updates land on next launch
|
|
31
|
+
const destSkills = join(agentDir, 'skills');
|
|
32
|
+
const srcSkills = join(resourcesDir, 'skills');
|
|
33
|
+
if (existsSync(srcSkills)) {
|
|
34
|
+
cpSync(srcSkills, destSkills, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
// Sync AGENTS.md
|
|
37
|
+
const srcAgentsMd = join(resourcesDir, 'AGENTS.md');
|
|
38
|
+
const destAgentsMd = join(agentDir, 'AGENTS.md');
|
|
39
|
+
if (existsSync(srcAgentsMd)) {
|
|
40
|
+
writeFileSync(destAgentsMd, readFileSync(srcAgentsMd));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Constructs a DefaultResourceLoader with no additionalExtensionPaths.
|
|
45
|
+
* Extensions are synced to agentDir by initResources() and pi auto-discovers
|
|
46
|
+
* them from ~/.kata-cli/agent/extensions/ via its normal agentDir scan.
|
|
47
|
+
*/
|
|
48
|
+
export function buildResourceLoader(agentDir) {
|
|
49
|
+
return new DefaultResourceLoader({ agentDir });
|
|
50
|
+
}
|
package/dist/wizard.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AuthStorage } from '@mariozechner/pi-coding-agent';
|
|
2
|
+
/**
|
|
3
|
+
* Hydrate process.env from stored auth.json credentials for optional tool keys.
|
|
4
|
+
* Runs on every launch so extensions see Brave/Context7/Jina keys stored via the
|
|
5
|
+
* wizard on prior launches.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadStoredEnvKeys(authStorage: AuthStorage): void;
|
|
8
|
+
/**
|
|
9
|
+
* Check for missing optional tool API keys and prompt for them if on a TTY.
|
|
10
|
+
*
|
|
11
|
+
* Anthropic auth is handled by pi's own OAuth/API key flow — we don't touch it.
|
|
12
|
+
* This wizard only collects Brave Search, Context7, and Jina keys which are needed
|
|
13
|
+
* for web search and documentation tools.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runWizardIfNeeded(authStorage: AuthStorage): Promise<void>;
|
package/dist/wizard.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createInterface } from 'readline';
|
|
2
|
+
// ─── Colors ──────────────────────────────────────────────────────────────────
|
|
3
|
+
const cyan = '\x1b[36m';
|
|
4
|
+
const green = '\x1b[32m';
|
|
5
|
+
const yellow = '\x1b[33m';
|
|
6
|
+
const dim = '\x1b[2m';
|
|
7
|
+
const bold = '\x1b[1m';
|
|
8
|
+
const reset = '\x1b[0m';
|
|
9
|
+
// ─── Masked input ─────────────────────────────────────────────────────────────
|
|
10
|
+
/**
|
|
11
|
+
* Prompt for masked input using raw mode stdin.
|
|
12
|
+
* Handles backspace, Ctrl+C, and Enter.
|
|
13
|
+
* Falls back to plain readline if setRawMode is unavailable (e.g. some SSH contexts).
|
|
14
|
+
*/
|
|
15
|
+
async function promptMasked(label, hint) {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
const question = ` ${cyan}›${reset} ${label} ${dim}${hint}${reset}\n `;
|
|
18
|
+
try {
|
|
19
|
+
process.stdout.write(question);
|
|
20
|
+
process.stdin.setRawMode(true);
|
|
21
|
+
process.stdin.resume();
|
|
22
|
+
process.stdin.setEncoding('utf8');
|
|
23
|
+
let value = '';
|
|
24
|
+
const handler = (ch) => {
|
|
25
|
+
if (ch === '\r' || ch === '\n') {
|
|
26
|
+
process.stdin.setRawMode(false);
|
|
27
|
+
process.stdin.pause();
|
|
28
|
+
process.stdin.off('data', handler);
|
|
29
|
+
process.stdout.write('\n');
|
|
30
|
+
resolve(value);
|
|
31
|
+
}
|
|
32
|
+
else if (ch === '\u0003') {
|
|
33
|
+
process.stdin.setRawMode(false);
|
|
34
|
+
process.stdout.write('\n');
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
else if (ch === '\u007f') {
|
|
38
|
+
if (value.length > 0) {
|
|
39
|
+
value = value.slice(0, -1);
|
|
40
|
+
}
|
|
41
|
+
process.stdout.clearLine(0);
|
|
42
|
+
process.stdout.cursorTo(0);
|
|
43
|
+
process.stdout.write(' ' + '*'.repeat(value.length));
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
value += ch;
|
|
47
|
+
process.stdout.write('*');
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
process.stdin.on('data', handler);
|
|
51
|
+
}
|
|
52
|
+
catch (_err) {
|
|
53
|
+
process.stdout.write(` ${dim}(input will be visible)${reset}\n `);
|
|
54
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
55
|
+
rl.question('', (answer) => {
|
|
56
|
+
rl.close();
|
|
57
|
+
resolve(answer);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// ─── Env hydration ────────────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Hydrate process.env from stored auth.json credentials for optional tool keys.
|
|
65
|
+
* Runs on every launch so extensions see Brave/Context7/Jina keys stored via the
|
|
66
|
+
* wizard on prior launches.
|
|
67
|
+
*/
|
|
68
|
+
export function loadStoredEnvKeys(authStorage) {
|
|
69
|
+
const providers = [
|
|
70
|
+
['brave', 'BRAVE_API_KEY'],
|
|
71
|
+
['brave_answers', 'BRAVE_ANSWERS_KEY'],
|
|
72
|
+
['context7', 'CONTEXT7_API_KEY'],
|
|
73
|
+
['jina', 'JINA_API_KEY'],
|
|
74
|
+
];
|
|
75
|
+
for (const [provider, envVar] of providers) {
|
|
76
|
+
if (!process.env[envVar]) {
|
|
77
|
+
const cred = authStorage.get(provider);
|
|
78
|
+
if (cred?.type === 'api_key') {
|
|
79
|
+
process.env[envVar] = cred.key;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const API_KEYS = [
|
|
85
|
+
{
|
|
86
|
+
provider: 'brave',
|
|
87
|
+
envVar: 'BRAVE_API_KEY',
|
|
88
|
+
label: 'Brave Search',
|
|
89
|
+
hint: '(search-the-web + search_and_read tools)',
|
|
90
|
+
description: 'Web search and page extraction',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
provider: 'brave_answers',
|
|
94
|
+
envVar: 'BRAVE_ANSWERS_KEY',
|
|
95
|
+
label: 'Brave Answers',
|
|
96
|
+
hint: '(AI-summarised search answers)',
|
|
97
|
+
description: 'AI-generated search summaries',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
provider: 'context7',
|
|
101
|
+
envVar: 'CONTEXT7_API_KEY',
|
|
102
|
+
label: 'Context7',
|
|
103
|
+
hint: '(up-to-date library docs)',
|
|
104
|
+
description: 'Live library and framework documentation',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
provider: 'jina',
|
|
108
|
+
envVar: 'JINA_API_KEY',
|
|
109
|
+
label: 'Jina AI',
|
|
110
|
+
hint: '(clean page extraction)',
|
|
111
|
+
description: 'High-quality web page content extraction',
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Check for missing optional tool API keys and prompt for them if on a TTY.
|
|
116
|
+
*
|
|
117
|
+
* Anthropic auth is handled by pi's own OAuth/API key flow — we don't touch it.
|
|
118
|
+
* This wizard only collects Brave Search, Context7, and Jina keys which are needed
|
|
119
|
+
* for web search and documentation tools.
|
|
120
|
+
*/
|
|
121
|
+
export async function runWizardIfNeeded(authStorage) {
|
|
122
|
+
const missing = API_KEYS.filter(k => !authStorage.has(k.provider) && !process.env[k.envVar]);
|
|
123
|
+
if (missing.length === 0)
|
|
124
|
+
return;
|
|
125
|
+
// Non-TTY: warn and continue
|
|
126
|
+
if (!process.stdin.isTTY) {
|
|
127
|
+
const names = missing.map(k => k.label).join(', ');
|
|
128
|
+
process.stderr.write(`[kata] Warning: optional tool API keys not configured (${names}). Some tools may not work.\n`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// ── Header ──────────────────────────────────────────────────────────────────
|
|
132
|
+
process.stdout.write(`\n ${bold}Optional API keys${reset}\n` +
|
|
133
|
+
` ${dim}─────────────────────────────────────────────${reset}\n` +
|
|
134
|
+
` These unlock additional tools. All optional — press ${cyan}Enter${reset} to skip any.\n\n`);
|
|
135
|
+
// ── Prompts ─────────────────────────────────────────────────────────────────
|
|
136
|
+
let savedCount = 0;
|
|
137
|
+
for (const key of missing) {
|
|
138
|
+
const value = await promptMasked(key.label, key.hint);
|
|
139
|
+
if (value.trim()) {
|
|
140
|
+
authStorage.set(key.provider, { type: 'api_key', key: value.trim() });
|
|
141
|
+
process.env[key.envVar] = value.trim();
|
|
142
|
+
process.stdout.write(` ${green}✓${reset} ${key.label} saved\n\n`);
|
|
143
|
+
savedCount++;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
process.stdout.write(` ${dim}↷ ${key.label} skipped${reset}\n\n`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ── Footer ───────────────────────────────────────────────────────────────────
|
|
150
|
+
process.stdout.write(` ${dim}─────────────────────────────────────────────${reset}\n`);
|
|
151
|
+
if (savedCount > 0) {
|
|
152
|
+
process.stdout.write(` ${green}✓${reset} ${savedCount} key${savedCount > 1 ? 's' : ''} saved to ${dim}~/.kata-cli/agent/auth.json${reset}\n` +
|
|
153
|
+
` ${dim}Run ${reset}${cyan}/login${reset}${dim} inside kata to connect your LLM provider.${reset}\n\n`);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
process.stdout.write(` ${yellow}↷${reset} All keys skipped — you can add them later via ${dim}~/.kata-cli/agent/auth.json${reset}\n` +
|
|
157
|
+
` ${dim}Run ${reset}${cyan}/login${reset}${dim} inside kata to connect your LLM provider.${reset}\n\n`);
|
|
158
|
+
}
|
|
159
|
+
}
|