openkitt 0.1.2
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 +236 -0
- package/dist/ast/engine.d.ts +26 -0
- package/dist/ast/engine.js +130 -0
- package/dist/ast/engine.js.map +1 -0
- package/dist/ast/operations.d.ts +13 -0
- package/dist/ast/operations.js +329 -0
- package/dist/ast/operations.js.map +1 -0
- package/dist/ast/validator.d.ts +19 -0
- package/dist/ast/validator.js +281 -0
- package/dist/ast/validator.js.map +1 -0
- package/dist/audit/logger.d.ts +14 -0
- package/dist/audit/logger.js +102 -0
- package/dist/audit/logger.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +401 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/create-confirm.d.ts +13 -0
- package/dist/commands/create-confirm.js +38 -0
- package/dist/commands/create-confirm.js.map +1 -0
- package/dist/commands/create-infra.d.ts +20 -0
- package/dist/commands/create-infra.js +63 -0
- package/dist/commands/create-infra.js.map +1 -0
- package/dist/commands/create-manifest.d.ts +10 -0
- package/dist/commands/create-manifest.js +21 -0
- package/dist/commands/create-manifest.js.map +1 -0
- package/dist/commands/create-packages.d.ts +17 -0
- package/dist/commands/create-packages.js +69 -0
- package/dist/commands/create-packages.js.map +1 -0
- package/dist/commands/create-pipeline.d.ts +15 -0
- package/dist/commands/create-pipeline.js +57 -0
- package/dist/commands/create-pipeline.js.map +1 -0
- package/dist/commands/create-scaffolding.d.ts +12 -0
- package/dist/commands/create-scaffolding.js +137 -0
- package/dist/commands/create-scaffolding.js.map +1 -0
- package/dist/commands/create-staging.d.ts +13 -0
- package/dist/commands/create-staging.js +17 -0
- package/dist/commands/create-staging.js.map +1 -0
- package/dist/commands/create-transforms.d.ts +10 -0
- package/dist/commands/create-transforms.js +33 -0
- package/dist/commands/create-transforms.js.map +1 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +155 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +2 -0
- package/dist/commands/delete.js +83 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.js +371 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/domain.d.ts +2 -0
- package/dist/commands/domain.js +90 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/env.d.ts +2 -0
- package/dist/commands/env.js +153 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.js +107 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +217 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +142 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +235 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +90 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +113 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/run.d.ts +14 -0
- package/dist/commands/run.js +196 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/settings.d.ts +3 -0
- package/dist/commands/settings.js +278 -0
- package/dist/commands/settings.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +88 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/versions.d.ts +2 -0
- package/dist/commands/versions.js +242 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/credentials/config.d.ts +12 -0
- package/dist/credentials/config.js +196 -0
- package/dist/credentials/config.js.map +1 -0
- package/dist/credentials/encryption.d.ts +9 -0
- package/dist/credentials/encryption.js +100 -0
- package/dist/credentials/encryption.js.map +1 -0
- package/dist/credentials/keychain.d.ts +8 -0
- package/dist/credentials/keychain.js +236 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/railway.d.ts +9 -0
- package/dist/credentials/railway.js +69 -0
- package/dist/credentials/railway.js.map +1 -0
- package/dist/llm/client.d.ts +59 -0
- package/dist/llm/client.js +530 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/operations.d.ts +39 -0
- package/dist/llm/operations.js +131 -0
- package/dist/llm/operations.js.map +1 -0
- package/dist/llm/rate-limiter.d.ts +20 -0
- package/dist/llm/rate-limiter.js +57 -0
- package/dist/llm/rate-limiter.js.map +1 -0
- package/dist/llm/scaffolding.d.ts +51 -0
- package/dist/llm/scaffolding.js +118 -0
- package/dist/llm/scaffolding.js.map +1 -0
- package/dist/manifest/drift.d.ts +6 -0
- package/dist/manifest/drift.js +45 -0
- package/dist/manifest/drift.js.map +1 -0
- package/dist/manifest/reader.d.ts +12 -0
- package/dist/manifest/reader.js +99 -0
- package/dist/manifest/reader.js.map +1 -0
- package/dist/manifest/types.d.ts +31 -0
- package/dist/manifest/types.js +2 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/manifest/writer.d.ts +9 -0
- package/dist/manifest/writer.js +142 -0
- package/dist/manifest/writer.js.map +1 -0
- package/dist/mcp/client.d.ts +21 -0
- package/dist/mcp/client.js +213 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/lifecycle.d.ts +12 -0
- package/dist/mcp/lifecycle.js +149 -0
- package/dist/mcp/lifecycle.js.map +1 -0
- package/dist/mcp/project-guard.d.ts +14 -0
- package/dist/mcp/project-guard.js +27 -0
- package/dist/mcp/project-guard.js.map +1 -0
- package/dist/prompts/operations.d.ts +1 -0
- package/dist/prompts/operations.js +160 -0
- package/dist/prompts/operations.js.map +1 -0
- package/dist/prompts/scaffolding.d.ts +1 -0
- package/dist/prompts/scaffolding.js +331 -0
- package/dist/prompts/scaffolding.js.map +1 -0
- package/dist/prompts/version.d.ts +2 -0
- package/dist/prompts/version.js +3 -0
- package/dist/prompts/version.js.map +1 -0
- package/dist/sandbox/command-allowlist.d.ts +6 -0
- package/dist/sandbox/command-allowlist.js +103 -0
- package/dist/sandbox/command-allowlist.js.map +1 -0
- package/dist/sandbox/package-allowlist.d.ts +6 -0
- package/dist/sandbox/package-allowlist.js +49 -0
- package/dist/sandbox/package-allowlist.js.map +1 -0
- package/dist/sandbox/scanner.d.ts +25 -0
- package/dist/sandbox/scanner.js +196 -0
- package/dist/sandbox/scanner.js.map +1 -0
- package/dist/sandbox/staging.d.ts +12 -0
- package/dist/sandbox/staging.js +107 -0
- package/dist/sandbox/staging.js.map +1 -0
- package/dist/scaffold/frameworks/express.d.ts +3 -0
- package/dist/scaffold/frameworks/express.js +242 -0
- package/dist/scaffold/frameworks/express.js.map +1 -0
- package/dist/scaffold/frameworks/hono.d.ts +3 -0
- package/dist/scaffold/frameworks/hono.js +238 -0
- package/dist/scaffold/frameworks/hono.js.map +1 -0
- package/dist/scaffold/frameworks/nextjs.d.ts +3 -0
- package/dist/scaffold/frameworks/nextjs.js +447 -0
- package/dist/scaffold/frameworks/nextjs.js.map +1 -0
- package/dist/scaffold/frameworks/tanstack-start.d.ts +3 -0
- package/dist/scaffold/frameworks/tanstack-start.js +280 -0
- package/dist/scaffold/frameworks/tanstack-start.js.map +1 -0
- package/dist/scaffold/index.d.ts +4 -0
- package/dist/scaffold/index.js +138 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/integrations/backend.d.ts +3 -0
- package/dist/scaffold/integrations/backend.js +403 -0
- package/dist/scaffold/integrations/backend.js.map +1 -0
- package/dist/scaffold/integrations/posthog.d.ts +2 -0
- package/dist/scaffold/integrations/posthog.js +21 -0
- package/dist/scaffold/integrations/posthog.js.map +1 -0
- package/dist/scaffold/integrations/sentry.d.ts +2 -0
- package/dist/scaffold/integrations/sentry.js +16 -0
- package/dist/scaffold/integrations/sentry.js.map +1 -0
- package/dist/scaffold/integrations/storybook.d.ts +2 -0
- package/dist/scaffold/integrations/storybook.js +79 -0
- package/dist/scaffold/integrations/storybook.js.map +1 -0
- package/dist/scaffold/integrations/vitest.d.ts +2 -0
- package/dist/scaffold/integrations/vitest.js +37 -0
- package/dist/scaffold/integrations/vitest.js.map +1 -0
- package/dist/scaffold/package-builder.d.ts +3 -0
- package/dist/scaffold/package-builder.js +136 -0
- package/dist/scaffold/package-builder.js.map +1 -0
- package/dist/scaffold/packages.d.ts +4 -0
- package/dist/scaffold/packages.js +144 -0
- package/dist/scaffold/packages.js.map +1 -0
- package/dist/scaffold/types.d.ts +20 -0
- package/dist/scaffold/types.js +2 -0
- package/dist/scaffold/types.js.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-guard.d.ts +5 -0
- package/dist/utils/auth-guard.js +52 -0
- package/dist/utils/auth-guard.js.map +1 -0
- package/dist/utils/cleanup.d.ts +2 -0
- package/dist/utils/cleanup.js +37 -0
- package/dist/utils/cleanup.js.map +1 -0
- package/dist/utils/constraints.d.ts +11 -0
- package/dist/utils/constraints.js +162 -0
- package/dist/utils/constraints.js.map +1 -0
- package/dist/utils/display.d.ts +32 -0
- package/dist/utils/display.js +103 -0
- package/dist/utils/display.js.map +1 -0
- package/dist/utils/global-config.d.ts +8 -0
- package/dist/utils/global-config.js +39 -0
- package/dist/utils/global-config.js.map +1 -0
- package/dist/utils/pm.d.ts +4 -0
- package/dist/utils/pm.js +40 -0
- package/dist/utils/pm.js.map +1 -0
- package/dist/utils/prerequisites.d.ts +9 -0
- package/dist/utils/prerequisites.js +96 -0
- package/dist/utils/prerequisites.js.map +1 -0
- package/dist/utils/prompts.d.ts +25 -0
- package/dist/utils/prompts.js +148 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/validation.d.ts +9 -0
- package/dist/utils/validation.js +38 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/versions/compat.d.ts +13 -0
- package/dist/versions/compat.js +127 -0
- package/dist/versions/compat.js.map +1 -0
- package/dist/versions/integrity.d.ts +9 -0
- package/dist/versions/integrity.js +60 -0
- package/dist/versions/integrity.js.map +1 -0
- package/dist/versions/parser.d.ts +13 -0
- package/dist/versions/parser.js +106 -0
- package/dist/versions/parser.js.map +1 -0
- package/dist/versions/registry.d.ts +30 -0
- package/dist/versions/registry.js +165 -0
- package/dist/versions/registry.js.map +1 -0
- package/package.json +58 -0
- package/scripts/publish.sh +254 -0
package/README.md
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# KITT
|
|
2
|
+
|
|
3
|
+
**AI-powered monorepo CLI for Railway deployments.**
|
|
4
|
+
|
|
5
|
+
KITT is an interactive terminal interface that scaffolds full-stack monorepos, adds apps with integrations pre-wired, and manages deployment to [Railway](https://railway.app) — all from a persistent REPL shell.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
______ _______________________
|
|
9
|
+
___ //_/___ /__ __/__ __/
|
|
10
|
+
__ ,< __ / __ / __ /
|
|
11
|
+
_ /| | __/ / _ / _ /
|
|
12
|
+
/_/ |_| /___/ /_/ /_/
|
|
13
|
+
|
|
14
|
+
KITT v0.1.0 — AI-Powered App Scaffolding CLI
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why KITT?
|
|
20
|
+
|
|
21
|
+
Modern app development means stitching together a monorepo, a cloud platform, an ORM, auth, payments, a job queue, and more — before writing a single line of product code. The setup tax is real and repetitive.
|
|
22
|
+
|
|
23
|
+
KITT eliminates that tax. It scaffolds a production-ready monorepo in one command, adds new apps with integrations already wired, and handles Railway deployments through a conversational REPL — no context-switching, no config hunting.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Who it's for
|
|
28
|
+
|
|
29
|
+
- **Indie developers and small teams** shipping full-stack TypeScript apps to Railway
|
|
30
|
+
- **Developers who want opinions** — KITT makes a stack choice (TanStack Start, Next.js, Hono, Express) and sets it up correctly
|
|
31
|
+
- **Teams who iterate fast** — add apps, provision databases, rotate envs, tail logs, all without leaving the terminal
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **Interactive REPL** with tab-completion and ghost text suggestions
|
|
38
|
+
- **AI scaffolding** — uses your LLM key (Anthropic, OpenAI, or Gemini) to generate app code, wire integrations, and provision Railway infrastructure
|
|
39
|
+
- **Monorepo workspace** with `apps/` and `packages/` following convention
|
|
40
|
+
- **Framework support**: TanStack Start, Next.js, Hono, Express
|
|
41
|
+
- **Integration catalog**: databases, auth, payments, email, queues, caching, UI, analytics, testing
|
|
42
|
+
- **Version management** — pin integration versions, check for updates, apply selectively
|
|
43
|
+
- **Secret scan** — blocks deploys if `.env` files containing secrets would be committed
|
|
44
|
+
- **Non-interactive mode** — scriptable via `--run` flag for CI pipelines
|
|
45
|
+
- **Auto update check** — notifies on new releases at startup
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- Node.js ≥ 20
|
|
52
|
+
- [Railway CLI](https://docs.railway.app/develop/cli) installed and authenticated
|
|
53
|
+
- API key for one of: Anthropic, OpenAI, or Gemini
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Install globally
|
|
61
|
+
npm install -g openkitt
|
|
62
|
+
|
|
63
|
+
# Or run without installing
|
|
64
|
+
npx openkitt
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 1. Authenticate
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
kitt > /login
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This walks you through Railway authentication (browser OAuth) and LLM provider setup (provider, model, API key). You only do this once — credentials are stored locally.
|
|
74
|
+
|
|
75
|
+
### 2. Initialize a workspace
|
|
76
|
+
|
|
77
|
+
Create a new directory and initialize it as a KITT monorepo:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mkdir my-project && cd my-project
|
|
81
|
+
npx openkitt
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
kitt > /init
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
KITT will:
|
|
89
|
+
- Prompt for a workspace name
|
|
90
|
+
- Create the `apps/` and `packages/` directory structure
|
|
91
|
+
- Write a workspace manifest (`.kitt/manifest.json`)
|
|
92
|
+
- Create a Railway project and link it to the workspace
|
|
93
|
+
- Generate `versions.md` with pinned integration versions
|
|
94
|
+
|
|
95
|
+
### 3. Add an app
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
kitt [my-project] > /create
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
KITT prompts you to select:
|
|
102
|
+
- **Framework** — TanStack Start, Next.js, Hono, or Express
|
|
103
|
+
- **Integrations** — pick from databases, auth, payments, email, queues, UI libraries, testing, and more
|
|
104
|
+
|
|
105
|
+
Then it scaffolds the app, installs packages, wires integrations, and stages everything for review before writing to disk.
|
|
106
|
+
|
|
107
|
+
### 4. Run locally
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
kitt [my-project] > /run
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Starts the dev server for a selected app. Auto-detects the dev script (`dev`, `start`, `serve`, `preview`) and opens the browser when the URL is detected.
|
|
114
|
+
|
|
115
|
+
### 5. Deploy to Railway
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
kitt [my-project] > /deploy
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Selects the app, generates `railway.toml` if needed, scans for exposed secrets, and triggers a Railway deployment via the MCP server.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Commands
|
|
126
|
+
|
|
127
|
+
### Setup
|
|
128
|
+
|
|
129
|
+
| Command | Description |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `/login` | Full auth setup — Railway + LLM in one flow |
|
|
132
|
+
| `/login railway` | Authenticate with Railway only |
|
|
133
|
+
| `/login llm` | Configure LLM provider, model, and API key |
|
|
134
|
+
| `/login model` | Switch model without re-entering your key |
|
|
135
|
+
| `/logout` | Remove all stored credentials |
|
|
136
|
+
|
|
137
|
+
### Workspace
|
|
138
|
+
|
|
139
|
+
| Command | Description |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `/init` | Scaffold a new KITT monorepo workspace |
|
|
142
|
+
| `/create` | Add a new app to the current workspace |
|
|
143
|
+
| `/delete [appName]` | Remove an app and its files |
|
|
144
|
+
| `/list` | List all apps, packages, and Railway services |
|
|
145
|
+
| `/run [appName]` | Start an app's dev server |
|
|
146
|
+
| `/settings` | View or update workspace settings |
|
|
147
|
+
|
|
148
|
+
### Deploy & Infrastructure
|
|
149
|
+
|
|
150
|
+
| Command | Description |
|
|
151
|
+
|---|---|
|
|
152
|
+
| `/deploy [appName]` | Deploy an app to Railway |
|
|
153
|
+
| `/deploy:template <name>` | Provision infrastructure — `PostgreSQL`, `MySQL`, `Redis`, `MinIO` |
|
|
154
|
+
| `/env:create <name>` | Create a new Railway environment |
|
|
155
|
+
| `/env:vars [service]` | List environment variables for a service |
|
|
156
|
+
| `/domain [appName]` | Generate or show the Railway domain for an app |
|
|
157
|
+
| `/logs [appName]` | Tail deployment logs |
|
|
158
|
+
| `/status` | Show workspace status and Railway deployment health |
|
|
159
|
+
|
|
160
|
+
### Version Management
|
|
161
|
+
|
|
162
|
+
| Command | Description |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `/versions` | View all pinned integration versions |
|
|
165
|
+
| `/versions check` | Check npm registry for newer versions |
|
|
166
|
+
| `/versions update` | Interactive update wizard — pick which to bump |
|
|
167
|
+
| `/versions set <integration> <version>` | Pin a specific version manually |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Frameworks & Integrations
|
|
172
|
+
|
|
173
|
+
**Frameworks**
|
|
174
|
+
|
|
175
|
+
| Type | Options |
|
|
176
|
+
|---|---|
|
|
177
|
+
| Full-stack | `tanstack-start`, `nextjs` |
|
|
178
|
+
| Backend | `hono`, `expressjs` |
|
|
179
|
+
|
|
180
|
+
**Integrations**
|
|
181
|
+
|
|
182
|
+
| Category | Options |
|
|
183
|
+
|---|---|
|
|
184
|
+
| Databases | `postgresql`, `mysql`, `sqlite` |
|
|
185
|
+
| ORM | `drizzle`, `prisma` |
|
|
186
|
+
| Auth | `better-auth` |
|
|
187
|
+
| Payments | `stripe`, `polar` |
|
|
188
|
+
| Email | `resend` |
|
|
189
|
+
| Queues | `bullmq`, `trigger-dev` |
|
|
190
|
+
| Cache | `redis` |
|
|
191
|
+
| UI | `tailwindcss`, `shadcn` |
|
|
192
|
+
| Analytics | `posthog`, `sentry` |
|
|
193
|
+
| Testing | `vitest`, `playwright`, `storybook` |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## CLI Flags
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
--verbose Enable verbose logging
|
|
201
|
+
-q, --quiet Suppress non-essential output
|
|
202
|
+
--run <command> Execute a single command and exit (non-interactive)
|
|
203
|
+
--dry-run Preview changes without applying them
|
|
204
|
+
-y, --yes Auto-confirm all prompts
|
|
205
|
+
--config <json> Pass command selections as inline JSON
|
|
206
|
+
--env <name> Target a specific Railway environment
|
|
207
|
+
--no-update-check Skip the version check on startup
|
|
208
|
+
--debug Show LLM timing and token usage after scaffolding
|
|
209
|
+
-v, --version Print CLI version
|
|
210
|
+
-h, --help Print help
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Non-interactive mode
|
|
214
|
+
|
|
215
|
+
KITT supports scriptable execution via `--run`:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Deploy from CI without prompts
|
|
219
|
+
npx openkitt --run "deploy my-app" --yes --env production
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
State-changing commands (`init`, `create`, `delete`, `deploy`, `env:create`, `env:vars`, `domain`) require `--yes` in non-interactive mode.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## How it works
|
|
227
|
+
|
|
228
|
+
KITT uses an LLM (via your API key) together with Railway's [MCP server](https://github.com/railwayapp/mcp-server) to perform Railway operations — creating projects, provisioning services, setting environment variables, and deploying. The LLM orchestrates MCP tool calls; KITT acts as the secure intermediary, enforcing a project-scoped guard so operations are confined to your linked Railway project.
|
|
229
|
+
|
|
230
|
+
For `hono` and `expressjs` apps, scaffolding is fully static — the LLM generates code at creation time only. For `tanstack-start` and `nextjs`, full server and client capabilities are available.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Project, SourceFile } from 'ts-morph';
|
|
2
|
+
export interface AstOperation {
|
|
3
|
+
op: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface AstTransform {
|
|
7
|
+
path: string;
|
|
8
|
+
operations: AstOperation[];
|
|
9
|
+
}
|
|
10
|
+
export interface AstEngineResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
modifiedFiles: string[];
|
|
13
|
+
errors: AstError[];
|
|
14
|
+
}
|
|
15
|
+
export interface AstError {
|
|
16
|
+
filePath: string;
|
|
17
|
+
operation: AstOperation;
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AstEngine {
|
|
21
|
+
loadSourceFile(relativePath: string): SourceFile;
|
|
22
|
+
writeToStaging(relativePath: string, sourceFile: SourceFile): void;
|
|
23
|
+
applyTransforms(transforms: AstTransform[], operationHandler: (sourceFile: SourceFile, operation: AstOperation) => void): AstEngineResult;
|
|
24
|
+
getProject(): Project;
|
|
25
|
+
}
|
|
26
|
+
export declare function createAstEngine(workspaceDir: string): AstEngine;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, isAbsolute, join, normalize, relative, resolve } from 'node:path';
|
|
4
|
+
import { Project } from 'ts-morph';
|
|
5
|
+
import { createAuditLogger } from '../audit/logger.js';
|
|
6
|
+
const KITT_DIR = '.kitt';
|
|
7
|
+
const STAGING_DIR = 'staging';
|
|
8
|
+
function hashContent(content) {
|
|
9
|
+
return createHash('sha256').update(content).digest('hex');
|
|
10
|
+
}
|
|
11
|
+
function isRelativePathInside(baseDir, targetPath) {
|
|
12
|
+
const pathFromBase = relative(baseDir, targetPath);
|
|
13
|
+
if (pathFromBase === '') {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return !pathFromBase.startsWith('..') && !isAbsolute(pathFromBase);
|
|
17
|
+
}
|
|
18
|
+
function validateRelativePath(relativePath) {
|
|
19
|
+
if (isAbsolute(relativePath)) {
|
|
20
|
+
throw new Error(`Absolute paths are not allowed: ${relativePath}`);
|
|
21
|
+
}
|
|
22
|
+
const rawSegments = relativePath.split(/[\\/]+/);
|
|
23
|
+
if (rawSegments.includes('..')) {
|
|
24
|
+
throw new Error(`Path traversal is not allowed: ${relativePath}`);
|
|
25
|
+
}
|
|
26
|
+
const normalizedRelativePath = normalize(relativePath);
|
|
27
|
+
const pathSegments = normalizedRelativePath.split(/[\\/]+/);
|
|
28
|
+
if (pathSegments.includes('node_modules')) {
|
|
29
|
+
throw new Error(`Refusing to load files from node_modules: ${relativePath}`);
|
|
30
|
+
}
|
|
31
|
+
if (pathSegments.includes(KITT_DIR)) {
|
|
32
|
+
throw new Error(`Refusing to load files from ${KITT_DIR}: ${relativePath}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function createAstEngine(workspaceDir) {
|
|
36
|
+
const project = new Project({
|
|
37
|
+
compilerOptions: {
|
|
38
|
+
skipLibCheck: true,
|
|
39
|
+
},
|
|
40
|
+
skipAddingFilesFromTsConfig: true,
|
|
41
|
+
});
|
|
42
|
+
const auditLogger = createAuditLogger(workspaceDir);
|
|
43
|
+
function loadSourceFile(relativePath) {
|
|
44
|
+
validateRelativePath(relativePath);
|
|
45
|
+
const fullPath = resolve(workspaceDir, relativePath);
|
|
46
|
+
if (!isRelativePathInside(workspaceDir, fullPath)) {
|
|
47
|
+
throw new Error(`Path is outside workspace: ${relativePath}`);
|
|
48
|
+
}
|
|
49
|
+
if (!existsSync(fullPath)) {
|
|
50
|
+
throw new Error(`File does not exist: ${relativePath}`);
|
|
51
|
+
}
|
|
52
|
+
const existing = project.getSourceFile(fullPath);
|
|
53
|
+
if (existing) {
|
|
54
|
+
return existing;
|
|
55
|
+
}
|
|
56
|
+
return project.addSourceFileAtPath(fullPath);
|
|
57
|
+
}
|
|
58
|
+
function writeToStaging(relativePath, sourceFile) {
|
|
59
|
+
validateRelativePath(relativePath);
|
|
60
|
+
const stagingPath = join(workspaceDir, KITT_DIR, STAGING_DIR, relativePath);
|
|
61
|
+
if (!isRelativePathInside(resolve(workspaceDir, KITT_DIR, STAGING_DIR), stagingPath)) {
|
|
62
|
+
throw new Error(`Refusing to write outside staging directory: ${relativePath}`);
|
|
63
|
+
}
|
|
64
|
+
mkdirSync(dirname(stagingPath), { recursive: true });
|
|
65
|
+
const fullText = sourceFile.getFullText();
|
|
66
|
+
writeFileSync(stagingPath, fullText, 'utf-8');
|
|
67
|
+
auditLogger.staged(relativePath, 'AST modified');
|
|
68
|
+
auditLogger.fileWrite(join(KITT_DIR, STAGING_DIR, relativePath), hashContent(fullText));
|
|
69
|
+
}
|
|
70
|
+
function applyTransforms(transforms, operationHandler) {
|
|
71
|
+
const modifiedFiles = [];
|
|
72
|
+
const errors = [];
|
|
73
|
+
for (const transform of transforms) {
|
|
74
|
+
let sourceFile;
|
|
75
|
+
try {
|
|
76
|
+
sourceFile = loadSourceFile(transform.path);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
errors.push({
|
|
80
|
+
filePath: transform.path,
|
|
81
|
+
operation: { op: 'loadSourceFile' },
|
|
82
|
+
message: error instanceof Error ? error.message : String(error),
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const priorErrorCount = errors.length;
|
|
87
|
+
for (const operation of transform.operations) {
|
|
88
|
+
try {
|
|
89
|
+
operationHandler(sourceFile, operation);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
errors.push({
|
|
93
|
+
filePath: transform.path,
|
|
94
|
+
operation,
|
|
95
|
+
message: error instanceof Error ? error.message : String(error),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (errors.length > priorErrorCount) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
writeToStaging(transform.path, sourceFile);
|
|
104
|
+
modifiedFiles.push(transform.path);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
errors.push({
|
|
108
|
+
filePath: transform.path,
|
|
109
|
+
operation: { op: 'writeToStaging' },
|
|
110
|
+
message: error instanceof Error ? error.message : String(error),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
success: errors.length === 0,
|
|
116
|
+
modifiedFiles,
|
|
117
|
+
errors,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function getProject() {
|
|
121
|
+
return project;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
loadSourceFile,
|
|
125
|
+
writeToStaging,
|
|
126
|
+
applyTransforms,
|
|
127
|
+
getProject,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/ast/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SourceFile } from 'ts-morph';
|
|
2
|
+
import type { AstOperation } from './engine.js';
|
|
3
|
+
/**
|
|
4
|
+
* The set of supported AST operation names.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SUPPORTED_OPERATIONS: ReadonlySet<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Apply a single AST operation to a source file.
|
|
9
|
+
* This is the operation handler that gets passed to engine.applyTransforms().
|
|
10
|
+
*
|
|
11
|
+
* Throws if the operation type is unknown or if the operation fails.
|
|
12
|
+
*/
|
|
13
|
+
export declare function applyOperation(sourceFile: SourceFile, operation: AstOperation): void;
|