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.
Files changed (234) hide show
  1. package/README.md +236 -0
  2. package/dist/ast/engine.d.ts +26 -0
  3. package/dist/ast/engine.js +130 -0
  4. package/dist/ast/engine.js.map +1 -0
  5. package/dist/ast/operations.d.ts +13 -0
  6. package/dist/ast/operations.js +329 -0
  7. package/dist/ast/operations.js.map +1 -0
  8. package/dist/ast/validator.d.ts +19 -0
  9. package/dist/ast/validator.js +281 -0
  10. package/dist/ast/validator.js.map +1 -0
  11. package/dist/audit/logger.d.ts +14 -0
  12. package/dist/audit/logger.js +102 -0
  13. package/dist/audit/logger.js.map +1 -0
  14. package/dist/cli.d.ts +4 -0
  15. package/dist/cli.js +401 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/commands/create-confirm.d.ts +13 -0
  18. package/dist/commands/create-confirm.js +38 -0
  19. package/dist/commands/create-confirm.js.map +1 -0
  20. package/dist/commands/create-infra.d.ts +20 -0
  21. package/dist/commands/create-infra.js +63 -0
  22. package/dist/commands/create-infra.js.map +1 -0
  23. package/dist/commands/create-manifest.d.ts +10 -0
  24. package/dist/commands/create-manifest.js +21 -0
  25. package/dist/commands/create-manifest.js.map +1 -0
  26. package/dist/commands/create-packages.d.ts +17 -0
  27. package/dist/commands/create-packages.js +69 -0
  28. package/dist/commands/create-packages.js.map +1 -0
  29. package/dist/commands/create-pipeline.d.ts +15 -0
  30. package/dist/commands/create-pipeline.js +57 -0
  31. package/dist/commands/create-pipeline.js.map +1 -0
  32. package/dist/commands/create-scaffolding.d.ts +12 -0
  33. package/dist/commands/create-scaffolding.js +137 -0
  34. package/dist/commands/create-scaffolding.js.map +1 -0
  35. package/dist/commands/create-staging.d.ts +13 -0
  36. package/dist/commands/create-staging.js +17 -0
  37. package/dist/commands/create-staging.js.map +1 -0
  38. package/dist/commands/create-transforms.d.ts +10 -0
  39. package/dist/commands/create-transforms.js +33 -0
  40. package/dist/commands/create-transforms.js.map +1 -0
  41. package/dist/commands/create.d.ts +2 -0
  42. package/dist/commands/create.js +155 -0
  43. package/dist/commands/create.js.map +1 -0
  44. package/dist/commands/delete.d.ts +2 -0
  45. package/dist/commands/delete.js +83 -0
  46. package/dist/commands/delete.js.map +1 -0
  47. package/dist/commands/deploy.d.ts +5 -0
  48. package/dist/commands/deploy.js +371 -0
  49. package/dist/commands/deploy.js.map +1 -0
  50. package/dist/commands/domain.d.ts +2 -0
  51. package/dist/commands/domain.js +90 -0
  52. package/dist/commands/domain.js.map +1 -0
  53. package/dist/commands/env.d.ts +2 -0
  54. package/dist/commands/env.js +153 -0
  55. package/dist/commands/env.js.map +1 -0
  56. package/dist/commands/help.d.ts +3 -0
  57. package/dist/commands/help.js +107 -0
  58. package/dist/commands/help.js.map +1 -0
  59. package/dist/commands/init.d.ts +2 -0
  60. package/dist/commands/init.js +217 -0
  61. package/dist/commands/init.js.map +1 -0
  62. package/dist/commands/list.d.ts +2 -0
  63. package/dist/commands/list.js +142 -0
  64. package/dist/commands/list.js.map +1 -0
  65. package/dist/commands/login.d.ts +2 -0
  66. package/dist/commands/login.js +235 -0
  67. package/dist/commands/login.js.map +1 -0
  68. package/dist/commands/logs.d.ts +2 -0
  69. package/dist/commands/logs.js +90 -0
  70. package/dist/commands/logs.js.map +1 -0
  71. package/dist/commands/publish.d.ts +2 -0
  72. package/dist/commands/publish.js +113 -0
  73. package/dist/commands/publish.js.map +1 -0
  74. package/dist/commands/run.d.ts +14 -0
  75. package/dist/commands/run.js +196 -0
  76. package/dist/commands/run.js.map +1 -0
  77. package/dist/commands/settings.d.ts +3 -0
  78. package/dist/commands/settings.js +278 -0
  79. package/dist/commands/settings.js.map +1 -0
  80. package/dist/commands/status.d.ts +2 -0
  81. package/dist/commands/status.js +88 -0
  82. package/dist/commands/status.js.map +1 -0
  83. package/dist/commands/versions.d.ts +2 -0
  84. package/dist/commands/versions.js +242 -0
  85. package/dist/commands/versions.js.map +1 -0
  86. package/dist/credentials/config.d.ts +12 -0
  87. package/dist/credentials/config.js +196 -0
  88. package/dist/credentials/config.js.map +1 -0
  89. package/dist/credentials/encryption.d.ts +9 -0
  90. package/dist/credentials/encryption.js +100 -0
  91. package/dist/credentials/encryption.js.map +1 -0
  92. package/dist/credentials/keychain.d.ts +8 -0
  93. package/dist/credentials/keychain.js +236 -0
  94. package/dist/credentials/keychain.js.map +1 -0
  95. package/dist/credentials/railway.d.ts +9 -0
  96. package/dist/credentials/railway.js +69 -0
  97. package/dist/credentials/railway.js.map +1 -0
  98. package/dist/llm/client.d.ts +59 -0
  99. package/dist/llm/client.js +530 -0
  100. package/dist/llm/client.js.map +1 -0
  101. package/dist/llm/operations.d.ts +39 -0
  102. package/dist/llm/operations.js +131 -0
  103. package/dist/llm/operations.js.map +1 -0
  104. package/dist/llm/rate-limiter.d.ts +20 -0
  105. package/dist/llm/rate-limiter.js +57 -0
  106. package/dist/llm/rate-limiter.js.map +1 -0
  107. package/dist/llm/scaffolding.d.ts +51 -0
  108. package/dist/llm/scaffolding.js +118 -0
  109. package/dist/llm/scaffolding.js.map +1 -0
  110. package/dist/manifest/drift.d.ts +6 -0
  111. package/dist/manifest/drift.js +45 -0
  112. package/dist/manifest/drift.js.map +1 -0
  113. package/dist/manifest/reader.d.ts +12 -0
  114. package/dist/manifest/reader.js +99 -0
  115. package/dist/manifest/reader.js.map +1 -0
  116. package/dist/manifest/types.d.ts +31 -0
  117. package/dist/manifest/types.js +2 -0
  118. package/dist/manifest/types.js.map +1 -0
  119. package/dist/manifest/writer.d.ts +9 -0
  120. package/dist/manifest/writer.js +142 -0
  121. package/dist/manifest/writer.js.map +1 -0
  122. package/dist/mcp/client.d.ts +21 -0
  123. package/dist/mcp/client.js +213 -0
  124. package/dist/mcp/client.js.map +1 -0
  125. package/dist/mcp/lifecycle.d.ts +12 -0
  126. package/dist/mcp/lifecycle.js +149 -0
  127. package/dist/mcp/lifecycle.js.map +1 -0
  128. package/dist/mcp/project-guard.d.ts +14 -0
  129. package/dist/mcp/project-guard.js +27 -0
  130. package/dist/mcp/project-guard.js.map +1 -0
  131. package/dist/prompts/operations.d.ts +1 -0
  132. package/dist/prompts/operations.js +160 -0
  133. package/dist/prompts/operations.js.map +1 -0
  134. package/dist/prompts/scaffolding.d.ts +1 -0
  135. package/dist/prompts/scaffolding.js +331 -0
  136. package/dist/prompts/scaffolding.js.map +1 -0
  137. package/dist/prompts/version.d.ts +2 -0
  138. package/dist/prompts/version.js +3 -0
  139. package/dist/prompts/version.js.map +1 -0
  140. package/dist/sandbox/command-allowlist.d.ts +6 -0
  141. package/dist/sandbox/command-allowlist.js +103 -0
  142. package/dist/sandbox/command-allowlist.js.map +1 -0
  143. package/dist/sandbox/package-allowlist.d.ts +6 -0
  144. package/dist/sandbox/package-allowlist.js +49 -0
  145. package/dist/sandbox/package-allowlist.js.map +1 -0
  146. package/dist/sandbox/scanner.d.ts +25 -0
  147. package/dist/sandbox/scanner.js +196 -0
  148. package/dist/sandbox/scanner.js.map +1 -0
  149. package/dist/sandbox/staging.d.ts +12 -0
  150. package/dist/sandbox/staging.js +107 -0
  151. package/dist/sandbox/staging.js.map +1 -0
  152. package/dist/scaffold/frameworks/express.d.ts +3 -0
  153. package/dist/scaffold/frameworks/express.js +242 -0
  154. package/dist/scaffold/frameworks/express.js.map +1 -0
  155. package/dist/scaffold/frameworks/hono.d.ts +3 -0
  156. package/dist/scaffold/frameworks/hono.js +238 -0
  157. package/dist/scaffold/frameworks/hono.js.map +1 -0
  158. package/dist/scaffold/frameworks/nextjs.d.ts +3 -0
  159. package/dist/scaffold/frameworks/nextjs.js +447 -0
  160. package/dist/scaffold/frameworks/nextjs.js.map +1 -0
  161. package/dist/scaffold/frameworks/tanstack-start.d.ts +3 -0
  162. package/dist/scaffold/frameworks/tanstack-start.js +280 -0
  163. package/dist/scaffold/frameworks/tanstack-start.js.map +1 -0
  164. package/dist/scaffold/index.d.ts +4 -0
  165. package/dist/scaffold/index.js +138 -0
  166. package/dist/scaffold/index.js.map +1 -0
  167. package/dist/scaffold/integrations/backend.d.ts +3 -0
  168. package/dist/scaffold/integrations/backend.js +403 -0
  169. package/dist/scaffold/integrations/backend.js.map +1 -0
  170. package/dist/scaffold/integrations/posthog.d.ts +2 -0
  171. package/dist/scaffold/integrations/posthog.js +21 -0
  172. package/dist/scaffold/integrations/posthog.js.map +1 -0
  173. package/dist/scaffold/integrations/sentry.d.ts +2 -0
  174. package/dist/scaffold/integrations/sentry.js +16 -0
  175. package/dist/scaffold/integrations/sentry.js.map +1 -0
  176. package/dist/scaffold/integrations/storybook.d.ts +2 -0
  177. package/dist/scaffold/integrations/storybook.js +79 -0
  178. package/dist/scaffold/integrations/storybook.js.map +1 -0
  179. package/dist/scaffold/integrations/vitest.d.ts +2 -0
  180. package/dist/scaffold/integrations/vitest.js +37 -0
  181. package/dist/scaffold/integrations/vitest.js.map +1 -0
  182. package/dist/scaffold/package-builder.d.ts +3 -0
  183. package/dist/scaffold/package-builder.js +136 -0
  184. package/dist/scaffold/package-builder.js.map +1 -0
  185. package/dist/scaffold/packages.d.ts +4 -0
  186. package/dist/scaffold/packages.js +144 -0
  187. package/dist/scaffold/packages.js.map +1 -0
  188. package/dist/scaffold/types.d.ts +20 -0
  189. package/dist/scaffold/types.js +2 -0
  190. package/dist/scaffold/types.js.map +1 -0
  191. package/dist/types.d.ts +11 -0
  192. package/dist/types.js +2 -0
  193. package/dist/types.js.map +1 -0
  194. package/dist/utils/auth-guard.d.ts +5 -0
  195. package/dist/utils/auth-guard.js +52 -0
  196. package/dist/utils/auth-guard.js.map +1 -0
  197. package/dist/utils/cleanup.d.ts +2 -0
  198. package/dist/utils/cleanup.js +37 -0
  199. package/dist/utils/cleanup.js.map +1 -0
  200. package/dist/utils/constraints.d.ts +11 -0
  201. package/dist/utils/constraints.js +162 -0
  202. package/dist/utils/constraints.js.map +1 -0
  203. package/dist/utils/display.d.ts +32 -0
  204. package/dist/utils/display.js +103 -0
  205. package/dist/utils/display.js.map +1 -0
  206. package/dist/utils/global-config.d.ts +8 -0
  207. package/dist/utils/global-config.js +39 -0
  208. package/dist/utils/global-config.js.map +1 -0
  209. package/dist/utils/pm.d.ts +4 -0
  210. package/dist/utils/pm.js +40 -0
  211. package/dist/utils/pm.js.map +1 -0
  212. package/dist/utils/prerequisites.d.ts +9 -0
  213. package/dist/utils/prerequisites.js +96 -0
  214. package/dist/utils/prerequisites.js.map +1 -0
  215. package/dist/utils/prompts.d.ts +25 -0
  216. package/dist/utils/prompts.js +148 -0
  217. package/dist/utils/prompts.js.map +1 -0
  218. package/dist/utils/validation.d.ts +9 -0
  219. package/dist/utils/validation.js +38 -0
  220. package/dist/utils/validation.js.map +1 -0
  221. package/dist/versions/compat.d.ts +13 -0
  222. package/dist/versions/compat.js +127 -0
  223. package/dist/versions/compat.js.map +1 -0
  224. package/dist/versions/integrity.d.ts +9 -0
  225. package/dist/versions/integrity.js +60 -0
  226. package/dist/versions/integrity.js.map +1 -0
  227. package/dist/versions/parser.d.ts +13 -0
  228. package/dist/versions/parser.js +106 -0
  229. package/dist/versions/parser.js.map +1 -0
  230. package/dist/versions/registry.d.ts +30 -0
  231. package/dist/versions/registry.js +165 -0
  232. package/dist/versions/registry.js.map +1 -0
  233. package/package.json +58 -0
  234. 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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAE,OAAO,EAAc,MAAM,UAAU,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,QAAQ,GAAG,OAAO,CAAC;AACzB,MAAM,WAAW,GAAG,SAAS,CAAC;AAkC9B,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAe,EAAE,UAAkB;IAC/D,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,oBAAoB,CAAC,YAAoB;IAChD,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,mCAAmC,YAAY,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,kCAAkC,YAAY,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,sBAAsB,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE5D,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6CAA6C,YAAY,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,KAAK,YAAY,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;QAC1B,eAAe,EAAE;YACf,YAAY,EAAE,IAAI;SACnB;QACD,2BAA2B,EAAE,IAAI;KAClC,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAEpD,SAAS,cAAc,CAAC,YAAoB;QAC1C,oBAAoB,CAAC,YAAY,CAAC,CAAC;QAEnC,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACrD,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,OAAO,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,SAAS,cAAc,CAAC,YAAoB,EAAE,UAAsB;QAClE,oBAAoB,CAAC,YAAY,CAAC,CAAC;QAEnC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;QAC5E,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,KAAK,CAAC,gDAAgD,YAAY,EAAE,CAAC,CAAC;QAClF,CAAC;QAED,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAErD,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QAC1C,aAAa,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE9C,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACjD,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1F,CAAC;IAED,SAAS,eAAe,CACtB,UAA0B,EAC1B,gBAA2E;QAE3E,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,MAAM,MAAM,GAAe,EAAE,CAAC;QAE9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,UAAsB,CAAC;YAE3B,IAAI,CAAC;gBACH,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC;oBACV,QAAQ,EAAE,SAAS,CAAC,IAAI;oBACxB,SAAS,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE;oBACnC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBAChE,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;YACtC,KAAK,MAAM,SAAS,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;gBAC7C,IAAI,CAAC;oBACH,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;gBAC1C,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC;wBACV,QAAQ,EAAE,SAAS,CAAC,IAAI;wBACxB,SAAS;wBACT,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;qBAChE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;gBACpC,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC3C,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC;oBACV,QAAQ,EAAE,SAAS,CAAC,IAAI;oBACxB,SAAS,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE;oBACnC,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;iBAChE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;YAC5B,aAAa;YACb,MAAM;SACP,CAAC;IACJ,CAAC;IAED,SAAS,UAAU;QACjB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,cAAc;QACd,cAAc;QACd,eAAe;QACf,UAAU;KACX,CAAC;AACJ,CAAC"}
@@ -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;