@gemini-designer/mcp-server 0.1.0

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 (153) hide show
  1. package/.prettierrc +9 -0
  2. package/dist/components/catalog.d.ts +24 -0
  3. package/dist/components/catalog.d.ts.map +1 -0
  4. package/dist/components/catalog.js +186 -0
  5. package/dist/components/catalog.js.map +1 -0
  6. package/dist/config/index.d.ts +60 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +199 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/context/builder.d.ts +32 -0
  11. package/dist/context/builder.d.ts.map +1 -0
  12. package/dist/context/builder.js +194 -0
  13. package/dist/context/builder.js.map +1 -0
  14. package/dist/context/filter.d.ts +28 -0
  15. package/dist/context/filter.d.ts.map +1 -0
  16. package/dist/context/filter.js +136 -0
  17. package/dist/context/filter.js.map +1 -0
  18. package/dist/context/grounding.d.ts +27 -0
  19. package/dist/context/grounding.d.ts.map +1 -0
  20. package/dist/context/grounding.js +162 -0
  21. package/dist/context/grounding.js.map +1 -0
  22. package/dist/context/guards.d.ts +31 -0
  23. package/dist/context/guards.d.ts.map +1 -0
  24. package/dist/context/guards.js +76 -0
  25. package/dist/context/guards.js.map +1 -0
  26. package/dist/context/repo-hints.d.ts +12 -0
  27. package/dist/context/repo-hints.d.ts.map +1 -0
  28. package/dist/context/repo-hints.js +40 -0
  29. package/dist/context/repo-hints.js.map +1 -0
  30. package/dist/generation/gemini-client.d.ts +27 -0
  31. package/dist/generation/gemini-client.d.ts.map +1 -0
  32. package/dist/generation/gemini-client.js +64 -0
  33. package/dist/generation/gemini-client.js.map +1 -0
  34. package/dist/generation/litellm-client.d.ts +16 -0
  35. package/dist/generation/litellm-client.d.ts.map +1 -0
  36. package/dist/generation/litellm-client.js +98 -0
  37. package/dist/generation/litellm-client.js.map +1 -0
  38. package/dist/generation/remote-client.d.ts +20 -0
  39. package/dist/generation/remote-client.d.ts.map +1 -0
  40. package/dist/generation/remote-client.js +69 -0
  41. package/dist/generation/remote-client.js.map +1 -0
  42. package/dist/index.d.ts +9 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +30 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/output/file-writer.d.ts +39 -0
  47. package/dist/output/file-writer.d.ts.map +1 -0
  48. package/dist/output/file-writer.js +153 -0
  49. package/dist/output/file-writer.js.map +1 -0
  50. package/dist/output/formatter.d.ts +26 -0
  51. package/dist/output/formatter.d.ts.map +1 -0
  52. package/dist/output/formatter.js +156 -0
  53. package/dist/output/formatter.js.map +1 -0
  54. package/dist/server.d.ts +9 -0
  55. package/dist/server.d.ts.map +1 -0
  56. package/dist/server.js +22 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/stack/detect.d.ts +49 -0
  59. package/dist/stack/detect.d.ts.map +1 -0
  60. package/dist/stack/detect.js +157 -0
  61. package/dist/stack/detect.js.map +1 -0
  62. package/dist/tokens/sync.d.ts +32 -0
  63. package/dist/tokens/sync.d.ts.map +1 -0
  64. package/dist/tokens/sync.js +188 -0
  65. package/dist/tokens/sync.js.map +1 -0
  66. package/dist/tools/analyze-screenshot-ui.d.ts +18 -0
  67. package/dist/tools/analyze-screenshot-ui.d.ts.map +1 -0
  68. package/dist/tools/analyze-screenshot-ui.js +133 -0
  69. package/dist/tools/analyze-screenshot-ui.js.map +1 -0
  70. package/dist/tools/analyze-tokens.d.ts +10 -0
  71. package/dist/tools/analyze-tokens.d.ts.map +1 -0
  72. package/dist/tools/analyze-tokens.js +107 -0
  73. package/dist/tools/analyze-tokens.js.map +1 -0
  74. package/dist/tools/catalog-components.d.ts +14 -0
  75. package/dist/tools/catalog-components.d.ts.map +1 -0
  76. package/dist/tools/catalog-components.js +85 -0
  77. package/dist/tools/catalog-components.js.map +1 -0
  78. package/dist/tools/create-ui.d.ts +10 -0
  79. package/dist/tools/create-ui.d.ts.map +1 -0
  80. package/dist/tools/create-ui.js +167 -0
  81. package/dist/tools/create-ui.js.map +1 -0
  82. package/dist/tools/detect-ui-stack.d.ts +15 -0
  83. package/dist/tools/detect-ui-stack.d.ts.map +1 -0
  84. package/dist/tools/detect-ui-stack.js +52 -0
  85. package/dist/tools/detect-ui-stack.js.map +1 -0
  86. package/dist/tools/generate-component-variants.d.ts +15 -0
  87. package/dist/tools/generate-component-variants.d.ts.map +1 -0
  88. package/dist/tools/generate-component-variants.js +199 -0
  89. package/dist/tools/generate-component-variants.js.map +1 -0
  90. package/dist/tools/generate-vibes.d.ts +10 -0
  91. package/dist/tools/generate-vibes.d.ts.map +1 -0
  92. package/dist/tools/generate-vibes.js +145 -0
  93. package/dist/tools/generate-vibes.js.map +1 -0
  94. package/dist/tools/index.d.ts +12 -0
  95. package/dist/tools/index.d.ts.map +1 -0
  96. package/dist/tools/index.js +36 -0
  97. package/dist/tools/index.js.map +1 -0
  98. package/dist/tools/modify-ui.d.ts +11 -0
  99. package/dist/tools/modify-ui.d.ts.map +1 -0
  100. package/dist/tools/modify-ui.js +207 -0
  101. package/dist/tools/modify-ui.js.map +1 -0
  102. package/dist/tools/scaffold-project.d.ts +10 -0
  103. package/dist/tools/scaffold-project.d.ts.map +1 -0
  104. package/dist/tools/scaffold-project.js +122 -0
  105. package/dist/tools/scaffold-project.js.map +1 -0
  106. package/dist/tools/snippet-ui.d.ts +11 -0
  107. package/dist/tools/snippet-ui.d.ts.map +1 -0
  108. package/dist/tools/snippet-ui.js +194 -0
  109. package/dist/tools/snippet-ui.js.map +1 -0
  110. package/dist/tools/sync-design-tokens.d.ts +14 -0
  111. package/dist/tools/sync-design-tokens.d.ts.map +1 -0
  112. package/dist/tools/sync-design-tokens.js +233 -0
  113. package/dist/tools/sync-design-tokens.js.map +1 -0
  114. package/dist/utils/walk.d.ts +15 -0
  115. package/dist/utils/walk.d.ts.map +1 -0
  116. package/dist/utils/walk.js +63 -0
  117. package/dist/utils/walk.js.map +1 -0
  118. package/eslint.config.js +37 -0
  119. package/package.json +56 -0
  120. package/src/__tests__/builder.test.ts +31 -0
  121. package/src/__tests__/config.test.ts +52 -0
  122. package/src/__tests__/filter.test.ts +109 -0
  123. package/src/components/catalog.ts +214 -0
  124. package/src/config/index.ts +237 -0
  125. package/src/context/builder.ts +233 -0
  126. package/src/context/filter.ts +164 -0
  127. package/src/context/grounding.ts +191 -0
  128. package/src/context/guards.ts +94 -0
  129. package/src/context/repo-hints.ts +43 -0
  130. package/src/generation/gemini-client.ts +94 -0
  131. package/src/generation/litellm-client.ts +121 -0
  132. package/src/generation/remote-client.ts +103 -0
  133. package/src/index.ts +36 -0
  134. package/src/output/file-writer.ts +181 -0
  135. package/src/output/formatter.ts +186 -0
  136. package/src/server.ts +28 -0
  137. package/src/stack/detect.ts +204 -0
  138. package/src/tokens/sync.ts +212 -0
  139. package/src/tools/analyze-screenshot-ui.ts +150 -0
  140. package/src/tools/analyze-tokens.ts +123 -0
  141. package/src/tools/catalog-components.ts +99 -0
  142. package/src/tools/create-ui.ts +194 -0
  143. package/src/tools/detect-ui-stack.ts +64 -0
  144. package/src/tools/generate-component-variants.ts +218 -0
  145. package/src/tools/generate-vibes.ts +177 -0
  146. package/src/tools/index.ts +42 -0
  147. package/src/tools/modify-ui.ts +230 -0
  148. package/src/tools/scaffold-project.ts +138 -0
  149. package/src/tools/snippet-ui.ts +222 -0
  150. package/src/tools/sync-design-tokens.ts +256 -0
  151. package/src/utils/walk.ts +75 -0
  152. package/tsconfig.json +34 -0
  153. package/vitest.config.ts +15 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Path Guards
3
+ *
4
+ * Centralized helpers to validate and resolve file paths for tools.
5
+ *
6
+ * Goals:
7
+ * - Prevent accidental reads/writes outside the workspace
8
+ * - Avoid including sensitive files (e.g. .env, private keys)
9
+ * - Provide consistent absolute-path resolution
10
+ */
11
+ import * as fs from 'node:fs';
12
+ import * as path from 'node:path';
13
+ import { isPathAllowed, isSensitiveFile } from './filter.js';
14
+ /**
15
+ * Resolve a path to an absolute path (relative paths are resolved from process.cwd()).
16
+ */
17
+ export function resolveToAbs(filePath) {
18
+ return path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath);
19
+ }
20
+ /**
21
+ * Validate that a path is safe to read according to server config.
22
+ * Returns the resolved absolute path.
23
+ */
24
+ export function assertReadablePath(filePath, config) {
25
+ const absPath = resolveToAbs(filePath);
26
+ if (!isPathAllowed(absPath, config.allowedPaths)) {
27
+ throw new Error(`Path is outside allowedPaths: ${filePath}`);
28
+ }
29
+ if (isSensitiveFile(absPath)) {
30
+ throw new Error(`Refusing to read sensitive file: ${filePath}`);
31
+ }
32
+ if (!fs.existsSync(absPath)) {
33
+ throw new Error(`File not found: ${filePath}`);
34
+ }
35
+ const stat = fs.statSync(absPath);
36
+ if (!stat.isFile()) {
37
+ throw new Error(`Not a file: ${filePath}`);
38
+ }
39
+ return absPath;
40
+ }
41
+ /**
42
+ * Validate that a path is safe to write according to server config.
43
+ * Returns the resolved absolute path.
44
+ */
45
+ export function assertWritablePath(filePath, config) {
46
+ const absPath = resolveToAbs(filePath);
47
+ if (!isPathAllowed(absPath, config.allowedPaths)) {
48
+ throw new Error(`Path is outside allowedPaths: ${filePath}`);
49
+ }
50
+ if (isSensitiveFile(absPath)) {
51
+ throw new Error(`Refusing to write to sensitive path: ${filePath}`);
52
+ }
53
+ return absPath;
54
+ }
55
+ /**
56
+ * Validate that a directory path is safe to read according to server config.
57
+ * Returns the resolved absolute path.
58
+ */
59
+ export function assertReadableDir(dirPath, config) {
60
+ const absPath = resolveToAbs(dirPath);
61
+ if (!isPathAllowed(absPath, config.allowedPaths)) {
62
+ throw new Error(`Path is outside allowedPaths: ${dirPath}`);
63
+ }
64
+ if (isSensitiveFile(absPath)) {
65
+ throw new Error(`Refusing to read sensitive directory: ${dirPath}`);
66
+ }
67
+ if (!fs.existsSync(absPath)) {
68
+ throw new Error(`Directory not found: ${dirPath}`);
69
+ }
70
+ const stat = fs.statSync(absPath);
71
+ if (!stat.isDirectory()) {
72
+ throw new Error(`Not a directory: ${dirPath}`);
73
+ }
74
+ return absPath;
75
+ }
76
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/context/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7D;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IACzC,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;AACxF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAc;IAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAc;IAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,wCAAwC,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,MAAc;IAC7D,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Repo Hints
3
+ *
4
+ * Very small, deterministic context that can be injected into LLM prompts
5
+ * to significantly improve output quality while avoiding big token burns.
6
+ *
7
+ * - Detects framework + styling + common libs
8
+ * - Does NOT include file contents
9
+ */
10
+ import { Config } from '../config/index.js';
11
+ export declare function buildRepoHints(config: Config, rootDir?: string): string;
12
+ //# sourceMappingURL=repo-hints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-hints.d.ts","sourceRoot":"","sources":["../../src/context/repo-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG5C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,MAAsB,GAAG,MAAM,CA4BtF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Repo Hints
3
+ *
4
+ * Very small, deterministic context that can be injected into LLM prompts
5
+ * to significantly improve output quality while avoiding big token burns.
6
+ *
7
+ * - Detects framework + styling + common libs
8
+ * - Does NOT include file contents
9
+ */
10
+ import * as path from 'node:path';
11
+ import { detectUiStack } from '../stack/detect.js';
12
+ export function buildRepoHints(config, rootDir = process.cwd()) {
13
+ try {
14
+ const stack = detectUiStack(rootDir);
15
+ const hints = {
16
+ root: path.basename(stack.root),
17
+ framework: stack.framework,
18
+ typescript: stack.language.typescript,
19
+ styling: stack.styling,
20
+ uiLibraries: stack.uiLibraries,
21
+ iconLibraries: stack.iconLibraries,
22
+ tooling: stack.tooling,
23
+ conventions: {
24
+ srcDir: stack.conventions.srcDir,
25
+ hasAppDir: stack.conventions.hasAppDir,
26
+ hasPagesDir: stack.conventions.hasPagesDir,
27
+ tsconfigPaths: stack.conventions.tsconfigPaths,
28
+ },
29
+ };
30
+ return `REPO_HINTS (deterministic):\n${JSON.stringify(hints, null, 2)}`;
31
+ }
32
+ catch (error) {
33
+ if (config.debug) {
34
+ const msg = error instanceof Error ? error.message : 'unknown error';
35
+ console.error('[repo-hints] Failed to detect stack:', msg);
36
+ }
37
+ return '';
38
+ }
39
+ }
40
+ //# sourceMappingURL=repo-hints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-hints.js","sourceRoot":"","sources":["../../src/context/repo-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,UAAkB,OAAO,CAAC,GAAG,EAAE;IAC1E,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAErC,MAAM,KAAK,GAAG;YACV,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAC/B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU;YACrC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,WAAW,EAAE;gBACT,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;gBAChC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,SAAS;gBACtC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,WAAW;gBAC1C,aAAa,EAAE,KAAK,CAAC,WAAW,CAAC,aAAa;aACjD;SACJ,CAAC;QAEF,OAAO,gCAAgC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Gemini API Client
3
+ *
4
+ * Handles direct communication with Google Gemini API.
5
+ * Used in local mode with user's own API key.
6
+ */
7
+ import { Config } from '../config/index.js';
8
+ export type GeminiUserContent = string | Array<{
9
+ text: string;
10
+ } | {
11
+ inlineData: {
12
+ mimeType: string;
13
+ data: string;
14
+ };
15
+ }>;
16
+ export interface GenerateOptions {
17
+ toolName?: string;
18
+ }
19
+ /**
20
+ * Generate content using Gemini
21
+ */
22
+ export declare function generateWithGemini(config: Config, systemPrompt: string, userPrompt: GeminiUserContent, options?: GenerateOptions): Promise<string>;
23
+ /**
24
+ * Count tokens for a given text (useful for quota tracking)
25
+ */
26
+ export declare function countTokens(config: Config, text: string): Promise<number>;
27
+ //# sourceMappingURL=gemini-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-client.d.ts","sourceRoot":"","sources":["../../src/generation/gemini-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,MAAM,iBAAiB,GACvB,MAAM,GACN,KAAK,CACC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CACvD,CAAC;AAKR,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD;;GAEG;AACH,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,iBAAiB,EAC7B,OAAO,CAAC,EAAE,eAAe,GAC1B,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS/E"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Gemini API Client
3
+ *
4
+ * Handles direct communication with Google Gemini API.
5
+ * Used in local mode with user's own API key.
6
+ */
7
+ import { GoogleGenerativeAI } from '@google/generative-ai';
8
+ // Cache the client instance
9
+ let genAI = null;
10
+ /**
11
+ * Get or create the Gemini client
12
+ */
13
+ function getClient(config) {
14
+ if (!config.apiKey) {
15
+ throw new Error('Gemini API key not configured. Set GEMINI_API_KEY environment variable.');
16
+ }
17
+ if (!genAI) {
18
+ genAI = new GoogleGenerativeAI(config.apiKey);
19
+ }
20
+ return genAI;
21
+ }
22
+ /**
23
+ * Generate content using Gemini
24
+ */
25
+ export async function generateWithGemini(config, systemPrompt, userPrompt, options) {
26
+ // If remote mode, delegate to remote client
27
+ if (config.mode === 'remote') {
28
+ const { generateWithRemote } = await import('./remote-client.js');
29
+ return generateWithRemote(config, systemPrompt, userPrompt, options?.toolName);
30
+ }
31
+ // If local mode is configured to use an OpenAI-compatible proxy (e.g. LiteLLM)
32
+ if (config.localProvider === 'litellm') {
33
+ const { generateWithLiteLLM } = await import('./litellm-client.js');
34
+ return generateWithLiteLLM(config, systemPrompt, userPrompt, options?.toolName);
35
+ }
36
+ const client = getClient(config);
37
+ // Use model from config (default: gemini-2.5-flash-lite)
38
+ const model = client.getGenerativeModel({
39
+ model: config.model,
40
+ systemInstruction: systemPrompt,
41
+ });
42
+ const result = await model.generateContent(userPrompt);
43
+ const response = result.response;
44
+ const text = response.text();
45
+ if (config.debug) {
46
+ console.error('[gemini] Tool:', options?.toolName || '(unknown)');
47
+ console.error('[gemini] Response length:', text.length);
48
+ console.error('[gemini] Usage:', response.usageMetadata);
49
+ }
50
+ return text;
51
+ }
52
+ /**
53
+ * Count tokens for a given text (useful for quota tracking)
54
+ */
55
+ export async function countTokens(config, text) {
56
+ if (config.localProvider === 'litellm') {
57
+ throw new Error('countTokens is not supported when localProvider=litellm');
58
+ }
59
+ const client = getClient(config);
60
+ const model = client.getGenerativeModel({ model: config.model });
61
+ const result = await model.countTokens(text);
62
+ return result.totalTokens;
63
+ }
64
+ //# sourceMappingURL=gemini-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-client.js","sourceRoot":"","sources":["../../src/generation/gemini-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAU3D,4BAA4B;AAC5B,IAAI,KAAK,GAA8B,IAAI,CAAC;AAM5C;;GAEG;AACH,SAAS,SAAS,CAAC,MAAc;IAC7B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC/F,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,KAAK,GAAG,IAAI,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACpC,MAAc,EACd,YAAoB,EACpB,UAA6B,EAC7B,OAAyB;IAEzB,4CAA4C;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAClE,OAAO,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnF,CAAC;IAED,+EAA+E;IAC/E,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACpE,OAAO,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC,yDAAyD;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,iBAAiB,EAAE,YAAY;KAClC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,UAAiB,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE7B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,QAAQ,IAAI,WAAW,CAAC,CAAC;QAClE,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxD,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,IAAY;IAC1D,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAEjE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,WAAW,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * LiteLLM (OpenAI-compatible) Client
3
+ *
4
+ * This client allows running the MCP server in local mode while routing
5
+ * requests through a self-hosted LiteLLM instance.
6
+ *
7
+ * Why LiteLLM?
8
+ * - Key management / key rotation
9
+ * - Load balancing across multiple upstream API keys
10
+ * - Unified OpenAI-compatible interface
11
+ * - Optional caching / retries / budgets
12
+ */
13
+ import { Config } from '../config/index.js';
14
+ import type { GeminiUserContent } from './gemini-client.js';
15
+ export declare function generateWithLiteLLM(config: Config, systemPrompt: string, userContent: GeminiUserContent, toolName?: string): Promise<string>;
16
+ //# sourceMappingURL=litellm-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"litellm-client.d.ts","sourceRoot":"","sources":["../../src/generation/litellm-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA0C5D,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,iBAAiB,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA2DjB"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * LiteLLM (OpenAI-compatible) Client
3
+ *
4
+ * This client allows running the MCP server in local mode while routing
5
+ * requests through a self-hosted LiteLLM instance.
6
+ *
7
+ * Why LiteLLM?
8
+ * - Key management / key rotation
9
+ * - Load balancing across multiple upstream API keys
10
+ * - Unified OpenAI-compatible interface
11
+ * - Optional caching / retries / budgets
12
+ */
13
+ function normalizeBaseUrl(baseUrl) {
14
+ const trimmed = baseUrl.replace(/\/+$/, '');
15
+ // Allow users to provide either http://host:port or http://host:port/v1
16
+ if (trimmed.endsWith('/v1'))
17
+ return trimmed;
18
+ return `${trimmed}/v1`;
19
+ }
20
+ function inferMimeTypeFromInlineData(mimeType) {
21
+ // LiteLLM expects a data URL. Ensure mime type is reasonable.
22
+ if (!mimeType || !mimeType.includes('/'))
23
+ return 'application/octet-stream';
24
+ return mimeType;
25
+ }
26
+ function toOpenAIUserContent(userContent) {
27
+ if (typeof userContent === 'string')
28
+ return userContent;
29
+ const parts = [];
30
+ for (const part of userContent) {
31
+ if ('text' in part) {
32
+ parts.push({ type: 'text', text: part.text });
33
+ continue;
34
+ }
35
+ if ('inlineData' in part) {
36
+ const mime = inferMimeTypeFromInlineData(part.inlineData.mimeType);
37
+ const url = `data:${mime};base64,${part.inlineData.data}`;
38
+ parts.push({ type: 'image_url', image_url: { url } });
39
+ continue;
40
+ }
41
+ }
42
+ // If the model only received one text part, prefer string (cheaper payload)
43
+ if (parts.length === 1 && parts[0].type === 'text')
44
+ return parts[0].text;
45
+ return parts;
46
+ }
47
+ export async function generateWithLiteLLM(config, systemPrompt, userContent, toolName) {
48
+ if (!config.litellmEndpoint) {
49
+ throw new Error('LiteLLM endpoint not configured. Set LITELLM_ENDPOINT.');
50
+ }
51
+ const baseUrl = normalizeBaseUrl(config.litellmEndpoint);
52
+ const url = `${baseUrl}/chat/completions`;
53
+ const model = config.litellmModel || config.model;
54
+ const body = {
55
+ model,
56
+ messages: [
57
+ { role: 'system', content: systemPrompt },
58
+ { role: 'user', content: toOpenAIUserContent(userContent) },
59
+ ],
60
+ // Keep default-ish sampling. Let downstream agents control via prompts.
61
+ temperature: 0.2,
62
+ };
63
+ const headers = {
64
+ 'Content-Type': 'application/json',
65
+ };
66
+ if (config.litellmApiKey) {
67
+ headers.Authorization = `Bearer ${config.litellmApiKey}`;
68
+ }
69
+ const resp = await fetch(url, {
70
+ method: 'POST',
71
+ headers,
72
+ body: JSON.stringify(body),
73
+ });
74
+ if (!resp.ok) {
75
+ const text = await resp.text();
76
+ throw new Error(`LiteLLM error (${resp.status}): ${text}`);
77
+ }
78
+ const data = (await resp.json());
79
+ const content = data?.choices?.[0]?.message?.content;
80
+ if (config.debug) {
81
+ const usage = data?.usage;
82
+ console.error('[litellm] Tool:', toolName || '(unknown)');
83
+ if (usage)
84
+ console.error('[litellm] Usage:', usage);
85
+ console.error('[litellm] Model:', data?.model || model);
86
+ }
87
+ if (typeof content === 'string')
88
+ return content;
89
+ // Some providers return arrays; stringify safely.
90
+ if (Array.isArray(content)) {
91
+ return content
92
+ .map((p) => (typeof p === 'string' ? p : (p?.text ?? '')))
93
+ .filter(Boolean)
94
+ .join('');
95
+ }
96
+ return '';
97
+ }
98
+ //# sourceMappingURL=litellm-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"litellm-client.js","sourceRoot":"","sources":["../../src/generation/litellm-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Remote Gateway Client
3
+ *
4
+ * Handles communication with the VPS gateway for remote mode.
5
+ * Transmits only sanitized context to protect user secrets.
6
+ */
7
+ import { Config } from '../config/index.js';
8
+ import type { GeminiUserContent } from './gemini-client.js';
9
+ /**
10
+ * Generate content via remote gateway
11
+ */
12
+ export declare function generateWithRemote(config: Config, systemPrompt: string, userPrompt: GeminiUserContent, toolName?: string): Promise<string>;
13
+ /**
14
+ * Check remaining quota with the gateway
15
+ */
16
+ export declare function checkQuota(config: Config): Promise<{
17
+ remaining: number;
18
+ limit: number;
19
+ }>;
20
+ //# sourceMappingURL=remote-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-client.d.ts","sourceRoot":"","sources":["../../src/generation/remote-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAkB5D;;GAEG;AACH,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,iBAAiB,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA+CjB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB9F"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Remote Gateway Client
3
+ *
4
+ * Handles communication with the VPS gateway for remote mode.
5
+ * Transmits only sanitized context to protect user secrets.
6
+ */
7
+ /**
8
+ * Generate content via remote gateway
9
+ */
10
+ export async function generateWithRemote(config, systemPrompt, userPrompt, toolName) {
11
+ if (!config.remoteEndpoint) {
12
+ throw new Error('Remote endpoint not configured');
13
+ }
14
+ if (!config.remoteApiKey) {
15
+ throw new Error('Remote API key not configured');
16
+ }
17
+ const request = {
18
+ systemPrompt,
19
+ toolName,
20
+ };
21
+ if (typeof userPrompt === 'string') {
22
+ request.userPrompt = userPrompt;
23
+ }
24
+ else {
25
+ request.userParts = userPrompt;
26
+ }
27
+ const response = await fetch(`${config.remoteEndpoint}/generate`, {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ Authorization: `Bearer ${config.remoteApiKey}`,
32
+ },
33
+ body: JSON.stringify(request),
34
+ });
35
+ if (!response.ok) {
36
+ const errorText = await response.text();
37
+ throw new Error(`Gateway error (${response.status}): ${errorText}`);
38
+ }
39
+ const data = (await response.json());
40
+ if (data.error) {
41
+ throw new Error(`Gateway error: ${data.error}`);
42
+ }
43
+ if (config.debug) {
44
+ console.error('[remote] Tokens used:', data.tokensUsed);
45
+ if (typeof data.inputTokens === 'number')
46
+ console.error('[remote] Input tokens:', data.inputTokens);
47
+ if (data.model)
48
+ console.error('[remote] Model:', data.model);
49
+ }
50
+ return data.content;
51
+ }
52
+ /**
53
+ * Check remaining quota with the gateway
54
+ */
55
+ export async function checkQuota(config) {
56
+ if (!config.remoteEndpoint || !config.remoteApiKey) {
57
+ throw new Error('Remote configuration missing');
58
+ }
59
+ const response = await fetch(`${config.remoteEndpoint}/quota`, {
60
+ headers: {
61
+ Authorization: `Bearer ${config.remoteApiKey}`,
62
+ },
63
+ });
64
+ if (!response.ok) {
65
+ throw new Error(`Failed to check quota: ${response.status}`);
66
+ }
67
+ return (await response.json());
68
+ }
69
+ //# sourceMappingURL=remote-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-client.js","sourceRoot":"","sources":["../../src/generation/remote-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACpC,MAAc,EACd,YAAoB,EACpB,UAA6B,EAC7B,QAAiB;IAEjB,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,OAAO,GAAmB;QAC5B,YAAY;QACZ,QAAQ;KACX,CAAC;IAEF,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,UAAU,GAAG,UAAU,CAAC;IACpC,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,SAAS,GAAG,UAAiB,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,cAAc,WAAW,EAAE;QAC9D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACL,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE;SACjD;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAChC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAoB,CAAC;IAExD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;YAAE,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACpG,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc;IAC3C,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,cAAc,QAAQ,EAAE;QAC3D,OAAO,EAAE;YACL,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE;SACjD;KACJ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyC,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Gemini Designer MCP - Entry Point
4
+ *
5
+ * Open-source MCP server for design-to-code generation.
6
+ * Supports both local (BYO API key) and remote gateway modes.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Gemini Designer MCP - Entry Point
4
+ *
5
+ * Open-source MCP server for design-to-code generation.
6
+ * Supports both local (BYO API key) and remote gateway modes.
7
+ */
8
+ import { createServer } from './server.js';
9
+ import { loadConfig } from './config/index.js';
10
+ async function main() {
11
+ const config = loadConfig();
12
+ console.error(`[gemini-designer-mcp] Starting in ${config.mode} mode...`);
13
+ const server = await createServer(config);
14
+ // Handle graceful shutdown
15
+ process.on('SIGINT', async () => {
16
+ console.error('[gemini-designer-mcp] Shutting down...');
17
+ await server.close();
18
+ process.exit(0);
19
+ });
20
+ process.on('SIGTERM', async () => {
21
+ console.error('[gemini-designer-mcp] Shutting down...');
22
+ await server.close();
23
+ process.exit(0);
24
+ });
25
+ }
26
+ main().catch((error) => {
27
+ console.error('[gemini-designer-mcp] Fatal error:', error);
28
+ process.exit(1);
29
+ });
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,KAAK,UAAU,IAAI;IACf,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,OAAO,CAAC,KAAK,CAAC,qCAAqC,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC;IAE1E,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAE1C,2BAA2B;IAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC5B,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC7B,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * File Writer
3
+ *
4
+ * Writes generated code to files with safety checks.
5
+ * Supports backup creation and git-aware operations.
6
+ */
7
+ export interface WriteOptions {
8
+ backup?: boolean;
9
+ format?: boolean;
10
+ createDirs?: boolean;
11
+ gitAdd?: boolean;
12
+ }
13
+ export interface WriteResult {
14
+ success: boolean;
15
+ filePath: string;
16
+ backupPath?: string;
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Write content to file with safety features
21
+ */
22
+ export declare function writeFile(filePath: string, content: string, options?: WriteOptions): Promise<WriteResult>;
23
+ /**
24
+ * Restore file from backup
25
+ */
26
+ export declare function restoreFromBackup(filePath: string): boolean;
27
+ /**
28
+ * Get git status for a file
29
+ */
30
+ export declare function getGitStatus(filePath: string): 'modified' | 'untracked' | 'clean' | 'not-git';
31
+ /**
32
+ * List all backup files in a directory
33
+ */
34
+ export declare function listBackups(directory: string): string[];
35
+ /**
36
+ * Clean up old backup files
37
+ */
38
+ export declare function cleanBackups(directory: string): number;
39
+ //# sourceMappingURL=file-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/output/file-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,YAAY;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAuDtB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAe3D;AAiBD;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,CAmB7F;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CASvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CActD"}