openkitt 0.2.6 → 0.2.7

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 (2) hide show
  1. package/dist/cli.js +914 -895
  2. package/package.json +1 -2
package/dist/cli.js CHANGED
@@ -2192,8 +2192,66 @@ var require_picocolors = __commonJS((exports, module) => {
2192
2192
  module.exports.createColors = createColors;
2193
2193
  });
2194
2194
 
2195
+ // node_modules/sisteransi/src/index.js
2196
+ var require_src = __commonJS((exports, module) => {
2197
+ var ESC = "\x1B";
2198
+ var CSI = `${ESC}[`;
2199
+ var beep = "\x07";
2200
+ var cursor = {
2201
+ to(x, y) {
2202
+ if (!y)
2203
+ return `${CSI}${x + 1}G`;
2204
+ return `${CSI}${y + 1};${x + 1}H`;
2205
+ },
2206
+ move(x, y) {
2207
+ let ret = "";
2208
+ if (x < 0)
2209
+ ret += `${CSI}${-x}D`;
2210
+ else if (x > 0)
2211
+ ret += `${CSI}${x}C`;
2212
+ if (y < 0)
2213
+ ret += `${CSI}${-y}A`;
2214
+ else if (y > 0)
2215
+ ret += `${CSI}${y}B`;
2216
+ return ret;
2217
+ },
2218
+ up: (count = 1) => `${CSI}${count}A`,
2219
+ down: (count = 1) => `${CSI}${count}B`,
2220
+ forward: (count = 1) => `${CSI}${count}C`,
2221
+ backward: (count = 1) => `${CSI}${count}D`,
2222
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
2223
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
2224
+ left: `${CSI}G`,
2225
+ hide: `${CSI}?25l`,
2226
+ show: `${CSI}?25h`,
2227
+ save: `${ESC}7`,
2228
+ restore: `${ESC}8`
2229
+ };
2230
+ var scroll = {
2231
+ up: (count = 1) => `${CSI}S`.repeat(count),
2232
+ down: (count = 1) => `${CSI}T`.repeat(count)
2233
+ };
2234
+ var erase = {
2235
+ screen: `${CSI}2J`,
2236
+ up: (count = 1) => `${CSI}1J`.repeat(count),
2237
+ down: (count = 1) => `${CSI}J`.repeat(count),
2238
+ line: `${CSI}2K`,
2239
+ lineEnd: `${CSI}K`,
2240
+ lineStart: `${CSI}1K`,
2241
+ lines(count) {
2242
+ let clear = "";
2243
+ for (let i = 0;i < count; i++)
2244
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
2245
+ if (count)
2246
+ clear += cursor.left;
2247
+ return clear;
2248
+ }
2249
+ };
2250
+ module.exports = { cursor, scroll, erase, beep };
2251
+ });
2252
+
2195
2253
  // src/credentials/encryption.ts
2196
- import { execSync } from "node:child_process";
2254
+ import { execSync as execSync2 } from "node:child_process";
2197
2255
  import {
2198
2256
  createCipheriv,
2199
2257
  createDecipheriv,
@@ -2209,7 +2267,7 @@ function getMachineId() {
2209
2267
  const currentPlatform = platform();
2210
2268
  if (currentPlatform === "darwin") {
2211
2269
  try {
2212
- const output = execSync("ioreg -rd1 -c IOPlatformExpertDevice", {
2270
+ const output = execSync2("ioreg -rd1 -c IOPlatformExpertDevice", {
2213
2271
  encoding: "utf-8",
2214
2272
  stdio: "pipe"
2215
2273
  });
@@ -2231,7 +2289,7 @@ function getMachineId() {
2231
2289
  }
2232
2290
  if (currentPlatform === "win32") {
2233
2291
  try {
2234
- const output = execSync('reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid', {
2292
+ const output = execSync2('reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid', {
2235
2293
  encoding: "utf-8",
2236
2294
  stdio: "pipe"
2237
2295
  });
@@ -2298,17 +2356,17 @@ function isNotFoundError(errorMessage) {
2298
2356
  const normalized = errorMessage.toLowerCase();
2299
2357
  return normalized.includes("could not be found") || normalized.includes("item not found") || normalized.includes("not found") || normalized.includes("element not found");
2300
2358
  }
2301
- function getErrorMessage(error) {
2302
- if (error instanceof Error) {
2303
- const maybeStderr = error.stderr;
2359
+ function getErrorMessage(error2) {
2360
+ if (error2 instanceof Error) {
2361
+ const maybeStderr = error2.stderr;
2304
2362
  if (typeof maybeStderr === "string" && maybeStderr.trim().length > 0) {
2305
2363
  return maybeStderr.trim();
2306
2364
  }
2307
2365
  if (Buffer.isBuffer(maybeStderr) && maybeStderr.length > 0) {
2308
2366
  return maybeStderr.toString("utf-8").trim();
2309
2367
  }
2310
- if (error.message.trim().length > 0) {
2311
- return error.message.trim();
2368
+ if (error2.message.trim().length > 0) {
2369
+ return error2.message.trim();
2312
2370
  }
2313
2371
  }
2314
2372
  return "Unknown keychain error";
@@ -2450,8 +2508,8 @@ async function setKeychainValue(key, value) {
2450
2508
  default:
2451
2509
  return { success: false, error: "Unsupported platform" };
2452
2510
  }
2453
- } catch (error) {
2454
- return { success: false, error: getErrorMessage(error) };
2511
+ } catch (error2) {
2512
+ return { success: false, error: getErrorMessage(error2) };
2455
2513
  }
2456
2514
  }
2457
2515
  async function getKeychainValue(key) {
@@ -2476,8 +2534,8 @@ async function getKeychainValue(key) {
2476
2534
  default:
2477
2535
  return null;
2478
2536
  }
2479
- } catch (error) {
2480
- const errorMessage = getErrorMessage(error);
2537
+ } catch (error2) {
2538
+ const errorMessage = getErrorMessage(error2);
2481
2539
  if (isNotFoundError(errorMessage)) {
2482
2540
  return null;
2483
2541
  }
@@ -2509,8 +2567,8 @@ async function deleteKeychainValue(key) {
2509
2567
  default:
2510
2568
  return { success: false, error: "Unsupported platform" };
2511
2569
  }
2512
- } catch (error) {
2513
- const errorMessage = getErrorMessage(error);
2570
+ } catch (error2) {
2571
+ const errorMessage = getErrorMessage(error2);
2514
2572
  if (isNotFoundError(errorMessage)) {
2515
2573
  return { success: true };
2516
2574
  }
@@ -2530,9 +2588,9 @@ __export(exports_config, {
2530
2588
  getLlmApiKey: () => getLlmApiKey,
2531
2589
  clearLlmCredentials: () => clearLlmCredentials
2532
2590
  });
2533
- import { chmodSync, existsSync, mkdirSync, readFileSync as readFileSync2, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
2591
+ import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, statSync as statSync2, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
2534
2592
  import { homedir, platform as platform2 } from "node:os";
2535
- import { join } from "node:path";
2593
+ import { join as join3 } from "node:path";
2536
2594
  function isWindows() {
2537
2595
  return platform2() === "win32";
2538
2596
  }
@@ -2541,18 +2599,18 @@ function hasExtraPermissionBits(actualMode, allowedMode) {
2541
2599
  return (activeBits & ~allowedMode) !== 0;
2542
2600
  }
2543
2601
  function ensurePermissions(path, mode) {
2544
- if (isWindows() || !existsSync(path)) {
2602
+ if (isWindows() || !existsSync3(path)) {
2545
2603
  return;
2546
2604
  }
2547
- const currentMode = statSync(path).mode;
2605
+ const currentMode = statSync2(path).mode;
2548
2606
  if (hasExtraPermissionBits(currentMode, mode)) {
2549
2607
  console.warn(`[kitt] Detected permissive config permissions for ${path}. Auto-fixing.`);
2550
2608
  chmodSync(path, mode);
2551
2609
  }
2552
2610
  }
2553
2611
  function ensureConfigDir() {
2554
- if (!existsSync(CONFIG_DIR)) {
2555
- mkdirSync(CONFIG_DIR, { recursive: true, mode: DIR_MODE });
2612
+ if (!existsSync3(CONFIG_DIR)) {
2613
+ mkdirSync2(CONFIG_DIR, { recursive: true, mode: DIR_MODE });
2556
2614
  }
2557
2615
  if (!isWindows()) {
2558
2616
  ensurePermissions(CONFIG_DIR, DIR_MODE);
@@ -2560,7 +2618,7 @@ function ensureConfigDir() {
2560
2618
  }
2561
2619
  function readConfig() {
2562
2620
  ensureConfigDir();
2563
- if (!existsSync(CONFIG_FILE)) {
2621
+ if (!existsSync3(CONFIG_FILE)) {
2564
2622
  return {};
2565
2623
  }
2566
2624
  if (!isWindows()) {
@@ -2582,19 +2640,19 @@ function writeConfig(config) {
2582
2640
  const payload = `${JSON.stringify(config, null, 2)}
2583
2641
  `;
2584
2642
  try {
2585
- writeFileSync(tempFile, payload, { encoding: "utf-8", mode: FILE_MODE });
2643
+ writeFileSync2(tempFile, payload, { encoding: "utf-8", mode: FILE_MODE });
2586
2644
  if (!isWindows()) {
2587
2645
  chmodSync(tempFile, FILE_MODE);
2588
2646
  }
2589
- renameSync(tempFile, CONFIG_FILE);
2647
+ renameSync2(tempFile, CONFIG_FILE);
2590
2648
  if (!isWindows()) {
2591
2649
  chmodSync(CONFIG_FILE, FILE_MODE);
2592
2650
  }
2593
- } catch (error) {
2594
- if (existsSync(tempFile)) {
2651
+ } catch (error2) {
2652
+ if (existsSync3(tempFile)) {
2595
2653
  unlinkSync(tempFile);
2596
2654
  }
2597
- throw error;
2655
+ throw error2;
2598
2656
  }
2599
2657
  }
2600
2658
  function isStoredProvider(value) {
@@ -2718,66 +2776,8 @@ var CONFIG_DIR, CONFIG_FILE, KEYCHAIN_API_KEY = "llm-api-key", DIR_MODE = 448, F
2718
2776
  var init_config = __esm(() => {
2719
2777
  init_encryption();
2720
2778
  init_keychain();
2721
- CONFIG_DIR = join(homedir(), ".kitt");
2722
- CONFIG_FILE = join(CONFIG_DIR, "config.json");
2723
- });
2724
-
2725
- // node_modules/sisteransi/src/index.js
2726
- var require_src = __commonJS((exports, module) => {
2727
- var ESC = "\x1B";
2728
- var CSI = `${ESC}[`;
2729
- var beep = "\x07";
2730
- var cursor = {
2731
- to(x, y) {
2732
- if (!y)
2733
- return `${CSI}${x + 1}G`;
2734
- return `${CSI}${y + 1};${x + 1}H`;
2735
- },
2736
- move(x, y) {
2737
- let ret = "";
2738
- if (x < 0)
2739
- ret += `${CSI}${-x}D`;
2740
- else if (x > 0)
2741
- ret += `${CSI}${x}C`;
2742
- if (y < 0)
2743
- ret += `${CSI}${-y}A`;
2744
- else if (y > 0)
2745
- ret += `${CSI}${y}B`;
2746
- return ret;
2747
- },
2748
- up: (count = 1) => `${CSI}${count}A`,
2749
- down: (count = 1) => `${CSI}${count}B`,
2750
- forward: (count = 1) => `${CSI}${count}C`,
2751
- backward: (count = 1) => `${CSI}${count}D`,
2752
- nextLine: (count = 1) => `${CSI}E`.repeat(count),
2753
- prevLine: (count = 1) => `${CSI}F`.repeat(count),
2754
- left: `${CSI}G`,
2755
- hide: `${CSI}?25l`,
2756
- show: `${CSI}?25h`,
2757
- save: `${ESC}7`,
2758
- restore: `${ESC}8`
2759
- };
2760
- var scroll = {
2761
- up: (count = 1) => `${CSI}S`.repeat(count),
2762
- down: (count = 1) => `${CSI}T`.repeat(count)
2763
- };
2764
- var erase = {
2765
- screen: `${CSI}2J`,
2766
- up: (count = 1) => `${CSI}1J`.repeat(count),
2767
- down: (count = 1) => `${CSI}J`.repeat(count),
2768
- line: `${CSI}2K`,
2769
- lineEnd: `${CSI}K`,
2770
- lineStart: `${CSI}1K`,
2771
- lines(count) {
2772
- let clear = "";
2773
- for (let i = 0;i < count; i++)
2774
- clear += this.line + (i < count - 1 ? cursor.up() : "");
2775
- if (count)
2776
- clear += cursor.left;
2777
- return clear;
2778
- }
2779
- };
2780
- module.exports = { cursor, scroll, erase, beep };
2779
+ CONFIG_DIR = join3(homedir(), ".kitt");
2780
+ CONFIG_FILE = join3(CONFIG_DIR, "config.json");
2781
2781
  });
2782
2782
 
2783
2783
  // node_modules/@anthropic-ai/sdk/internal/tslib.mjs
@@ -185957,7 +185957,7 @@ var require_path_browserify = __commonJS((exports, module) => {
185957
185957
  _makeLong: function _makeLong(path3) {
185958
185958
  return path3;
185959
185959
  },
185960
- dirname: function dirname5(path3) {
185960
+ dirname: function dirname4(path3) {
185961
185961
  assertPath(path3);
185962
185962
  if (path3.length === 0)
185963
185963
  return ".";
@@ -255595,497 +255595,118 @@ var {
255595
255595
  var import_picocolors12 = __toESM(require_picocolors(), 1);
255596
255596
  import { createInterface, emitKeypressEvents } from "node:readline";
255597
255597
  import { stdin as input, stdout as output } from "node:process";
255598
- import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync15, realpathSync } from "node:fs";
255598
+ import { existsSync as existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync15, realpathSync } from "node:fs";
255599
255599
  import { homedir as homedir4 } from "node:os";
255600
- import { join as join23, resolve as resolve6, dirname as dirname6 } from "node:path";
255600
+ import { join as join23, resolve as resolve6, dirname as dirname5 } from "node:path";
255601
255601
  import { pathToFileURL } from "node:url";
255602
255602
 
255603
255603
  // src/utils/prerequisites.ts
255604
- var import_picocolors = __toESM(require_picocolors(), 1);
255605
- import { execSync as execSync2 } from "node:child_process";
255606
- function getNodeVersion() {
255607
- try {
255608
- const output = execSync2("node --version", {
255609
- encoding: "utf-8",
255610
- stdio: "pipe"
255611
- }).trim();
255612
- return output.replace(/^v/, "");
255613
- } catch {
255614
- return "";
255615
- }
255616
- }
255617
- function getBunVersion() {
255618
- try {
255619
- const output = execSync2("bun --version", {
255620
- encoding: "utf-8",
255621
- stdio: "pipe"
255622
- }).trim();
255623
- return output;
255624
- } catch {
255625
- return null;
255626
- }
255627
- }
255628
- function getRailwayVersion() {
255629
- try {
255630
- const output = execSync2("railway --version", {
255631
- encoding: "utf-8",
255632
- stdio: "pipe"
255633
- }).trim();
255634
- return output || null;
255635
- } catch {
255636
- return null;
255637
- }
255638
- }
255639
- async function checkPrerequisites() {
255640
- const nodeVersion = getNodeVersion();
255641
- const bunVersion = getBunVersion();
255642
- const railwayVersion = getRailwayVersion();
255643
- return [
255644
- {
255645
- name: "Node.js",
255646
- found: !!nodeVersion,
255647
- version: nodeVersion || undefined
255648
- },
255649
- {
255650
- name: "Bun",
255651
- found: !!bunVersion,
255652
- version: bunVersion || undefined,
255653
- installUrl: bunVersion ? undefined : "https://bun.sh"
255654
- },
255655
- {
255656
- name: "Railway CLI",
255657
- found: !!railwayVersion,
255658
- version: railwayVersion || undefined,
255659
- installUrl: railwayVersion ? undefined : "https://docs.railway.com/cli"
255660
- }
255661
- ];
255662
- }
255663
- function displayPrerequisites(statuses) {
255664
- for (const status of statuses) {
255665
- if (status.found) {
255666
- const version = status.version ? `v${status.version}` : "";
255667
- const paddedName = status.name.padEnd(12);
255668
- console.log(` ${import_picocolors.default.green("✓")} ${paddedName} ${version}`);
255669
- } else {
255670
- const paddedName = status.name.padEnd(12);
255671
- const installMsg = status.installUrl ? `not found. Install: ${status.installUrl}` : "not found";
255672
- console.log(` ${import_picocolors.default.red("✗")} ${paddedName} ${installMsg}`);
255673
- }
255674
- }
255675
- }
255676
- async function displayLlmStatus() {
255677
- const paddedName = "LLM".padEnd(12);
255678
- try {
255679
- const { isLlmConfigured: isLlmConfigured2, getLlmConfig: getLlmConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
255680
- const [configured, config] = await Promise.all([isLlmConfigured2(), getLlmConfig2()]);
255681
- if (configured && config) {
255682
- const label = `${config.provider[0].toUpperCase()}${config.provider.slice(1)} (${config.model})`;
255683
- console.log(` ${import_picocolors.default.green("✓")} ${paddedName} ${label}`);
255684
- } else {
255685
- console.log(` ${import_picocolors.default.yellow("!")} ${paddedName} not configured`);
255686
- }
255687
- } catch {
255688
- console.log(` ${import_picocolors.default.yellow("!")} ${paddedName} not configured`);
255689
- }
255690
- }
255691
-
255692
- // src/manifest/reader.ts
255693
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
255694
- import { join as join4, dirname as dirname2, resolve } from "node:path";
255604
+ import { execSync as execSync3 } from "node:child_process";
255695
255605
 
255696
- // src/utils/global-config.ts
255697
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
255698
- import { homedir as homedir2 } from "node:os";
255606
+ // src/mcp/lifecycle.ts
255607
+ import { spawn, execSync } from "node:child_process";
255608
+ import { existsSync as existsSync2 } from "node:fs";
255699
255609
  import { join as join2 } from "node:path";
255700
- function getGlobalConfigPath() {
255701
- return join2(homedir2(), ".kitt", "workspace.json");
255702
- }
255703
- function readGlobalConfig() {
255704
- const configPath = getGlobalConfigPath();
255705
- if (!existsSync2(configPath)) {
255706
- return {};
255707
- }
255708
- try {
255709
- const raw = readFileSync3(configPath, "utf-8").trim();
255710
- if (!raw)
255711
- return {};
255712
- const parsed = JSON.parse(raw);
255713
- if (typeof parsed === "object" && parsed !== null) {
255714
- return parsed;
255715
- }
255716
- return {};
255717
- } catch {
255718
- return {};
255719
- }
255720
- }
255721
- function writeGlobalConfig(config) {
255722
- const configPath = getGlobalConfigPath();
255723
- const configDir = join2(homedir2(), ".kitt");
255724
- mkdirSync2(configDir, { recursive: true });
255725
- writeFileSync2(configPath, JSON.stringify(config, null, 2) + `
255726
- `, "utf-8");
255727
- }
255728
- function setGlobalWorkspacePath(workspacePath) {
255729
- const existing = readGlobalConfig();
255730
- writeGlobalConfig({ ...existing, workspacePath });
255731
- }
255732
- function getGlobalWorkspacePath() {
255733
- return readGlobalConfig().workspacePath ?? null;
255734
- }
255735
255610
 
255736
- // src/manifest/writer.ts
255737
- import { chmodSync as chmodSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
255738
- import { platform as platform3 } from "node:os";
255739
- import { dirname, join as join3 } from "node:path";
255740
- var DIR_MODE2 = 448;
255741
- var FILE_MODE2 = 384;
255742
- var MANIFEST_VERSION = "0.1.0";
255743
- function isWindows2() {
255744
- return platform3() === "win32";
255745
- }
255746
- function ensureKittDir(manifestPath) {
255747
- const kittDir = dirname(manifestPath);
255748
- if (!existsSync3(kittDir)) {
255749
- mkdirSync3(kittDir, { recursive: true, mode: DIR_MODE2 });
255750
- }
255751
- if (!isWindows2()) {
255752
- chmodSync2(kittDir, DIR_MODE2);
255753
- }
255754
- }
255755
- function writeManifest(workspaceDir, manifest) {
255756
- const manifestPath = getManifestPath(workspaceDir);
255757
- const manifestDir = dirname(manifestPath);
255758
- const tempFile = join3(manifestDir, `manifest.json.tmp-${process.pid}-${Date.now()}`);
255759
- const payload = `${JSON.stringify(manifest, null, 2)}
255611
+ // src/audit/logger.ts
255612
+ import {
255613
+ appendFileSync,
255614
+ existsSync,
255615
+ mkdirSync,
255616
+ renameSync,
255617
+ rmSync,
255618
+ statSync,
255619
+ writeFileSync
255620
+ } from "node:fs";
255621
+ import { join } from "node:path";
255622
+ var AUDIT_DIR_NAME = ".kitt";
255623
+ var AUDIT_FILE_NAME = "audit.log";
255624
+ var ROTATED_LOG_1 = "audit.log.1";
255625
+ var ROTATED_LOG_2 = "audit.log.2";
255626
+ var MAX_LOG_SIZE_BYTES = 10 * 1024 * 1024;
255627
+ function formatLine(type, message) {
255628
+ return `[${new Date().toISOString()}] ${type} ${message}
255760
255629
  `;
255761
- ensureKittDir(manifestPath);
255762
- try {
255763
- writeFileSync3(tempFile, payload, { encoding: "utf-8", mode: FILE_MODE2 });
255764
- if (!isWindows2()) {
255765
- chmodSync2(tempFile, FILE_MODE2);
255766
- }
255767
- renameSync2(tempFile, manifestPath);
255768
- if (!isWindows2()) {
255769
- chmodSync2(manifestPath, FILE_MODE2);
255770
- }
255771
- } catch (error) {
255772
- if (existsSync3(tempFile)) {
255773
- unlinkSync2(tempFile);
255774
- }
255775
- throw error;
255776
- }
255777
- }
255778
- function createInitialManifest(workspaceName, packageManager, railway) {
255779
- return {
255780
- version: MANIFEST_VERSION,
255781
- workspace: {
255782
- name: workspaceName,
255783
- packageManager,
255784
- ...railway ? { railway } : {}
255785
- },
255786
- settings: {},
255787
- apps: {},
255788
- packages: {}
255789
- };
255790
255630
  }
255791
- function addApp(manifest, name, app) {
255792
- return {
255793
- ...manifest,
255794
- apps: {
255795
- ...manifest.apps,
255796
- [name]: app
255797
- }
255798
- };
255799
- }
255800
- function removeApp(manifest, name) {
255801
- const nextApps = { ...manifest.apps };
255802
- delete nextApps[name];
255803
- const nextPackages = {};
255804
- for (const [packageName, pkg] of Object.entries(manifest.packages)) {
255805
- nextPackages[packageName] = {
255806
- ...pkg,
255807
- consumers: pkg.consumers.filter((consumer) => consumer !== name)
255808
- };
255809
- }
255810
- return {
255811
- ...manifest,
255812
- apps: nextApps,
255813
- packages: nextPackages
255814
- };
255815
- }
255816
- function addPackage(manifest, name, pkg) {
255817
- return {
255818
- ...manifest,
255819
- packages: {
255820
- ...manifest.packages,
255821
- [name]: pkg
255822
- }
255823
- };
255824
- }
255825
- function addConsumer(manifest, packageName, appName) {
255826
- const pkg = manifest.packages[packageName];
255827
- if (!pkg) {
255828
- return {
255829
- ...manifest,
255830
- packages: {
255831
- ...manifest.packages
255832
- }
255833
- };
255834
- }
255835
- const consumers = pkg.consumers.includes(appName) ? [...pkg.consumers] : [...pkg.consumers, appName];
255836
- return {
255837
- ...manifest,
255838
- packages: {
255839
- ...manifest.packages,
255840
- [packageName]: {
255841
- ...pkg,
255842
- consumers
255843
- }
255844
- }
255845
- };
255846
- }
255847
-
255848
- // src/manifest/reader.ts
255849
- function isObjectRecord(value) {
255850
- return typeof value === "object" && value !== null;
255851
- }
255852
- function isValidWorkspaceManifest(value) {
255853
- if (!isObjectRecord(value)) {
255854
- return false;
255855
- }
255856
- if (typeof value.version !== "string") {
255857
- return false;
255858
- }
255859
- if (!isObjectRecord(value.workspace)) {
255860
- return false;
255861
- }
255862
- if (typeof value.workspace.name !== "string") {
255863
- return false;
255864
- }
255865
- const packageManager = value.workspace.packageManager;
255866
- if (packageManager !== "bun" && packageManager !== "npm" && packageManager !== "pnpm" && packageManager !== "yarn") {
255867
- return false;
255868
- }
255869
- if (!isObjectRecord(value.apps)) {
255870
- return false;
255871
- }
255872
- if (!isObjectRecord(value.packages)) {
255873
- return false;
255874
- }
255875
- if (!isObjectRecord(value.settings)) {
255876
- return false;
255877
- }
255878
- return true;
255879
- }
255880
- function getManifestPath(workspaceDir) {
255881
- return join4(workspaceDir, ".kitt", "manifest.json");
255882
- }
255883
- function isKittWorkspace(dir) {
255884
- return existsSync4(getManifestPath(dir));
255885
- }
255886
- function findWorkspaceRoot(startDir) {
255887
- let current = resolve(startDir);
255888
- while (true) {
255889
- if (isKittWorkspace(current))
255890
- return current;
255891
- const parent = dirname2(current);
255892
- if (parent === current)
255893
- break;
255894
- current = parent;
255895
- }
255896
- const globalPath = getGlobalWorkspacePath();
255897
- if (globalPath && isKittWorkspace(globalPath))
255898
- return globalPath;
255899
- return null;
255900
- }
255901
- function findWorkspaceRootStrict(startDir) {
255902
- let current = resolve(startDir);
255903
- while (true) {
255904
- if (isKittWorkspace(current))
255905
- return current;
255906
- const parent = dirname2(current);
255907
- if (parent === current)
255908
- break;
255909
- current = parent;
255910
- }
255911
- return null;
255912
- }
255913
- function readManifest(workspaceDir) {
255914
- const manifestPath = getManifestPath(workspaceDir);
255915
- if (!existsSync4(manifestPath)) {
255916
- return null;
255917
- }
255918
- try {
255919
- const raw = readFileSync4(manifestPath, "utf-8").trim();
255920
- if (raw.length === 0) {
255921
- return null;
255922
- }
255923
- const parsed = JSON.parse(raw);
255924
- if (!isValidWorkspaceManifest(parsed)) {
255925
- return null;
255926
- }
255927
- return parsed;
255928
- } catch {
255929
- return null;
255930
- }
255931
- }
255932
- function reconcileManifest(workspaceDir) {
255933
- const manifest = readManifest(workspaceDir);
255934
- if (!manifest)
255935
- return null;
255936
- const staleApps = Object.keys(manifest.apps).filter((name) => !existsSync4(join4(workspaceDir, "apps", name)));
255937
- if (staleApps.length === 0)
255938
- return manifest;
255939
- let cleaned = manifest;
255940
- for (const name of staleApps) {
255941
- cleaned = removeApp(cleaned, name);
255631
+ function ensureAuditDir(auditDir) {
255632
+ if (existsSync(auditDir)) {
255633
+ return;
255942
255634
  }
255943
- writeManifest(workspaceDir, cleaned);
255944
- return cleaned;
255635
+ mkdirSync(auditDir, { recursive: true, mode: 448 });
255945
255636
  }
255946
-
255947
- // src/utils/auth-guard.ts
255948
- init_config();
255949
-
255950
- // src/credentials/railway.ts
255951
- import { execSync as execSync3 } from "node:child_process";
255952
- async function isRailwayInstalled() {
255953
- try {
255954
- execSync3("railway --version", {
255955
- encoding: "utf-8",
255956
- stdio: "pipe"
255957
- });
255958
- return true;
255959
- } catch {
255960
- return false;
255637
+ function rotateLogIfNeeded(logPath, log1Path, log2Path) {
255638
+ if (!existsSync(logPath)) {
255639
+ return;
255961
255640
  }
255962
- }
255963
- async function checkRailwayAuth() {
255964
- const installed = await isRailwayInstalled();
255965
- if (!installed) {
255966
- return {
255967
- authenticated: false,
255968
- error: "Railway CLI not installed"
255969
- };
255641
+ const stats = statSync(logPath);
255642
+ if (stats.size < MAX_LOG_SIZE_BYTES) {
255643
+ return;
255970
255644
  }
255971
- try {
255972
- const output = execSync3("railway whoami", {
255973
- encoding: "utf-8",
255974
- stdio: "pipe"
255975
- }).trim();
255976
- if (output && output.length > 0) {
255977
- return {
255978
- authenticated: true,
255979
- username: output
255980
- };
255981
- }
255982
- return {
255983
- authenticated: false
255984
- };
255985
- } catch {
255986
- return {
255987
- authenticated: false
255988
- };
255645
+ if (existsSync(log2Path)) {
255646
+ rmSync(log2Path, { force: true });
255989
255647
  }
255990
- }
255991
- async function railwayLogin() {
255992
- try {
255993
- execSync3("railway login", {
255994
- stdio: "inherit"
255995
- });
255996
- return await checkRailwayAuth();
255997
- } catch {
255998
- return {
255999
- authenticated: false,
256000
- error: "Failed to complete Railway login"
256001
- };
255648
+ if (existsSync(log1Path)) {
255649
+ renameSync(log1Path, log2Path);
256002
255650
  }
255651
+ renameSync(logPath, log1Path);
255652
+ writeFileSync(logPath, "", { encoding: "utf8", mode: 384 });
256003
255653
  }
256004
- async function railwayLogout() {
255654
+ function writeAuditLine(logPath, log1Path, log2Path, type, message) {
256005
255655
  try {
256006
- execSync3("railway logout", {
256007
- encoding: "utf-8",
256008
- stdio: "pipe"
256009
- });
256010
- return true;
255656
+ rotateLogIfNeeded(logPath, log1Path, log2Path);
255657
+ appendFileSync(logPath, formatLine(type, message), { encoding: "utf8", mode: 384 });
256011
255658
  } catch {
256012
- return false;
255659
+ return;
256013
255660
  }
256014
255661
  }
256015
-
256016
- // src/utils/auth-guard.ts
256017
- var WORKSPACE_REQUIRED = new Set([
256018
- "create",
256019
- "delete",
256020
- "list",
256021
- "run",
256022
- "deploy",
256023
- "deploy:template",
256024
- "env:create",
256025
- "env:vars",
256026
- "domain",
256027
- "logs",
256028
- "status",
256029
- "versions"
256030
- ]);
256031
- var COMMAND_AUTH = {
256032
- login: "none",
256033
- logout: "none",
256034
- help: "none",
256035
- settings: "none",
256036
- list: "none",
256037
- versions: "none",
256038
- exit: "none",
256039
- init: "both",
256040
- create: "both",
256041
- delete: "both",
256042
- deploy: "both",
256043
- "deploy:template": "both",
256044
- "env:create": "both",
256045
- "env:vars": "both",
256046
- domain: "both",
256047
- logs: "both",
256048
- status: "both"
256049
- };
256050
- async function checkAuthGuard(commandKey) {
256051
- if (WORKSPACE_REQUIRED.has(commandKey)) {
256052
- const workspaceRoot = findWorkspaceRootStrict(process.cwd());
256053
- if (!workspaceRoot) {
256054
- return {
256055
- allowed: false,
256056
- message: "No KITT workspace found. Run /init to initialize one."
256057
- };
256058
- }
256059
- }
256060
- const requirement = COMMAND_AUTH[commandKey];
256061
- if (!requirement || requirement === "none") {
256062
- return { allowed: true };
256063
- }
256064
- if (requirement === "llm" || requirement === "both") {
256065
- const llmConfigured = await isLlmConfigured();
256066
- if (!llmConfigured) {
256067
- return {
256068
- allowed: false,
256069
- message: "LLM API key required. Run /login llm to configure."
256070
- };
256071
- }
256072
- }
256073
- if (requirement === "railway" || requirement === "both") {
256074
- const railwayStatus = await checkRailwayAuth();
256075
- if (!railwayStatus.authenticated) {
256076
- return {
256077
- allowed: false,
256078
- message: "Railway authentication required. Run /login railway to authenticate."
256079
- };
255662
+ function createAuditLogger(workspaceDir) {
255663
+ const auditDir = join(workspaceDir, AUDIT_DIR_NAME);
255664
+ const logPath = join(auditDir, AUDIT_FILE_NAME);
255665
+ const log1Path = join(auditDir, ROTATED_LOG_1);
255666
+ const log2Path = join(auditDir, ROTATED_LOG_2);
255667
+ return {
255668
+ log(type, message) {
255669
+ try {
255670
+ ensureAuditDir(auditDir);
255671
+ } catch {
255672
+ return;
255673
+ }
255674
+ writeAuditLine(logPath, log1Path, log2Path, type, message);
255675
+ },
255676
+ cmd(command, status, detail) {
255677
+ const suffix = detail ? ` (${detail})` : "";
255678
+ this.log("CMD", `${command} ${status}${suffix}`);
255679
+ },
255680
+ cmdExec(command, status) {
255681
+ this.log("CMD_EXEC", `${command} → ${status}`);
255682
+ },
255683
+ mcp(tool, params, status, detail) {
255684
+ const suffix = detail ? ` (${detail})` : "";
255685
+ this.log("MCP", `${tool} (${params}) → ${status}${suffix}`);
255686
+ },
255687
+ llmCall(provider, model, promptVersion, estimatedTokens, status) {
255688
+ this.log("LLM_CALL", `${provider}/${model} (prompt: ${promptVersion}, est. ${estimatedTokens} tokens) → ${status}`);
255689
+ },
255690
+ fileWrite(path, hash) {
255691
+ const suffix = hash ? ` (SHA-256: ${hash})` : "";
255692
+ this.log("FILE_WRITE", `${path}${suffix}`);
255693
+ },
255694
+ staged(path, detail) {
255695
+ this.log("STAGED", `${path} (${detail})`);
255696
+ },
255697
+ userConfirmed() {
255698
+ this.log("USER_CONFIRMED", "staged changes");
255699
+ },
255700
+ security(action, message) {
255701
+ this.log("SECURITY", `${action} ${message}`);
256080
255702
  }
256081
- }
256082
- return { allowed: true };
255703
+ };
256083
255704
  }
256084
255705
 
256085
255706
  // node_modules/@clack/core/dist/index.mjs
256086
255707
  var import_sisteransi = __toESM(require_src(), 1);
256087
255708
  import { stdin as j, stdout as M } from "node:process";
256088
- var import_picocolors2 = __toESM(require_picocolors(), 1);
255709
+ var import_picocolors = __toESM(require_picocolors(), 1);
256089
255710
  import O from "node:readline";
256090
255711
  import { Writable as X } from "node:stream";
256091
255712
  function DD({ onlyFirst: e = false } = {}) {
@@ -256481,10 +256102,10 @@ class MD extends x {
256481
256102
  this.valueWithCursor = this.masked;
256482
256103
  }), this.on("value", () => {
256483
256104
  if (this.cursor >= this.value.length)
256484
- this.valueWithCursor = `${this.masked}${import_picocolors2.default.inverse(import_picocolors2.default.hidden("_"))}`;
256105
+ this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
256485
256106
  else {
256486
256107
  const F = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
256487
- this.valueWithCursor = `${F}${import_picocolors2.default.inverse(s[0])}${s.slice(1)}`;
256108
+ this.valueWithCursor = `${F}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
256488
256109
  }
256489
256110
  });
256490
256111
  }
@@ -256529,7 +256150,7 @@ class RD extends x {
256529
256150
  if (this.cursor >= this.value.length)
256530
256151
  return `${this.value}█`;
256531
256152
  const u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
256532
- return `${u}${import_picocolors2.default.inverse(t)}${F.join("")}`;
256153
+ return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
256533
256154
  }
256534
256155
  get cursor() {
256535
256156
  return this._cursor;
@@ -256542,7 +256163,7 @@ class RD extends x {
256542
256163
  }
256543
256164
 
256544
256165
  // node_modules/@clack/prompts/dist/index.mjs
256545
- var import_picocolors3 = __toESM(require_picocolors(), 1);
256166
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
256546
256167
  var import_sisteransi2 = __toESM(require_src(), 1);
256547
256168
  import y2 from "node:process";
256548
256169
  function ce() {
@@ -256575,13 +256196,13 @@ var b2 = (t) => {
256575
256196
  switch (t) {
256576
256197
  case "initial":
256577
256198
  case "active":
256578
- return import_picocolors3.default.cyan(le);
256199
+ return import_picocolors2.default.cyan(le);
256579
256200
  case "cancel":
256580
- return import_picocolors3.default.red(L2);
256201
+ return import_picocolors2.default.red(L2);
256581
256202
  case "error":
256582
- return import_picocolors3.default.yellow(W2);
256203
+ return import_picocolors2.default.yellow(W2);
256583
256204
  case "submit":
256584
- return import_picocolors3.default.green(C);
256205
+ return import_picocolors2.default.green(C);
256585
256206
  }
256586
256207
  };
256587
256208
  var G2 = (t) => {
@@ -256591,66 +256212,66 @@ var G2 = (t) => {
256591
256212
  const $2 = a < r2.length && l2 > 0, g = a < r2.length && l2 + a < r2.length;
256592
256213
  return r2.slice(l2, l2 + a).map((p2, v2, f) => {
256593
256214
  const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g;
256594
- return j2 || E ? import_picocolors3.default.dim("...") : i(p2, v2 + l2 === n);
256215
+ return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
256595
256216
  });
256596
256217
  };
256597
256218
  var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
256598
- const n = `${import_picocolors3.default.gray(o)}
256219
+ const n = `${import_picocolors2.default.gray(o)}
256599
256220
  ${b2(this.state)} ${t.message}
256600
- `, r2 = t.placeholder ? import_picocolors3.default.inverse(t.placeholder[0]) + import_picocolors3.default.dim(t.placeholder.slice(1)) : import_picocolors3.default.inverse(import_picocolors3.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
256221
+ `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
256601
256222
  switch (this.state) {
256602
256223
  case "error":
256603
256224
  return `${n.trim()}
256604
- ${import_picocolors3.default.yellow(o)} ${i}
256605
- ${import_picocolors3.default.yellow(d2)} ${import_picocolors3.default.yellow(this.error)}
256225
+ ${import_picocolors2.default.yellow(o)} ${i}
256226
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
256606
256227
  `;
256607
256228
  case "submit":
256608
- return `${n}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.dim(this.value || t.placeholder)}`;
256229
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
256609
256230
  case "cancel":
256610
- return `${n}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(this.value ?? ""))}${this.value?.trim() ? `
256611
- ${import_picocolors3.default.gray(o)}` : ""}`;
256231
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
256232
+ ${import_picocolors2.default.gray(o)}` : ""}`;
256612
256233
  default:
256613
- return `${n}${import_picocolors3.default.cyan(o)} ${i}
256614
- ${import_picocolors3.default.cyan(d2)}
256234
+ return `${n}${import_picocolors2.default.cyan(o)} ${i}
256235
+ ${import_picocolors2.default.cyan(d2)}
256615
256236
  `;
256616
256237
  }
256617
256238
  } }).prompt();
256618
256239
  var ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
256619
- const n = `${import_picocolors3.default.gray(o)}
256240
+ const n = `${import_picocolors2.default.gray(o)}
256620
256241
  ${b2(this.state)} ${t.message}
256621
256242
  `, r2 = this.valueWithCursor, i = this.masked;
256622
256243
  switch (this.state) {
256623
256244
  case "error":
256624
256245
  return `${n.trim()}
256625
- ${import_picocolors3.default.yellow(o)} ${i}
256626
- ${import_picocolors3.default.yellow(d2)} ${import_picocolors3.default.yellow(this.error)}
256246
+ ${import_picocolors2.default.yellow(o)} ${i}
256247
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
256627
256248
  `;
256628
256249
  case "submit":
256629
- return `${n}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.dim(i)}`;
256250
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
256630
256251
  case "cancel":
256631
- return `${n}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(i ?? ""))}${i ? `
256632
- ${import_picocolors3.default.gray(o)}` : ""}`;
256252
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
256253
+ ${import_picocolors2.default.gray(o)}` : ""}`;
256633
256254
  default:
256634
- return `${n}${import_picocolors3.default.cyan(o)} ${r2}
256635
- ${import_picocolors3.default.cyan(d2)}
256255
+ return `${n}${import_picocolors2.default.cyan(o)} ${r2}
256256
+ ${import_picocolors2.default.cyan(d2)}
256636
256257
  `;
256637
256258
  }
256638
256259
  } }).prompt();
256639
256260
  var ye = (t) => {
256640
256261
  const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
256641
256262
  return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
256642
- const i = `${import_picocolors3.default.gray(o)}
256263
+ const i = `${import_picocolors2.default.gray(o)}
256643
256264
  ${b2(this.state)} ${t.message}
256644
256265
  `, s = this.value ? n : r2;
256645
256266
  switch (this.state) {
256646
256267
  case "submit":
256647
- return `${i}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.dim(s)}`;
256268
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
256648
256269
  case "cancel":
256649
- return `${i}${import_picocolors3.default.gray(o)} ${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}
256650
- ${import_picocolors3.default.gray(o)}`;
256270
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
256271
+ ${import_picocolors2.default.gray(o)}`;
256651
256272
  default:
256652
- return `${i}${import_picocolors3.default.cyan(o)} ${this.value ? `${import_picocolors3.default.green(k2)} ${n}` : `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(n)}`} ${import_picocolors3.default.dim("/")} ${this.value ? `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(r2)}` : `${import_picocolors3.default.green(k2)} ${r2}`}
256653
- ${import_picocolors3.default.cyan(d2)}
256273
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
256274
+ ${import_picocolors2.default.cyan(d2)}
256654
256275
  `;
256655
256276
  }
256656
256277
  } }).prompt();
@@ -256660,29 +256281,29 @@ var ve = (t) => {
256660
256281
  const s = r2.label ?? String(r2.value);
256661
256282
  switch (i) {
256662
256283
  case "selected":
256663
- return `${import_picocolors3.default.dim(s)}`;
256284
+ return `${import_picocolors2.default.dim(s)}`;
256664
256285
  case "active":
256665
- return `${import_picocolors3.default.green(k2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}`;
256286
+ return `${import_picocolors2.default.green(k2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
256666
256287
  case "cancelled":
256667
- return `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}`;
256288
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
256668
256289
  default:
256669
- return `${import_picocolors3.default.dim(P2)} ${import_picocolors3.default.dim(s)}`;
256290
+ return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
256670
256291
  }
256671
256292
  };
256672
256293
  return new LD({ options: t.options, initialValue: t.initialValue, render() {
256673
- const r2 = `${import_picocolors3.default.gray(o)}
256294
+ const r2 = `${import_picocolors2.default.gray(o)}
256674
256295
  ${b2(this.state)} ${t.message}
256675
256296
  `;
256676
256297
  switch (this.state) {
256677
256298
  case "submit":
256678
- return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
256299
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
256679
256300
  case "cancel":
256680
- return `${r2}${import_picocolors3.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
256681
- ${import_picocolors3.default.gray(o)}`;
256301
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
256302
+ ${import_picocolors2.default.gray(o)}`;
256682
256303
  default:
256683
- return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
256684
- ${import_picocolors3.default.cyan(o)} `)}
256685
- ${import_picocolors3.default.cyan(d2)}
256304
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
256305
+ ${import_picocolors2.default.cyan(o)} `)}
256306
+ ${import_picocolors2.default.cyan(d2)}
256686
256307
  `;
256687
256308
  }
256688
256309
  } }).prompt();
@@ -256690,14 +256311,14 @@ ${import_picocolors3.default.cyan(d2)}
256690
256311
  var fe = (t) => {
256691
256312
  const n = (r2, i) => {
256692
256313
  const s = r2.label ?? String(r2.value);
256693
- return i === "active" ? `${import_picocolors3.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors3.default.green(T)} ${import_picocolors3.default.dim(s)} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors3.default.strikethrough(import_picocolors3.default.dim(s))}` : i === "active-selected" ? `${import_picocolors3.default.green(T)} ${s} ${r2.hint ? import_picocolors3.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors3.default.dim(s)}` : `${import_picocolors3.default.dim(F)} ${import_picocolors3.default.dim(s)}`;
256314
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
256694
256315
  };
256695
256316
  return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
256696
256317
  if (this.required && r2.length === 0)
256697
256318
  return `Please select at least one option.
256698
- ${import_picocolors3.default.reset(import_picocolors3.default.dim(`Press ${import_picocolors3.default.gray(import_picocolors3.default.bgWhite(import_picocolors3.default.inverse(" space ")))} to select, ${import_picocolors3.default.gray(import_picocolors3.default.bgWhite(import_picocolors3.default.inverse(" enter ")))} to submit`))}`;
256319
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
256699
256320
  }, render() {
256700
- const r2 = `${import_picocolors3.default.gray(o)}
256321
+ const r2 = `${import_picocolors2.default.gray(o)}
256701
256322
  ${b2(this.state)} ${t.message}
256702
256323
  `, i = (s, c) => {
256703
256324
  const a = this.value.includes(s.value);
@@ -256705,44 +256326,44 @@ ${b2(this.state)} ${t.message}
256705
256326
  };
256706
256327
  switch (this.state) {
256707
256328
  case "submit":
256708
- return `${r2}${import_picocolors3.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors3.default.dim(", ")) || import_picocolors3.default.dim("none")}`;
256329
+ return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
256709
256330
  case "cancel": {
256710
- const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors3.default.dim(", "));
256711
- return `${r2}${import_picocolors3.default.gray(o)} ${s.trim() ? `${s}
256712
- ${import_picocolors3.default.gray(o)}` : ""}`;
256331
+ const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
256332
+ return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
256333
+ ${import_picocolors2.default.gray(o)}` : ""}`;
256713
256334
  }
256714
256335
  case "error": {
256715
256336
  const s = this.error.split(`
256716
- `).map((c, a) => a === 0 ? `${import_picocolors3.default.yellow(d2)} ${import_picocolors3.default.yellow(c)}` : ` ${c}`).join(`
256337
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
256717
256338
  `);
256718
- return `${r2 + import_picocolors3.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
256719
- ${import_picocolors3.default.yellow(o)} `)}
256339
+ return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
256340
+ ${import_picocolors2.default.yellow(o)} `)}
256720
256341
  ${s}
256721
256342
  `;
256722
256343
  }
256723
256344
  default:
256724
- return `${r2}${import_picocolors3.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
256725
- ${import_picocolors3.default.cyan(o)} `)}
256726
- ${import_picocolors3.default.cyan(d2)}
256345
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
256346
+ ${import_picocolors2.default.cyan(o)} `)}
256347
+ ${import_picocolors2.default.cyan(d2)}
256727
256348
  `;
256728
256349
  }
256729
256350
  } }).prompt();
256730
256351
  };
256731
- var J2 = `${import_picocolors3.default.gray(o)} `;
256352
+ var J2 = `${import_picocolors2.default.gray(o)} `;
256732
256353
 
256733
256354
  // src/utils/display.ts
256734
- var import_picocolors4 = __toESM(require_picocolors(), 1);
256355
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
256735
256356
  function success(message) {
256736
- console.log(`${import_picocolors4.default.green("✓")} ${message}`);
256357
+ console.log(`${import_picocolors3.default.green("✓")} ${message}`);
256737
256358
  }
256738
256359
  function error(message) {
256739
- console.log(`${import_picocolors4.default.red("✗")} ${message}`);
256360
+ console.log(`${import_picocolors3.default.red("✗")} ${message}`);
256740
256361
  }
256741
256362
  function warn(message) {
256742
- console.log(`${import_picocolors4.default.yellow("⚠")} ${message}`);
256363
+ console.log(`${import_picocolors3.default.yellow("⚠")} ${message}`);
256743
256364
  }
256744
256365
  function info(message) {
256745
- console.log(`${import_picocolors4.default.blue("ℹ")} ${message}`);
256366
+ console.log(`${import_picocolors3.default.blue("ℹ")} ${message}`);
256746
256367
  }
256747
256368
  var MODEL_PRICING = {
256748
256369
  "claude-opus-4-5": [15, 75],
@@ -256784,135 +256405,665 @@ function renderContextBanner(params) {
256784
256405
  const costUsd = pricing ? inputTokens / 1e6 * pricing[0] + outputTokens / 1e6 * pricing[1] : null;
256785
256406
  const providerLabel = provider.charAt(0).toUpperCase() + provider.slice(1);
256786
256407
  const width = 36;
256787
- const border = import_picocolors4.default.dim("─".repeat(width));
256408
+ const border = import_picocolors3.default.dim("─".repeat(width));
256788
256409
  console.log("");
256789
- console.log(` ${import_picocolors4.default.dim(border)}`);
256790
- console.log(` ${import_picocolors4.default.dim("│")} ${import_picocolors4.default.bold("Context")}${" ".repeat(width - 9)}${import_picocolors4.default.dim("│")}`);
256791
- console.log(` ${import_picocolors4.default.dim("│")} ${import_picocolors4.default.cyan(totalTokens.toLocaleString())} ${import_picocolors4.default.dim("tokens")}${" ".repeat(Math.max(0, width - 2 - totalTokens.toLocaleString().length - 7))}${import_picocolors4.default.dim("│")}`);
256792
- console.log(` ${import_picocolors4.default.dim("│")} ${import_picocolors4.default.yellow(`${pctUsed}%`)} ${import_picocolors4.default.dim("of context window used")}${" ".repeat(Math.max(0, width - 2 - String(pctUsed).length - 1 - 22))}${import_picocolors4.default.dim("│")}`);
256410
+ console.log(` ${import_picocolors3.default.dim(border)}`);
256411
+ console.log(` ${import_picocolors3.default.dim("│")} ${import_picocolors3.default.bold("Context")}${" ".repeat(width - 9)}${import_picocolors3.default.dim("│")}`);
256412
+ console.log(` ${import_picocolors3.default.dim("│")} ${import_picocolors3.default.cyan(totalTokens.toLocaleString())} ${import_picocolors3.default.dim("tokens")}${" ".repeat(Math.max(0, width - 2 - totalTokens.toLocaleString().length - 7))}${import_picocolors3.default.dim("│")}`);
256413
+ console.log(` ${import_picocolors3.default.dim("│")} ${import_picocolors3.default.yellow(`${pctUsed}%`)} ${import_picocolors3.default.dim("of context window used")}${" ".repeat(Math.max(0, width - 2 - String(pctUsed).length - 1 - 22))}${import_picocolors3.default.dim("│")}`);
256793
256414
  if (costUsd !== null) {
256794
256415
  const costStr = formatCost(costUsd);
256795
- console.log(` ${import_picocolors4.default.dim("│")} ${import_picocolors4.default.green(costStr)} ${import_picocolors4.default.dim("spent")}${" ".repeat(Math.max(0, width - 2 - costStr.length - 6))}${import_picocolors4.default.dim("│")}`);
256416
+ console.log(` ${import_picocolors3.default.dim("│")} ${import_picocolors3.default.green(costStr)} ${import_picocolors3.default.dim("spent")}${" ".repeat(Math.max(0, width - 2 - costStr.length - 6))}${import_picocolors3.default.dim("│")}`);
256796
256417
  }
256797
- console.log(` ${import_picocolors4.default.dim("│")} ${import_picocolors4.default.dim(`${providerLabel} · ${model}`)}${" ".repeat(Math.max(0, width - 2 - providerLabel.length - 3 - model.length))}${import_picocolors4.default.dim("│")}`);
256798
- console.log(` ${import_picocolors4.default.dim(border)}`);
256418
+ console.log(` ${import_picocolors3.default.dim("│")} ${import_picocolors3.default.dim(`${providerLabel} · ${model}`)}${" ".repeat(Math.max(0, width - 2 - providerLabel.length - 3 - model.length))}${import_picocolors3.default.dim("│")}`);
256419
+ console.log(` ${import_picocolors3.default.dim(border)}`);
256799
256420
  console.log("");
256800
256421
  }
256801
256422
 
256802
- // src/sandbox/staging.ts
256803
- import {
256804
- copyFileSync,
256805
- existsSync as existsSync6,
256806
- mkdirSync as mkdirSync5,
256807
- readdirSync,
256808
- readFileSync as readFileSync5,
256809
- rmSync as rmSync2,
256810
- statSync as statSync3,
256811
- writeFileSync as writeFileSync5
256812
- } from "node:fs";
256813
- import { createHash } from "node:crypto";
256814
- import { dirname as dirname3, join as join6, relative } from "node:path";
256815
-
256816
- // src/audit/logger.ts
256817
- import {
256818
- appendFileSync,
256819
- existsSync as existsSync5,
256820
- mkdirSync as mkdirSync4,
256821
- renameSync as renameSync3,
256822
- rmSync,
256823
- statSync as statSync2,
256824
- writeFileSync as writeFileSync4
256825
- } from "node:fs";
256826
- import { join as join5 } from "node:path";
256827
- var AUDIT_DIR_NAME = ".kitt";
256828
- var AUDIT_FILE_NAME = "audit.log";
256829
- var ROTATED_LOG_1 = "audit.log.1";
256830
- var ROTATED_LOG_2 = "audit.log.2";
256831
- var MAX_LOG_SIZE_BYTES = 10 * 1024 * 1024;
256832
- function formatLine(type, message) {
256833
- return `[${new Date().toISOString()}] ${type} ${message}
256834
- `;
256423
+ // src/mcp/lifecycle.ts
256424
+ var MCP_START_FAILURE_MESSAGE = "Railway MCP Server not found. Install it: npm install -g @railway/mcp-server";
256425
+ var SHUTDOWN_TIMEOUT_MS = 5000;
256426
+ var auditLogger = createAuditLogger(".");
256427
+ function findMcpEntryPoint() {
256428
+ try {
256429
+ const globalRoot = execSync("npm root -g", { encoding: "utf-8", stdio: "pipe" }).trim();
256430
+ const candidate = join2(globalRoot, "@railway", "mcp-server", "dist", "index.js");
256431
+ if (existsSync2(candidate))
256432
+ return candidate;
256433
+ } catch {}
256434
+ return null;
256835
256435
  }
256836
- function ensureAuditDir(auditDir) {
256837
- if (existsSync5(auditDir)) {
256838
- return;
256436
+ var activeServer = null;
256437
+ var pendingSpawn = null;
256438
+ var shouldLogRespawn = false;
256439
+ var intentionallyShuttingDown = new WeakSet;
256440
+ function formatExitDetail(code, signal) {
256441
+ const codeLabel = code === null ? "null" : String(code);
256442
+ const signalLabel = signal ?? "null";
256443
+ return `code=${codeLabel}, signal=${signalLabel}`;
256444
+ }
256445
+ function isChildRunning(child) {
256446
+ return child.exitCode === null && !child.killed;
256447
+ }
256448
+ function buildServerProcess(child) {
256449
+ if (!child.stdin || !child.stdout) {
256450
+ throw new Error("MCP server stdio was not created");
256839
256451
  }
256840
- mkdirSync4(auditDir, { recursive: true, mode: 448 });
256452
+ return {
256453
+ process: child,
256454
+ stdin: child.stdin,
256455
+ stdout: child.stdout,
256456
+ pid: child.pid ?? -1
256457
+ };
256841
256458
  }
256842
- function rotateLogIfNeeded(logPath, log1Path, log2Path) {
256843
- if (!existsSync5(logPath)) {
256459
+ function attachLifecycleListeners(child) {
256460
+ child.stderr?.on("data", (chunk) => {
256461
+ const message = String(chunk).trim();
256462
+ if (!message) {
256463
+ return;
256464
+ }
256465
+ auditLogger.mcp("server-lifecycle", "stderr", "FAILED", message);
256466
+ });
256467
+ child.on("exit", (code, signal) => {
256468
+ const detail = formatExitDetail(code, signal);
256469
+ if (activeServer?.process === child) {
256470
+ activeServer = null;
256471
+ }
256472
+ if (intentionallyShuttingDown.has(child)) {
256473
+ return;
256474
+ }
256475
+ shouldLogRespawn = true;
256476
+ auditLogger.mcp("server-lifecycle", "crash", "FAILED", detail);
256477
+ });
256478
+ }
256479
+ function displaySpawnFailure(reason) {
256480
+ error(MCP_START_FAILURE_MESSAGE);
256481
+ auditLogger.mcp("server-lifecycle", "spawn", "FAILED", reason);
256482
+ }
256483
+ async function spawnMcpServer() {
256484
+ if (activeServer && isChildRunning(activeServer.process)) {
256485
+ return activeServer;
256486
+ }
256487
+ if (pendingSpawn) {
256488
+ return pendingSpawn;
256489
+ }
256490
+ const entryPoint = findMcpEntryPoint();
256491
+ if (!entryPoint) {
256492
+ throw new Error(MCP_START_FAILURE_MESSAGE);
256493
+ }
256494
+ const respawn = shouldLogRespawn;
256495
+ const child = spawn("node", [entryPoint], {
256496
+ stdio: ["pipe", "pipe", "pipe"]
256497
+ });
256498
+ attachLifecycleListeners(child);
256499
+ pendingSpawn = new Promise((resolve, reject) => {
256500
+ const handleError = (spawnError) => {
256501
+ child.off("spawn", handleSpawn);
256502
+ if (activeServer?.process === child) {
256503
+ activeServer = null;
256504
+ }
256505
+ displaySpawnFailure(spawnError.message);
256506
+ reject(spawnError);
256507
+ };
256508
+ const handleSpawn = () => {
256509
+ child.off("error", handleError);
256510
+ let serverProcess;
256511
+ try {
256512
+ serverProcess = buildServerProcess(child);
256513
+ } catch (buildError) {
256514
+ const err = buildError instanceof Error ? buildError : new Error(String(buildError));
256515
+ displaySpawnFailure(err.message);
256516
+ reject(err);
256517
+ return;
256518
+ }
256519
+ activeServer = serverProcess;
256520
+ shouldLogRespawn = false;
256521
+ if (respawn) {
256522
+ auditLogger.mcp("server-lifecycle", "respawn", "SUCCESS", `pid=${serverProcess.pid}`);
256523
+ } else {
256524
+ auditLogger.mcp("server-lifecycle", "spawn", "SUCCESS", `pid=${serverProcess.pid}`);
256525
+ }
256526
+ resolve(serverProcess);
256527
+ };
256528
+ child.once("error", handleError);
256529
+ child.once("spawn", handleSpawn);
256530
+ }).finally(() => {
256531
+ pendingSpawn = null;
256532
+ });
256533
+ return pendingSpawn;
256534
+ }
256535
+ async function shutdownMcpServer() {
256536
+ if (!activeServer) {
256844
256537
  return;
256845
256538
  }
256846
- const stats = statSync2(logPath);
256847
- if (stats.size < MAX_LOG_SIZE_BYTES) {
256539
+ const child = activeServer.process;
256540
+ intentionallyShuttingDown.add(child);
256541
+ if (!isChildRunning(child)) {
256542
+ activeServer = null;
256848
256543
  return;
256849
256544
  }
256850
- if (existsSync5(log2Path)) {
256851
- rmSync(log2Path, { force: true });
256545
+ const exitPromise = new Promise((resolve) => {
256546
+ child.once("exit", (code, signal) => {
256547
+ resolve({ code, signal });
256548
+ });
256549
+ });
256550
+ child.kill("SIGTERM");
256551
+ let forcedKill = false;
256552
+ const timeoutHandle = setTimeout(() => {
256553
+ forcedKill = true;
256554
+ child.kill("SIGKILL");
256555
+ }, SHUTDOWN_TIMEOUT_MS);
256556
+ const exitResult = await exitPromise;
256557
+ clearTimeout(timeoutHandle);
256558
+ activeServer = null;
256559
+ const detail = forcedKill ? `forced after timeout (${formatExitDetail(exitResult.code, exitResult.signal)})` : formatExitDetail(exitResult.code, exitResult.signal);
256560
+ auditLogger.mcp("server-lifecycle", "shutdown", "SUCCESS", detail);
256561
+ }
256562
+
256563
+ // src/utils/prerequisites.ts
256564
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
256565
+ function getNodeVersion() {
256566
+ try {
256567
+ const output = execSync3("node --version", {
256568
+ encoding: "utf-8",
256569
+ stdio: "pipe"
256570
+ }).trim();
256571
+ return output.replace(/^v/, "");
256572
+ } catch {
256573
+ return "";
256852
256574
  }
256853
- if (existsSync5(log1Path)) {
256854
- renameSync3(log1Path, log2Path);
256575
+ }
256576
+ function getBunVersion() {
256577
+ try {
256578
+ const output = execSync3("bun --version", {
256579
+ encoding: "utf-8",
256580
+ stdio: "pipe"
256581
+ }).trim();
256582
+ return output;
256583
+ } catch {
256584
+ return null;
256855
256585
  }
256856
- renameSync3(logPath, log1Path);
256857
- writeFileSync4(logPath, "", { encoding: "utf8", mode: 384 });
256858
256586
  }
256859
- function writeAuditLine(logPath, log1Path, log2Path, type, message) {
256587
+ function getRailwayVersion() {
256860
256588
  try {
256861
- rotateLogIfNeeded(logPath, log1Path, log2Path);
256862
- appendFileSync(logPath, formatLine(type, message), { encoding: "utf8", mode: 384 });
256589
+ const output = execSync3("railway --version", {
256590
+ encoding: "utf-8",
256591
+ stdio: "pipe"
256592
+ }).trim();
256593
+ return output || null;
256863
256594
  } catch {
256864
- return;
256595
+ return null;
256865
256596
  }
256866
256597
  }
256867
- function createAuditLogger(workspaceDir) {
256868
- const auditDir = join5(workspaceDir, AUDIT_DIR_NAME);
256869
- const logPath = join5(auditDir, AUDIT_FILE_NAME);
256870
- const log1Path = join5(auditDir, ROTATED_LOG_1);
256871
- const log2Path = join5(auditDir, ROTATED_LOG_2);
256872
- return {
256873
- log(type, message) {
256874
- try {
256875
- ensureAuditDir(auditDir);
256876
- } catch {
256877
- return;
256878
- }
256879
- writeAuditLine(logPath, log1Path, log2Path, type, message);
256880
- },
256881
- cmd(command, status, detail) {
256882
- const suffix = detail ? ` (${detail})` : "";
256883
- this.log("CMD", `${command} → ${status}${suffix}`);
256884
- },
256885
- cmdExec(command, status) {
256886
- this.log("CMD_EXEC", `${command} → ${status}`);
256887
- },
256888
- mcp(tool, params, status, detail) {
256889
- const suffix = detail ? ` (${detail})` : "";
256890
- this.log("MCP", `${tool} (${params}) → ${status}${suffix}`);
256891
- },
256892
- llmCall(provider, model, promptVersion, estimatedTokens, status) {
256893
- this.log("LLM_CALL", `${provider}/${model} (prompt: ${promptVersion}, est. ${estimatedTokens} tokens) → ${status}`);
256598
+ async function checkPrerequisites() {
256599
+ const nodeVersion = getNodeVersion();
256600
+ const bunVersion = getBunVersion();
256601
+ const railwayVersion = getRailwayVersion();
256602
+ const mcpFound = findMcpEntryPoint() !== null;
256603
+ return [
256604
+ {
256605
+ name: "Node.js",
256606
+ found: !!nodeVersion,
256607
+ version: nodeVersion || undefined
256894
256608
  },
256895
- fileWrite(path, hash) {
256896
- const suffix = hash ? ` (SHA-256: ${hash})` : "";
256897
- this.log("FILE_WRITE", `${path}${suffix}`);
256609
+ {
256610
+ name: "Bun",
256611
+ found: !!bunVersion,
256612
+ version: bunVersion || undefined,
256613
+ installUrl: bunVersion ? undefined : "https://bun.sh"
256898
256614
  },
256899
- staged(path, detail) {
256900
- this.log("STAGED", `${path} (${detail})`);
256615
+ {
256616
+ name: "Railway CLI",
256617
+ found: !!railwayVersion,
256618
+ version: railwayVersion || undefined,
256619
+ installUrl: railwayVersion ? undefined : "https://docs.railway.com/cli"
256901
256620
  },
256902
- userConfirmed() {
256903
- this.log("USER_CONFIRMED", "staged changes");
256621
+ {
256622
+ name: "Railway MCP",
256623
+ found: mcpFound,
256624
+ installUrl: mcpFound ? undefined : "npm install -g @railway/mcp-server"
256625
+ }
256626
+ ];
256627
+ }
256628
+ function displayPrerequisites(statuses) {
256629
+ for (const status of statuses) {
256630
+ if (status.found) {
256631
+ const version = status.version ? `v${status.version}` : "";
256632
+ const paddedName = status.name.padEnd(12);
256633
+ console.log(` ${import_picocolors4.default.green("✓")} ${paddedName} ${version}`);
256634
+ } else {
256635
+ const paddedName = status.name.padEnd(12);
256636
+ const installMsg = status.installUrl ? `not found. Install: ${status.installUrl}` : "not found";
256637
+ console.log(` ${import_picocolors4.default.red("✗")} ${paddedName} ${installMsg}`);
256638
+ }
256639
+ }
256640
+ }
256641
+ async function displayLlmStatus() {
256642
+ const paddedName = "LLM".padEnd(12);
256643
+ try {
256644
+ const { isLlmConfigured: isLlmConfigured2, getLlmConfig: getLlmConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
256645
+ const [configured, config] = await Promise.all([isLlmConfigured2(), getLlmConfig2()]);
256646
+ if (configured && config) {
256647
+ const label = `${config.provider[0].toUpperCase()}${config.provider.slice(1)} (${config.model})`;
256648
+ console.log(` ${import_picocolors4.default.green("✓")} ${paddedName} ${label}`);
256649
+ } else {
256650
+ console.log(` ${import_picocolors4.default.yellow("!")} ${paddedName} not configured`);
256651
+ }
256652
+ } catch {
256653
+ console.log(` ${import_picocolors4.default.yellow("!")} ${paddedName} not configured`);
256654
+ }
256655
+ }
256656
+
256657
+ // src/manifest/reader.ts
256658
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
256659
+ import { join as join6, dirname as dirname2, resolve } from "node:path";
256660
+
256661
+ // src/utils/global-config.ts
256662
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
256663
+ import { homedir as homedir2 } from "node:os";
256664
+ import { join as join4 } from "node:path";
256665
+ function getGlobalConfigPath() {
256666
+ return join4(homedir2(), ".kitt", "workspace.json");
256667
+ }
256668
+ function readGlobalConfig() {
256669
+ const configPath = getGlobalConfigPath();
256670
+ if (!existsSync4(configPath)) {
256671
+ return {};
256672
+ }
256673
+ try {
256674
+ const raw = readFileSync3(configPath, "utf-8").trim();
256675
+ if (!raw)
256676
+ return {};
256677
+ const parsed = JSON.parse(raw);
256678
+ if (typeof parsed === "object" && parsed !== null) {
256679
+ return parsed;
256680
+ }
256681
+ return {};
256682
+ } catch {
256683
+ return {};
256684
+ }
256685
+ }
256686
+ function writeGlobalConfig(config) {
256687
+ const configPath = getGlobalConfigPath();
256688
+ const configDir = join4(homedir2(), ".kitt");
256689
+ mkdirSync3(configDir, { recursive: true });
256690
+ writeFileSync3(configPath, JSON.stringify(config, null, 2) + `
256691
+ `, "utf-8");
256692
+ }
256693
+ function setGlobalWorkspacePath(workspacePath) {
256694
+ const existing = readGlobalConfig();
256695
+ writeGlobalConfig({ ...existing, workspacePath });
256696
+ }
256697
+ function getGlobalWorkspacePath() {
256698
+ return readGlobalConfig().workspacePath ?? null;
256699
+ }
256700
+
256701
+ // src/manifest/writer.ts
256702
+ import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync4, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
256703
+ import { platform as platform3 } from "node:os";
256704
+ import { dirname, join as join5 } from "node:path";
256705
+ var DIR_MODE2 = 448;
256706
+ var FILE_MODE2 = 384;
256707
+ var MANIFEST_VERSION = "0.1.0";
256708
+ function isWindows2() {
256709
+ return platform3() === "win32";
256710
+ }
256711
+ function ensureKittDir(manifestPath) {
256712
+ const kittDir = dirname(manifestPath);
256713
+ if (!existsSync5(kittDir)) {
256714
+ mkdirSync4(kittDir, { recursive: true, mode: DIR_MODE2 });
256715
+ }
256716
+ if (!isWindows2()) {
256717
+ chmodSync2(kittDir, DIR_MODE2);
256718
+ }
256719
+ }
256720
+ function writeManifest(workspaceDir, manifest) {
256721
+ const manifestPath = getManifestPath(workspaceDir);
256722
+ const manifestDir = dirname(manifestPath);
256723
+ const tempFile = join5(manifestDir, `manifest.json.tmp-${process.pid}-${Date.now()}`);
256724
+ const payload = `${JSON.stringify(manifest, null, 2)}
256725
+ `;
256726
+ ensureKittDir(manifestPath);
256727
+ try {
256728
+ writeFileSync4(tempFile, payload, { encoding: "utf-8", mode: FILE_MODE2 });
256729
+ if (!isWindows2()) {
256730
+ chmodSync2(tempFile, FILE_MODE2);
256731
+ }
256732
+ renameSync3(tempFile, manifestPath);
256733
+ if (!isWindows2()) {
256734
+ chmodSync2(manifestPath, FILE_MODE2);
256735
+ }
256736
+ } catch (error2) {
256737
+ if (existsSync5(tempFile)) {
256738
+ unlinkSync2(tempFile);
256739
+ }
256740
+ throw error2;
256741
+ }
256742
+ }
256743
+ function createInitialManifest(workspaceName, packageManager, railway) {
256744
+ return {
256745
+ version: MANIFEST_VERSION,
256746
+ workspace: {
256747
+ name: workspaceName,
256748
+ packageManager,
256749
+ ...railway ? { railway } : {}
256904
256750
  },
256905
- security(action, message) {
256906
- this.log("SECURITY", `${action} ${message}`);
256751
+ settings: {},
256752
+ apps: {},
256753
+ packages: {}
256754
+ };
256755
+ }
256756
+ function addApp(manifest, name, app) {
256757
+ return {
256758
+ ...manifest,
256759
+ apps: {
256760
+ ...manifest.apps,
256761
+ [name]: app
256762
+ }
256763
+ };
256764
+ }
256765
+ function removeApp(manifest, name) {
256766
+ const nextApps = { ...manifest.apps };
256767
+ delete nextApps[name];
256768
+ const nextPackages = {};
256769
+ for (const [packageName, pkg] of Object.entries(manifest.packages)) {
256770
+ nextPackages[packageName] = {
256771
+ ...pkg,
256772
+ consumers: pkg.consumers.filter((consumer) => consumer !== name)
256773
+ };
256774
+ }
256775
+ return {
256776
+ ...manifest,
256777
+ apps: nextApps,
256778
+ packages: nextPackages
256779
+ };
256780
+ }
256781
+ function addPackage(manifest, name, pkg) {
256782
+ return {
256783
+ ...manifest,
256784
+ packages: {
256785
+ ...manifest.packages,
256786
+ [name]: pkg
256907
256787
  }
256908
256788
  };
256909
256789
  }
256790
+ function addConsumer(manifest, packageName, appName) {
256791
+ const pkg = manifest.packages[packageName];
256792
+ if (!pkg) {
256793
+ return {
256794
+ ...manifest,
256795
+ packages: {
256796
+ ...manifest.packages
256797
+ }
256798
+ };
256799
+ }
256800
+ const consumers = pkg.consumers.includes(appName) ? [...pkg.consumers] : [...pkg.consumers, appName];
256801
+ return {
256802
+ ...manifest,
256803
+ packages: {
256804
+ ...manifest.packages,
256805
+ [packageName]: {
256806
+ ...pkg,
256807
+ consumers
256808
+ }
256809
+ }
256810
+ };
256811
+ }
256812
+
256813
+ // src/manifest/reader.ts
256814
+ function isObjectRecord(value) {
256815
+ return typeof value === "object" && value !== null;
256816
+ }
256817
+ function isValidWorkspaceManifest(value) {
256818
+ if (!isObjectRecord(value)) {
256819
+ return false;
256820
+ }
256821
+ if (typeof value.version !== "string") {
256822
+ return false;
256823
+ }
256824
+ if (!isObjectRecord(value.workspace)) {
256825
+ return false;
256826
+ }
256827
+ if (typeof value.workspace.name !== "string") {
256828
+ return false;
256829
+ }
256830
+ const packageManager = value.workspace.packageManager;
256831
+ if (packageManager !== "bun" && packageManager !== "npm" && packageManager !== "pnpm" && packageManager !== "yarn") {
256832
+ return false;
256833
+ }
256834
+ if (!isObjectRecord(value.apps)) {
256835
+ return false;
256836
+ }
256837
+ if (!isObjectRecord(value.packages)) {
256838
+ return false;
256839
+ }
256840
+ if (!isObjectRecord(value.settings)) {
256841
+ return false;
256842
+ }
256843
+ return true;
256844
+ }
256845
+ function getManifestPath(workspaceDir) {
256846
+ return join6(workspaceDir, ".kitt", "manifest.json");
256847
+ }
256848
+ function isKittWorkspace(dir) {
256849
+ return existsSync6(getManifestPath(dir));
256850
+ }
256851
+ function findWorkspaceRoot(startDir) {
256852
+ let current = resolve(startDir);
256853
+ while (true) {
256854
+ if (isKittWorkspace(current))
256855
+ return current;
256856
+ const parent = dirname2(current);
256857
+ if (parent === current)
256858
+ break;
256859
+ current = parent;
256860
+ }
256861
+ const globalPath = getGlobalWorkspacePath();
256862
+ if (globalPath && isKittWorkspace(globalPath))
256863
+ return globalPath;
256864
+ return null;
256865
+ }
256866
+ function findWorkspaceRootStrict(startDir) {
256867
+ let current = resolve(startDir);
256868
+ while (true) {
256869
+ if (isKittWorkspace(current))
256870
+ return current;
256871
+ const parent = dirname2(current);
256872
+ if (parent === current)
256873
+ break;
256874
+ current = parent;
256875
+ }
256876
+ return null;
256877
+ }
256878
+ function readManifest(workspaceDir) {
256879
+ const manifestPath = getManifestPath(workspaceDir);
256880
+ if (!existsSync6(manifestPath)) {
256881
+ return null;
256882
+ }
256883
+ try {
256884
+ const raw = readFileSync4(manifestPath, "utf-8").trim();
256885
+ if (raw.length === 0) {
256886
+ return null;
256887
+ }
256888
+ const parsed = JSON.parse(raw);
256889
+ if (!isValidWorkspaceManifest(parsed)) {
256890
+ return null;
256891
+ }
256892
+ return parsed;
256893
+ } catch {
256894
+ return null;
256895
+ }
256896
+ }
256897
+ function reconcileManifest(workspaceDir) {
256898
+ const manifest = readManifest(workspaceDir);
256899
+ if (!manifest)
256900
+ return null;
256901
+ const staleApps = Object.keys(manifest.apps).filter((name) => !existsSync6(join6(workspaceDir, "apps", name)));
256902
+ if (staleApps.length === 0)
256903
+ return manifest;
256904
+ let cleaned = manifest;
256905
+ for (const name of staleApps) {
256906
+ cleaned = removeApp(cleaned, name);
256907
+ }
256908
+ writeManifest(workspaceDir, cleaned);
256909
+ return cleaned;
256910
+ }
256911
+
256912
+ // src/utils/auth-guard.ts
256913
+ init_config();
256914
+
256915
+ // src/credentials/railway.ts
256916
+ import { execSync as execSync4 } from "node:child_process";
256917
+ async function isRailwayInstalled() {
256918
+ try {
256919
+ execSync4("railway --version", {
256920
+ encoding: "utf-8",
256921
+ stdio: "pipe"
256922
+ });
256923
+ return true;
256924
+ } catch {
256925
+ return false;
256926
+ }
256927
+ }
256928
+ async function checkRailwayAuth() {
256929
+ const installed = await isRailwayInstalled();
256930
+ if (!installed) {
256931
+ return {
256932
+ authenticated: false,
256933
+ error: "Railway CLI not installed"
256934
+ };
256935
+ }
256936
+ try {
256937
+ const output = execSync4("railway whoami", {
256938
+ encoding: "utf-8",
256939
+ stdio: "pipe"
256940
+ }).trim();
256941
+ if (output && output.length > 0) {
256942
+ return {
256943
+ authenticated: true,
256944
+ username: output
256945
+ };
256946
+ }
256947
+ return {
256948
+ authenticated: false
256949
+ };
256950
+ } catch {
256951
+ return {
256952
+ authenticated: false
256953
+ };
256954
+ }
256955
+ }
256956
+ async function railwayLogin() {
256957
+ try {
256958
+ execSync4("railway login", {
256959
+ stdio: "inherit"
256960
+ });
256961
+ return await checkRailwayAuth();
256962
+ } catch {
256963
+ return {
256964
+ authenticated: false,
256965
+ error: "Failed to complete Railway login"
256966
+ };
256967
+ }
256968
+ }
256969
+ async function railwayLogout() {
256970
+ try {
256971
+ execSync4("railway logout", {
256972
+ encoding: "utf-8",
256973
+ stdio: "pipe"
256974
+ });
256975
+ return true;
256976
+ } catch {
256977
+ return false;
256978
+ }
256979
+ }
256980
+
256981
+ // src/utils/auth-guard.ts
256982
+ var WORKSPACE_REQUIRED = new Set([
256983
+ "create",
256984
+ "delete",
256985
+ "list",
256986
+ "run",
256987
+ "deploy",
256988
+ "deploy:template",
256989
+ "env:create",
256990
+ "env:vars",
256991
+ "domain",
256992
+ "logs",
256993
+ "status",
256994
+ "versions"
256995
+ ]);
256996
+ var COMMAND_AUTH = {
256997
+ login: "none",
256998
+ logout: "none",
256999
+ help: "none",
257000
+ settings: "none",
257001
+ list: "none",
257002
+ versions: "none",
257003
+ exit: "none",
257004
+ init: "both",
257005
+ create: "both",
257006
+ delete: "both",
257007
+ deploy: "both",
257008
+ "deploy:template": "both",
257009
+ "env:create": "both",
257010
+ "env:vars": "both",
257011
+ domain: "both",
257012
+ logs: "both",
257013
+ status: "both"
257014
+ };
257015
+ async function checkAuthGuard(commandKey) {
257016
+ if (WORKSPACE_REQUIRED.has(commandKey)) {
257017
+ const workspaceRoot = findWorkspaceRootStrict(process.cwd());
257018
+ if (!workspaceRoot) {
257019
+ return {
257020
+ allowed: false,
257021
+ message: "No KITT workspace found. Run /init to initialize one."
257022
+ };
257023
+ }
257024
+ }
257025
+ const requirement = COMMAND_AUTH[commandKey];
257026
+ if (!requirement || requirement === "none") {
257027
+ return { allowed: true };
257028
+ }
257029
+ if (requirement === "llm" || requirement === "both") {
257030
+ const llmConfigured = await isLlmConfigured();
257031
+ if (!llmConfigured) {
257032
+ return {
257033
+ allowed: false,
257034
+ message: "LLM API key required. Run /login llm to configure."
257035
+ };
257036
+ }
257037
+ }
257038
+ if (requirement === "railway" || requirement === "both") {
257039
+ const railwayStatus = await checkRailwayAuth();
257040
+ if (!railwayStatus.authenticated) {
257041
+ return {
257042
+ allowed: false,
257043
+ message: "Railway authentication required. Run /login railway to authenticate."
257044
+ };
257045
+ }
257046
+ }
257047
+ return { allowed: true };
257048
+ }
256910
257049
 
256911
257050
  // src/sandbox/staging.ts
257051
+ import {
257052
+ copyFileSync,
257053
+ existsSync as existsSync7,
257054
+ mkdirSync as mkdirSync5,
257055
+ readdirSync,
257056
+ readFileSync as readFileSync5,
257057
+ rmSync as rmSync2,
257058
+ statSync as statSync3,
257059
+ writeFileSync as writeFileSync5
257060
+ } from "node:fs";
257061
+ import { createHash } from "node:crypto";
257062
+ import { dirname as dirname3, join as join7, relative } from "node:path";
256912
257063
  var KITT_DIR = ".kitt";
256913
257064
  var STAGING_DIR = "staging";
256914
257065
  function getStagingDir(workspaceDir) {
256915
- return join6(workspaceDir, KITT_DIR, STAGING_DIR);
257066
+ return join7(workspaceDir, KITT_DIR, STAGING_DIR);
256916
257067
  }
256917
257068
  function hashContent(content) {
256918
257069
  return createHash("sha256").update(content).digest("hex");
@@ -256929,7 +257080,7 @@ function countLines(content) {
256929
257080
  function collectStagedFilePaths(stagingDir, currentDir, output) {
256930
257081
  const entries = readdirSync(currentDir);
256931
257082
  for (const entry of entries) {
256932
- const absolutePath = join6(currentDir, entry);
257083
+ const absolutePath = join7(currentDir, entry);
256933
257084
  const stats = statSync3(absolutePath);
256934
257085
  if (stats.isDirectory()) {
256935
257086
  collectStagedFilePaths(stagingDir, absolutePath, output);
@@ -256942,36 +257093,36 @@ function collectStagedFilePaths(stagingDir, currentDir, output) {
256942
257093
  function clearStaging(workspaceDir) {
256943
257094
  const logger = createAuditLogger(workspaceDir);
256944
257095
  const stagingDir = getStagingDir(workspaceDir);
256945
- if (existsSync6(stagingDir)) {
257096
+ if (existsSync7(stagingDir)) {
256946
257097
  rmSync2(stagingDir, { recursive: true, force: true });
256947
257098
  }
256948
257099
  mkdirSync5(stagingDir, { recursive: true });
256949
- logger.staged(join6(KITT_DIR, STAGING_DIR), "cleared");
257100
+ logger.staged(join7(KITT_DIR, STAGING_DIR), "cleared");
256950
257101
  }
256951
257102
  function writeToStaging(workspaceDir, relativePath, content) {
256952
257103
  const logger = createAuditLogger(workspaceDir);
256953
257104
  const stagingDir = getStagingDir(workspaceDir);
256954
- const stagedPath = join6(stagingDir, relativePath);
257105
+ const stagedPath = join7(stagingDir, relativePath);
256955
257106
  assertWithinWorkspace(stagingDir, stagedPath);
256956
257107
  mkdirSync5(dirname3(stagedPath), { recursive: true });
256957
257108
  writeFileSync5(stagedPath, content, "utf-8");
256958
257109
  const hash = hashContent(content);
256959
257110
  logger.staged(relativePath, "written to staging");
256960
- logger.fileWrite(join6(KITT_DIR, STAGING_DIR, relativePath), hash);
257111
+ logger.fileWrite(join7(KITT_DIR, STAGING_DIR, relativePath), hash);
256961
257112
  }
256962
257113
  function listStagedFiles(workspaceDir) {
256963
257114
  const logger = createAuditLogger(workspaceDir);
256964
257115
  const stagingDir = getStagingDir(workspaceDir);
256965
- if (!existsSync6(stagingDir)) {
257116
+ if (!existsSync7(stagingDir)) {
256966
257117
  return [];
256967
257118
  }
256968
257119
  const filePaths = [];
256969
257120
  collectStagedFilePaths(stagingDir, stagingDir, filePaths);
256970
257121
  return filePaths.sort((a, b3) => a.localeCompare(b3)).map((stagedRelativePath) => {
256971
- const workspacePath = join6(workspaceDir, stagedRelativePath);
257122
+ const workspacePath = join7(workspaceDir, stagedRelativePath);
256972
257123
  assertWithinWorkspace(workspaceDir, workspacePath);
256973
- const content = readFileSync5(join6(stagingDir, stagedRelativePath), "utf-8");
256974
- const isNew = !existsSync6(workspacePath);
257124
+ const content = readFileSync5(join7(stagingDir, stagedRelativePath), "utf-8");
257125
+ const isNew = !existsSync7(workspacePath);
256975
257126
  const isModified = !isNew;
256976
257127
  logger.staged(stagedRelativePath, isNew ? "new" : "modified");
256977
257128
  return {
@@ -256994,8 +257145,8 @@ function applyStagedChanges(workspaceDir, stagedFiles) {
256994
257145
  const logger = createAuditLogger(workspaceDir);
256995
257146
  const stagingDir = getStagingDir(workspaceDir);
256996
257147
  for (const stagedFile of stagedFiles) {
256997
- const sourcePath = join6(stagingDir, stagedFile.relativePath);
256998
- const destinationPath = join6(workspaceDir, stagedFile.relativePath);
257148
+ const sourcePath = join7(stagingDir, stagedFile.relativePath);
257149
+ const destinationPath = join7(workspaceDir, stagedFile.relativePath);
256999
257150
  assertWithinWorkspace(workspaceDir, destinationPath);
257000
257151
  mkdirSync5(dirname3(destinationPath), { recursive: true });
257001
257152
  copyFileSync(sourcePath, destinationPath);
@@ -257115,7 +257266,7 @@ function createRateLimiter() {
257115
257266
  }
257116
257267
 
257117
257268
  // src/llm/client.ts
257118
- var auditLogger = createAuditLogger(".");
257269
+ var auditLogger2 = createAuditLogger(".");
257119
257270
  var DEFAULT_MAX_TOKENS = 8192;
257120
257271
  async function loadProvider(provider) {
257121
257272
  switch (provider) {
@@ -257159,17 +257310,17 @@ function ensureRateLimit(rateLimiter, provider, model, estimatedTokens) {
257159
257310
  if (check.allowed) {
257160
257311
  return;
257161
257312
  }
257162
- auditLogger.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "FAILED");
257313
+ auditLogger2.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "FAILED");
257163
257314
  throw new Error(check.reason ?? "LLM call limit reached for this session.");
257164
257315
  }
257165
257316
  async function executeWithAudit(options) {
257166
257317
  const { provider, model, estimatedTokens, rateLimiter, operation } = options;
257167
257318
  try {
257168
257319
  const response = await operation();
257169
- auditLogger.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "SUCCESS");
257320
+ auditLogger2.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "SUCCESS");
257170
257321
  return response;
257171
257322
  } catch (error4) {
257172
- auditLogger.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "FAILED");
257323
+ auditLogger2.llmCall(provider, model, PROMPT_VERSION, estimatedTokens, "FAILED");
257173
257324
  throw error4;
257174
257325
  } finally {
257175
257326
  rateLimiter.recordCall(estimatedTokens);
@@ -257915,7 +258066,7 @@ var CLIENT_INFO = {
257915
258066
  name: "openkitt",
257916
258067
  version: "0.1.0"
257917
258068
  };
257918
- var auditLogger2 = createAuditLogger(".");
258069
+ var auditLogger3 = createAuditLogger(".");
257919
258070
  function createJsonRpcError(code, message) {
257920
258071
  const error4 = new Error(message);
257921
258072
  error4.code = code;
@@ -258085,7 +258236,7 @@ async function createMcpClient(server2) {
258085
258236
  if (!isToolsListResult(result)) {
258086
258237
  throw new Error("Invalid tools/list response from MCP server");
258087
258238
  }
258088
- auditLogger2.mcp("tools/list", "{}", "SUCCESS");
258239
+ auditLogger3.mcp("tools/list", "{}", "SUCCESS");
258089
258240
  return result.tools;
258090
258241
  },
258091
258242
  async callTool(name, args) {
@@ -258100,12 +258251,12 @@ async function createMcpClient(server2) {
258100
258251
  throw new Error("Invalid tools/call response from MCP server");
258101
258252
  }
258102
258253
  const status = result.isError ? "FAILED" : "SUCCESS";
258103
- auditLogger2.mcp(name, paramsText, status, result.isError ? "tool returned isError=true" : undefined);
258254
+ auditLogger3.mcp(name, paramsText, status, result.isError ? "tool returned isError=true" : undefined);
258104
258255
  return result;
258105
258256
  } catch (requestError) {
258106
258257
  const error4 = requestError instanceof Error ? requestError : new Error(String(requestError));
258107
258258
  const detail = "code" in error4 ? `${String(error4.code)}: ${error4.message}` : error4.message;
258108
- auditLogger2.mcp(name, paramsText, "FAILED", detail);
258259
+ auditLogger3.mcp(name, paramsText, "FAILED", detail);
258109
258260
  throw error4;
258110
258261
  }
258111
258262
  },
@@ -258116,137 +258267,6 @@ async function createMcpClient(server2) {
258116
258267
  };
258117
258268
  }
258118
258269
 
258119
- // src/mcp/lifecycle.ts
258120
- import { spawn } from "node:child_process";
258121
- import { fileURLToPath } from "node:url";
258122
- import { dirname as dirname4, join as join7 } from "node:path";
258123
- var MCP_ENTRY_POINT = join7(dirname4(fileURLToPath(import.meta.url)), "..", "..", "node_modules", "@railway", "mcp-server", "dist", "index.js");
258124
- var MCP_START_FAILURE_MESSAGE = "Railway MCP Server failed to start. Try reinstalling: npm install -g openkitt@latest";
258125
- var SHUTDOWN_TIMEOUT_MS = 5000;
258126
- var auditLogger3 = createAuditLogger(".");
258127
- var activeServer = null;
258128
- var pendingSpawn = null;
258129
- var shouldLogRespawn = false;
258130
- var intentionallyShuttingDown = new WeakSet;
258131
- function formatExitDetail(code, signal) {
258132
- const codeLabel = code === null ? "null" : String(code);
258133
- const signalLabel = signal ?? "null";
258134
- return `code=${codeLabel}, signal=${signalLabel}`;
258135
- }
258136
- function isChildRunning(child) {
258137
- return child.exitCode === null && !child.killed;
258138
- }
258139
- function buildServerProcess(child) {
258140
- if (!child.stdin || !child.stdout) {
258141
- throw new Error("MCP server stdio was not created");
258142
- }
258143
- return {
258144
- process: child,
258145
- stdin: child.stdin,
258146
- stdout: child.stdout,
258147
- pid: child.pid ?? -1
258148
- };
258149
- }
258150
- function attachLifecycleListeners(child) {
258151
- child.stderr?.on("data", (chunk) => {
258152
- const message = String(chunk).trim();
258153
- if (!message) {
258154
- return;
258155
- }
258156
- auditLogger3.mcp("server-lifecycle", "stderr", "FAILED", message);
258157
- });
258158
- child.on("exit", (code, signal) => {
258159
- const detail = formatExitDetail(code, signal);
258160
- if (activeServer?.process === child) {
258161
- activeServer = null;
258162
- }
258163
- if (intentionallyShuttingDown.has(child)) {
258164
- return;
258165
- }
258166
- shouldLogRespawn = true;
258167
- auditLogger3.mcp("server-lifecycle", "crash", "FAILED", detail);
258168
- });
258169
- }
258170
- function displaySpawnFailure(reason) {
258171
- error(MCP_START_FAILURE_MESSAGE);
258172
- auditLogger3.mcp("server-lifecycle", "spawn", "FAILED", reason);
258173
- }
258174
- async function spawnMcpServer() {
258175
- if (activeServer && isChildRunning(activeServer.process)) {
258176
- return activeServer;
258177
- }
258178
- if (pendingSpawn) {
258179
- return pendingSpawn;
258180
- }
258181
- const respawn = shouldLogRespawn;
258182
- const child = spawn("node", [MCP_ENTRY_POINT], {
258183
- stdio: ["pipe", "pipe", "pipe"]
258184
- });
258185
- attachLifecycleListeners(child);
258186
- pendingSpawn = new Promise((resolve2, reject) => {
258187
- const handleError = (spawnError) => {
258188
- child.off("spawn", handleSpawn);
258189
- if (activeServer?.process === child) {
258190
- activeServer = null;
258191
- }
258192
- displaySpawnFailure(spawnError.message);
258193
- reject(spawnError);
258194
- };
258195
- const handleSpawn = () => {
258196
- child.off("error", handleError);
258197
- let serverProcess;
258198
- try {
258199
- serverProcess = buildServerProcess(child);
258200
- } catch (buildError) {
258201
- const err = buildError instanceof Error ? buildError : new Error(String(buildError));
258202
- displaySpawnFailure(err.message);
258203
- reject(err);
258204
- return;
258205
- }
258206
- activeServer = serverProcess;
258207
- shouldLogRespawn = false;
258208
- if (respawn) {
258209
- auditLogger3.mcp("server-lifecycle", "respawn", "SUCCESS", `pid=${serverProcess.pid}`);
258210
- } else {
258211
- auditLogger3.mcp("server-lifecycle", "spawn", "SUCCESS", `pid=${serverProcess.pid}`);
258212
- }
258213
- resolve2(serverProcess);
258214
- };
258215
- child.once("error", handleError);
258216
- child.once("spawn", handleSpawn);
258217
- }).finally(() => {
258218
- pendingSpawn = null;
258219
- });
258220
- return pendingSpawn;
258221
- }
258222
- async function shutdownMcpServer() {
258223
- if (!activeServer) {
258224
- return;
258225
- }
258226
- const child = activeServer.process;
258227
- intentionallyShuttingDown.add(child);
258228
- if (!isChildRunning(child)) {
258229
- activeServer = null;
258230
- return;
258231
- }
258232
- const exitPromise = new Promise((resolve2) => {
258233
- child.once("exit", (code, signal) => {
258234
- resolve2({ code, signal });
258235
- });
258236
- });
258237
- child.kill("SIGTERM");
258238
- let forcedKill = false;
258239
- const timeoutHandle = setTimeout(() => {
258240
- forcedKill = true;
258241
- child.kill("SIGKILL");
258242
- }, SHUTDOWN_TIMEOUT_MS);
258243
- const exitResult = await exitPromise;
258244
- clearTimeout(timeoutHandle);
258245
- activeServer = null;
258246
- const detail = forcedKill ? `forced after timeout (${formatExitDetail(exitResult.code, exitResult.signal)})` : formatExitDetail(exitResult.code, exitResult.signal);
258247
- auditLogger3.mcp("server-lifecycle", "shutdown", "SUCCESS", detail);
258248
- }
258249
-
258250
258270
  // src/scaffold/packages.ts
258251
258271
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
258252
258272
  import { join as join8 } from "node:path";
@@ -258393,7 +258413,7 @@ function scaffoldDefaultPackages(packagesDir) {
258393
258413
  }
258394
258414
 
258395
258415
  // src/utils/validation.ts
258396
- import { existsSync as existsSync7 } from "node:fs";
258416
+ import { existsSync as existsSync8 } from "node:fs";
258397
258417
  import { join as join9 } from "node:path";
258398
258418
  var APP_NAME_REGEX = /^[a-z][a-z0-9-]{1,48}[a-z0-9]$/;
258399
258419
  function validateAppName(name) {
@@ -258420,7 +258440,7 @@ function sanitizeInput(input) {
258420
258440
  function validateAppNameUniqueness(name, workspaceDir) {
258421
258441
  const manifest = readManifest(workspaceDir);
258422
258442
  const existsInManifest = manifest !== null && name in manifest.apps;
258423
- const existsInAppsDirectory = existsSync7(join9(workspaceDir, "apps", name));
258443
+ const existsInAppsDirectory = existsSync8(join9(workspaceDir, "apps", name));
258424
258444
  if (existsInManifest || existsInAppsDirectory) {
258425
258445
  return {
258426
258446
  valid: false,
@@ -258432,7 +258452,7 @@ function validateAppNameUniqueness(name, workspaceDir) {
258432
258452
 
258433
258453
  // src/versions/integrity.ts
258434
258454
  import { createHash as createHash2 } from "node:crypto";
258435
- import { chmodSync as chmodSync3, existsSync as existsSync8, readFileSync as readFileSync6, renameSync as renameSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync7 } from "node:fs";
258455
+ import { chmodSync as chmodSync3, existsSync as existsSync9, readFileSync as readFileSync6, renameSync as renameSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync7 } from "node:fs";
258436
258456
  import { platform as platform4 } from "node:os";
258437
258457
  import { join as join10 } from "node:path";
258438
258458
  var FILE_MODE3 = 384;
@@ -258467,7 +258487,7 @@ function writeVersionsLock(workspaceDir, hash) {
258467
258487
  chmodSync3(lockPath, FILE_MODE3);
258468
258488
  }
258469
258489
  } catch (error4) {
258470
- if (existsSync8(tempPath)) {
258490
+ if (existsSync9(tempPath)) {
258471
258491
  unlinkSync3(tempPath);
258472
258492
  }
258473
258493
  throw error4;
@@ -258921,7 +258941,7 @@ async function initCommand(context, _args) {
258921
258941
  }
258922
258942
 
258923
258943
  // src/commands/create.ts
258924
- import { existsSync as existsSync14, mkdirSync as mkdirSync10 } from "node:fs";
258944
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10 } from "node:fs";
258925
258945
  import { join as join18 } from "node:path";
258926
258946
  init_config();
258927
258947
 
@@ -262205,7 +262225,7 @@ async function executeCreateScaffolding(options) {
262205
262225
  }
262206
262226
 
262207
262227
  // src/sandbox/scanner.ts
262208
- import { existsSync as existsSync9, lstatSync, readFileSync as readFileSync8 } from "node:fs";
262228
+ import { existsSync as existsSync10, lstatSync, readFileSync as readFileSync8 } from "node:fs";
262209
262229
  import { extname, isAbsolute, join as join13, normalize, resolve as resolve3 } from "node:path";
262210
262230
  var ALLOWED_EXTENSIONS = new Set([
262211
262231
  ".ts",
@@ -262281,7 +262301,7 @@ function validateFilePath(filePath) {
262281
262301
  detail: "Path contains '..' segments and may escape the workspace"
262282
262302
  });
262283
262303
  }
262284
- if (existsSync9(filePath)) {
262304
+ if (existsSync10(filePath)) {
262285
262305
  const stats = lstatSync(filePath);
262286
262306
  if (stats.isSymbolicLink()) {
262287
262307
  warnings.push({
@@ -262390,8 +262410,8 @@ async function confirmAndApply(options) {
262390
262410
  // src/ast/engine.ts
262391
262411
  var import_ts_morph = __toESM(require_ts_morph(), 1);
262392
262412
  import { createHash as createHash3 } from "node:crypto";
262393
- import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync10 } from "node:fs";
262394
- import { dirname as dirname5, isAbsolute as isAbsolute2, join as join14, normalize as normalize2, relative as relative2, resolve as resolve4 } from "node:path";
262413
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, writeFileSync as writeFileSync10 } from "node:fs";
262414
+ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join14, normalize as normalize2, relative as relative2, resolve as resolve4 } from "node:path";
262395
262415
  var KITT_DIR2 = ".kitt";
262396
262416
  var STAGING_DIR2 = "staging";
262397
262417
  function hashContent2(content) {
@@ -262435,7 +262455,7 @@ function createAstEngine(workspaceDir) {
262435
262455
  if (!isRelativePathInside(workspaceDir, fullPath)) {
262436
262456
  throw new Error(`Path is outside workspace: ${relativePath}`);
262437
262457
  }
262438
- if (!existsSync10(fullPath)) {
262458
+ if (!existsSync11(fullPath)) {
262439
262459
  throw new Error(`File does not exist: ${relativePath}`);
262440
262460
  }
262441
262461
  const existing = project.getSourceFile(fullPath);
@@ -262450,7 +262470,7 @@ function createAstEngine(workspaceDir) {
262450
262470
  if (!isRelativePathInside(resolve4(workspaceDir, KITT_DIR2, STAGING_DIR2), stagingPath)) {
262451
262471
  throw new Error(`Refusing to write outside staging directory: ${relativePath}`);
262452
262472
  }
262453
- mkdirSync8(dirname5(stagingPath), { recursive: true });
262473
+ mkdirSync8(dirname4(stagingPath), { recursive: true });
262454
262474
  const fullText = sourceFile.getFullText();
262455
262475
  writeFileSync10(stagingPath, fullText, "utf-8");
262456
262476
  auditLogger4.staged(relativePath, "AST modified");
@@ -262823,7 +262843,7 @@ function applyOperation(sourceFile, operation) {
262823
262843
 
262824
262844
  // src/ast/validator.ts
262825
262845
  var import_ts_morph3 = __toESM(require_ts_morph(), 1);
262826
- import { existsSync as existsSync11 } from "node:fs";
262846
+ import { existsSync as existsSync12 } from "node:fs";
262827
262847
  import { extname as extname2, isAbsolute as isAbsolute3, normalize as normalize3, relative as relative3, resolve as resolve5 } from "node:path";
262828
262848
  var VALID_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx"]);
262829
262849
  var TARGET_FILE_OPERATION = { op: "targetFile" };
@@ -263010,7 +263030,7 @@ function validateTargetFile(workspaceDir, filePath) {
263010
263030
  message: `Path is outside workspace: ${filePath}`
263011
263031
  });
263012
263032
  }
263013
- if (!existsSync11(absoluteTargetPath)) {
263033
+ if (!existsSync12(absoluteTargetPath)) {
263014
263034
  errors.push({
263015
263035
  filePath,
263016
263036
  operation: TARGET_FILE_OPERATION,
@@ -263131,7 +263151,7 @@ function executeTransformPipeline(transforms, workspaceDir) {
263131
263151
  }
263132
263152
 
263133
263153
  // src/commands/create-pipeline.ts
263134
- import { execSync as execSync4 } from "node:child_process";
263154
+ import { execSync as execSync5 } from "node:child_process";
263135
263155
  import { join as join15 } from "node:path";
263136
263156
 
263137
263157
  // src/utils/pm.ts
@@ -263308,7 +263328,7 @@ function executeCommandPipeline(commands, options) {
263308
263328
  continue;
263309
263329
  }
263310
263330
  try {
263311
- execSync4(bare, { cwd, stdio: "inherit" });
263331
+ execSync5(bare, { cwd, stdio: "inherit" });
263312
263332
  results.push({
263313
263333
  command: cmd.command,
263314
263334
  purpose: cmd.purpose,
@@ -263391,13 +263411,13 @@ async function provisionInfrastructure(options) {
263391
263411
 
263392
263412
  // src/commands/run.ts
263393
263413
  import { spawn as spawn2 } from "node:child_process";
263394
- import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
263414
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "node:fs";
263395
263415
  import { join as join17 } from "node:path";
263396
263416
  var import_picocolors6 = __toESM(require_picocolors(), 1);
263397
263417
 
263398
263418
  // src/commands/settings.ts
263399
- import { execSync as execSync5 } from "node:child_process";
263400
- import { chmodSync as chmodSync5, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync5, rmSync as rmSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "node:fs";
263419
+ import { execSync as execSync6 } from "node:child_process";
263420
+ import { chmodSync as chmodSync5, existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync5, rmSync as rmSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync11 } from "node:fs";
263401
263421
  import { homedir as homedir3, platform as platform6 } from "node:os";
263402
263422
  import { join as join16 } from "node:path";
263403
263423
  var SUPPORTED_PACKAGE_MANAGERS = ["bun", "npm", "pnpm", "yarn"];
@@ -263415,7 +263435,7 @@ function isWindows4() {
263415
263435
  return platform6() === "win32";
263416
263436
  }
263417
263437
  function ensureConfigDir2() {
263418
- if (!existsSync12(CONFIG_DIR2)) {
263438
+ if (!existsSync13(CONFIG_DIR2)) {
263419
263439
  mkdirSync9(CONFIG_DIR2, { recursive: true, mode: DIR_MODE3 });
263420
263440
  }
263421
263441
  if (!isWindows4()) {
@@ -263427,7 +263447,7 @@ function isPackageManager(value) {
263427
263447
  }
263428
263448
  function readGlobalConfig2() {
263429
263449
  ensureConfigDir2();
263430
- if (!existsSync12(CONFIG_FILE2)) {
263450
+ if (!existsSync13(CONFIG_FILE2)) {
263431
263451
  return {};
263432
263452
  }
263433
263453
  const raw = readFileSync9(CONFIG_FILE2, "utf-8").trim();
@@ -263459,7 +263479,7 @@ function writeGlobalConfig2(config) {
263459
263479
  chmodSync5(CONFIG_FILE2, FILE_MODE4);
263460
263480
  }
263461
263481
  } catch (writeError) {
263462
- if (existsSync12(tempFile)) {
263482
+ if (existsSync13(tempFile)) {
263463
263483
  unlinkSync4(tempFile);
263464
263484
  }
263465
263485
  throw writeError;
@@ -263584,7 +263604,7 @@ async function maybeConfirmMigration(context, fromPm, toPm) {
263584
263604
  function migrateWorkspacePackageManager(workspaceDir, fromPm, toPm) {
263585
263605
  removePackageManagerArtifacts(workspaceDir, fromPm);
263586
263606
  writePackageManagerFiles(workspaceDir, toPm);
263587
- execSync5(getInstallCommand(toPm), { cwd: workspaceDir, stdio: "inherit" });
263607
+ execSync6(getInstallCommand(toPm), { cwd: workspaceDir, stdio: "inherit" });
263588
263608
  }
263589
263609
  async function runDisplayMode(workspaceDir) {
263590
263610
  const autoOpen = readAutoOpenBrowser();
@@ -263668,7 +263688,7 @@ async function settingsCommand(context, args) {
263668
263688
  var DEV_SCRIPT_CANDIDATES = ["dev", "start", "serve", "preview"];
263669
263689
  function resolveDevScript(appDir) {
263670
263690
  const pkgPath = join17(appDir, "package.json");
263671
- if (!existsSync13(pkgPath)) {
263691
+ if (!existsSync14(pkgPath)) {
263672
263692
  return { found: false, reason: "no-package-json", available: [] };
263673
263693
  }
263674
263694
  let pkg;
@@ -263955,7 +263975,7 @@ async function createCommand2(context, _args) {
263955
263975
  });
263956
263976
  logger.cmd("/create", "SUCCESS");
263957
263977
  success(`App ${selections.appName} created.`);
263958
- if (existsSync14(appDir)) {
263978
+ if (existsSync15(appDir)) {
263959
263979
  const runCmd = getCommand(manifest.workspace.packageManager, "run");
263960
263980
  const scriptResolution = resolveDevScript(appDir);
263961
263981
  if (scriptResolution.found) {
@@ -264054,7 +264074,7 @@ async function deleteCommand(context, args) {
264054
264074
  }
264055
264075
 
264056
264076
  // src/commands/deploy.ts
264057
- import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync13 } from "node:fs";
264077
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync13 } from "node:fs";
264058
264078
  import { basename as basename2, join as join20 } from "node:path";
264059
264079
  init_config();
264060
264080
 
@@ -264118,7 +264138,7 @@ function matchesGitignorePattern(filePath, pattern) {
264118
264138
  }
264119
264139
  function loadGitignorePatterns(workspaceDir) {
264120
264140
  const gitignorePath = join20(workspaceDir, ".gitignore");
264121
- if (!existsSync15(gitignorePath)) {
264141
+ if (!existsSync16(gitignorePath)) {
264122
264142
  return [];
264123
264143
  }
264124
264144
  return readFileSync11(gitignorePath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
@@ -264257,7 +264277,7 @@ restartPolicyMaxRetries = 3${deployEnv}`;
264257
264277
  }
264258
264278
  function ensureRailwayToml(appName, framework, packageManager) {
264259
264279
  const railwayTomlPath = join20("apps", appName, "railway.toml");
264260
- if (existsSync15(railwayTomlPath)) {
264280
+ if (existsSync16(railwayTomlPath)) {
264261
264281
  return false;
264262
264282
  }
264263
264283
  writeFileSync13(railwayTomlPath, generateRailwayToml(framework, packageManager), "utf-8");
@@ -264746,10 +264766,10 @@ var import_picocolors7 = __toESM(require_picocolors(), 1);
264746
264766
  init_config();
264747
264767
 
264748
264768
  // src/manifest/drift.ts
264749
- import { existsSync as existsSync16, readdirSync as readdirSync4 } from "node:fs";
264769
+ import { existsSync as existsSync17, readdirSync as readdirSync4 } from "node:fs";
264750
264770
  import { join as join21 } from "node:path";
264751
264771
  function listDirectories(parentDir) {
264752
- if (!existsSync16(parentDir)) {
264772
+ if (!existsSync17(parentDir)) {
264753
264773
  return [];
264754
264774
  }
264755
264775
  return readdirSync4(parentDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => left.localeCompare(right));
@@ -265084,7 +265104,7 @@ async function loginCommand(context, args, commandKey = "login") {
265084
265104
  }
265085
265105
 
265086
265106
  // src/commands/versions.ts
265087
- import { existsSync as existsSync17, readFileSync as readFileSync12, writeFileSync as writeFileSync14 } from "node:fs";
265107
+ import { existsSync as existsSync18, readFileSync as readFileSync12, writeFileSync as writeFileSync14 } from "node:fs";
265088
265108
  import { join as join22 } from "node:path";
265089
265109
  var import_picocolors9 = __toESM(require_picocolors(), 1);
265090
265110
  var TABLE_HEADER_INTEGRATION = "Integration";
@@ -265129,7 +265149,7 @@ function loadVersionsContext(logger) {
265129
265149
  return null;
265130
265150
  }
265131
265151
  const versionsPath = join22(workspaceDir, "versions.md");
265132
- if (!existsSync17(versionsPath)) {
265152
+ if (!existsSync18(versionsPath)) {
265133
265153
  error("versions.md not found in workspace root.");
265134
265154
  logger.cmd("/versions", "FAILED", "versions.md missing");
265135
265155
  return null;
@@ -265562,7 +265582,7 @@ async function helpCommand(_context, _args) {
265562
265582
  // package.json
265563
265583
  var package_default = {
265564
265584
  name: "openkitt",
265565
- version: "0.2.6",
265585
+ version: "0.2.7",
265566
265586
  description: "AI-powered monorepo scaffolding CLI",
265567
265587
  keywords: [
265568
265588
  "cli",
@@ -265606,7 +265626,6 @@ var package_default = {
265606
265626
  "@anthropic-ai/sdk": "^0.66.0",
265607
265627
  "@clack/prompts": "^0.11.0",
265608
265628
  "@google/generative-ai": "^0.24.1",
265609
- "@railway/mcp-server": "^0.1.8",
265610
265629
  commander: "^14.0.1",
265611
265630
  openai: "^6.6.0",
265612
265631
  picocolors: "^1.1.1",
@@ -265716,7 +265735,7 @@ function isVersionNewer(latest, current) {
265716
265735
  return false;
265717
265736
  }
265718
265737
  function hasFreshUpdateCache(now) {
265719
- if (!existsSync18(UPDATE_CHECK_FILE)) {
265738
+ if (!existsSync19(UPDATE_CHECK_FILE)) {
265720
265739
  return false;
265721
265740
  }
265722
265741
  try {
@@ -265872,7 +265891,7 @@ function resolvePrompt() {
265872
265891
  workspaceRoot = current;
265873
265892
  break;
265874
265893
  }
265875
- const parent = dirname6(current);
265894
+ const parent = dirname5(current);
265876
265895
  if (parent === current)
265877
265896
  break;
265878
265897
  current = parent;