@enfyra/mcp-server 0.1.69 → 0.1.71

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 (248) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/config-local-adapters.d.ts +18 -0
  3. package/dist/lib/config-local-adapters.js +271 -0
  4. package/dist/lib/config-local-adapters.js.map +1 -0
  5. package/dist/lib/config-local-contracts.d.ts +28 -0
  6. package/dist/lib/config-local-contracts.js +200 -0
  7. package/dist/lib/config-local-contracts.js.map +1 -0
  8. package/dist/lib/config-local-prompts.d.ts +10 -0
  9. package/dist/lib/config-local-prompts.js +185 -0
  10. package/dist/lib/config-local-prompts.js.map +1 -0
  11. package/dist/lib/config-local-types.d.ts +23 -0
  12. package/dist/lib/config-local-types.js +2 -0
  13. package/dist/lib/config-local-types.js.map +1 -0
  14. package/dist/lib/config-local.js +3 -649
  15. package/dist/lib/config-local.js.map +1 -1
  16. package/dist/lib/discovery-tools.d.ts +4 -0
  17. package/dist/lib/discovery-tools.js +546 -0
  18. package/dist/lib/discovery-tools.js.map +1 -0
  19. package/dist/lib/dynamic-repository-builder.d.ts +1 -1
  20. package/dist/lib/dynamic-script-context-contract.d.ts +100 -0
  21. package/dist/lib/dynamic-script-context-contract.js +163 -0
  22. package/dist/lib/dynamic-script-context-contract.js.map +1 -0
  23. package/dist/lib/enfyra-mcp-server.d.ts +3 -0
  24. package/dist/lib/enfyra-mcp-server.js +79 -0
  25. package/dist/lib/enfyra-mcp-server.js.map +1 -0
  26. package/dist/lib/enfyra-tool-logic.d.ts +7 -0
  27. package/dist/lib/enfyra-tool-logic.js +8 -0
  28. package/dist/lib/enfyra-tool-logic.js.map +1 -0
  29. package/dist/lib/enfyra-tool-types.d.ts +27 -0
  30. package/dist/lib/enfyra-tool-types.js +2 -0
  31. package/dist/lib/enfyra-tool-types.js.map +1 -0
  32. package/dist/lib/extension-api-builders.d.ts +17 -0
  33. package/dist/lib/extension-api-builders.js +235 -0
  34. package/dist/lib/extension-api-builders.js.map +1 -0
  35. package/dist/lib/extension-component-builders.d.ts +87 -0
  36. package/dist/lib/extension-component-builders.js +623 -0
  37. package/dist/lib/extension-component-builders.js.map +1 -0
  38. package/dist/lib/extension-contract-review.d.ts +26 -0
  39. package/dist/lib/extension-contract-review.js +187 -0
  40. package/dist/lib/extension-contract-review.js.map +1 -0
  41. package/dist/lib/extension-theme-contract.d.ts +63 -0
  42. package/dist/lib/extension-theme-contract.js +417 -0
  43. package/dist/lib/extension-theme-contract.js.map +1 -0
  44. package/dist/lib/identity-tools.d.ts +4 -0
  45. package/dist/lib/identity-tools.js +46 -0
  46. package/dist/lib/identity-tools.js.map +1 -0
  47. package/dist/lib/log-tools.d.ts +4 -0
  48. package/dist/lib/log-tools.js +65 -0
  49. package/dist/lib/log-tools.js.map +1 -0
  50. package/dist/lib/mcp-example-connect.d.ts +9 -0
  51. package/dist/lib/mcp-example-connect.js +442 -0
  52. package/dist/lib/mcp-example-connect.js.map +1 -0
  53. package/dist/lib/mcp-example-extensions.d.ts +9 -0
  54. package/dist/lib/mcp-example-extensions.js +729 -0
  55. package/dist/lib/mcp-example-extensions.js.map +1 -0
  56. package/dist/lib/mcp-example-files.d.ts +9 -0
  57. package/dist/lib/mcp-example-files.js +51 -0
  58. package/dist/lib/mcp-example-files.js.map +1 -0
  59. package/dist/lib/mcp-example-flows.d.ts +9 -0
  60. package/dist/lib/mcp-example-flows.js +76 -0
  61. package/dist/lib/mcp-example-flows.js.map +1 -0
  62. package/dist/lib/mcp-example-graphql.d.ts +9 -0
  63. package/dist/lib/mcp-example-graphql.js +57 -0
  64. package/dist/lib/mcp-example-graphql.js.map +1 -0
  65. package/dist/lib/mcp-example-handlers-hooks.d.ts +9 -0
  66. package/dist/lib/mcp-example-handlers-hooks.js +328 -0
  67. package/dist/lib/mcp-example-handlers-hooks.js.map +1 -0
  68. package/dist/lib/mcp-example-oauth-setup.d.ts +9 -0
  69. package/dist/lib/mcp-example-oauth-setup.js +41 -0
  70. package/dist/lib/mcp-example-oauth-setup.js.map +1 -0
  71. package/dist/lib/mcp-example-permissions-rls.d.ts +9 -0
  72. package/dist/lib/mcp-example-permissions-rls.js +210 -0
  73. package/dist/lib/mcp-example-permissions-rls.js.map +1 -0
  74. package/dist/lib/mcp-example-queries-deep.d.ts +9 -0
  75. package/dist/lib/mcp-example-queries-deep.js +220 -0
  76. package/dist/lib/mcp-example-queries-deep.js.map +1 -0
  77. package/dist/lib/mcp-example-schema-relations.d.ts +9 -0
  78. package/dist/lib/mcp-example-schema-relations.js +148 -0
  79. package/dist/lib/mcp-example-schema-relations.js.map +1 -0
  80. package/dist/lib/mcp-example-websocket.d.ts +9 -0
  81. package/dist/lib/mcp-example-websocket.js +103 -0
  82. package/dist/lib/mcp-example-websocket.js.map +1 -0
  83. package/dist/lib/mcp-examples.d.ts +5 -5
  84. package/dist/lib/mcp-examples.js +22 -2394
  85. package/dist/lib/mcp-examples.js.map +1 -1
  86. package/dist/lib/method-tools.d.ts +4 -0
  87. package/dist/lib/method-tools.js +217 -0
  88. package/dist/lib/method-tools.js.map +1 -0
  89. package/dist/lib/package-tools.d.ts +4 -0
  90. package/dist/lib/package-tools.js +98 -0
  91. package/dist/lib/package-tools.js.map +1 -0
  92. package/dist/lib/platform-data-operations.d.ts +24 -0
  93. package/dist/lib/platform-data-operations.js +71 -0
  94. package/dist/lib/platform-data-operations.js.map +1 -0
  95. package/dist/lib/platform-endpoint-workflow.d.ts +42 -0
  96. package/dist/lib/platform-endpoint-workflow.js +382 -0
  97. package/dist/lib/platform-endpoint-workflow.js.map +1 -0
  98. package/dist/lib/platform-extension-source.d.ts +487 -0
  99. package/dist/lib/platform-extension-source.js +524 -0
  100. package/dist/lib/platform-extension-source.js.map +1 -0
  101. package/dist/lib/platform-extension-tools.d.ts +1 -0
  102. package/dist/lib/platform-extension-tools.js +416 -0
  103. package/dist/lib/platform-extension-tools.js.map +1 -0
  104. package/dist/lib/platform-extension-ui.d.ts +4 -0
  105. package/dist/lib/platform-extension-ui.js +5 -0
  106. package/dist/lib/platform-extension-ui.js.map +1 -0
  107. package/dist/lib/platform-extension-workflow.d.ts +54 -0
  108. package/dist/lib/platform-extension-workflow.js +194 -0
  109. package/dist/lib/platform-extension-workflow.js.map +1 -0
  110. package/dist/lib/platform-flow-operations.d.ts +554 -0
  111. package/dist/lib/platform-flow-operations.js +317 -0
  112. package/dist/lib/platform-flow-operations.js.map +1 -0
  113. package/dist/lib/platform-flow-tools.d.ts +1 -0
  114. package/dist/lib/platform-flow-tools.js +248 -0
  115. package/dist/lib/platform-flow-tools.js.map +1 -0
  116. package/dist/lib/platform-operation-logic.d.ts +10 -0
  117. package/dist/lib/platform-operation-logic.js +11 -0
  118. package/dist/lib/platform-operation-logic.js.map +1 -0
  119. package/dist/lib/platform-operation-tools.d.ts +1 -324
  120. package/dist/lib/platform-operation-tools.js +13 -4620
  121. package/dist/lib/platform-operation-tools.js.map +1 -1
  122. package/dist/lib/platform-operation-types.d.ts +46 -0
  123. package/dist/lib/platform-operation-types.js +2 -0
  124. package/dist/lib/platform-operation-types.js.map +1 -0
  125. package/dist/lib/platform-policy-tools.d.ts +1 -0
  126. package/dist/lib/platform-policy-tools.js +248 -0
  127. package/dist/lib/platform-policy-tools.js.map +1 -0
  128. package/dist/lib/platform-resource-operations.d.ts +124 -0
  129. package/dist/lib/platform-resource-operations.js +109 -0
  130. package/dist/lib/platform-resource-operations.js.map +1 -0
  131. package/dist/lib/platform-resource-tools.d.ts +1 -0
  132. package/dist/lib/platform-resource-tools.js +70 -0
  133. package/dist/lib/platform-resource-tools.js.map +1 -0
  134. package/dist/lib/platform-route-operations.d.ts +222 -0
  135. package/dist/lib/platform-route-operations.js +290 -0
  136. package/dist/lib/platform-route-operations.js.map +1 -0
  137. package/dist/lib/platform-route-tools.d.ts +1 -0
  138. package/dist/lib/platform-route-tools.js +307 -0
  139. package/dist/lib/platform-route-tools.js.map +1 -0
  140. package/dist/lib/platform-shared-operations.d.ts +7 -0
  141. package/dist/lib/platform-shared-operations.js +4 -0
  142. package/dist/lib/platform-shared-operations.js.map +1 -0
  143. package/dist/lib/platform-websocket-tools.d.ts +1 -0
  144. package/dist/lib/platform-websocket-tools.js +70 -0
  145. package/dist/lib/platform-websocket-tools.js.map +1 -0
  146. package/dist/lib/record-tools.d.ts +4 -0
  147. package/dist/lib/record-tools.js +418 -0
  148. package/dist/lib/record-tools.js.map +1 -0
  149. package/dist/lib/required-knowledge.d.ts +1 -1
  150. package/dist/lib/required-knowledge.js +3 -2
  151. package/dist/lib/required-knowledge.js.map +1 -1
  152. package/dist/lib/route-access-tools.d.ts +4 -0
  153. package/dist/lib/route-access-tools.js +172 -0
  154. package/dist/lib/route-access-tools.js.map +1 -0
  155. package/dist/lib/route-definition-tools.d.ts +4 -0
  156. package/dist/lib/route-definition-tools.js +285 -0
  157. package/dist/lib/route-definition-tools.js.map +1 -0
  158. package/dist/lib/route-inspection-tools.d.ts +4 -0
  159. package/dist/lib/route-inspection-tools.js +319 -0
  160. package/dist/lib/route-inspection-tools.js.map +1 -0
  161. package/dist/lib/route-tools.d.ts +1 -0
  162. package/dist/lib/route-tools.js +9 -0
  163. package/dist/lib/route-tools.js.map +1 -0
  164. package/dist/lib/runtime-zone-registry.d.ts +27 -0
  165. package/dist/lib/runtime-zone-registry.js +81 -0
  166. package/dist/lib/runtime-zone-registry.js.map +1 -0
  167. package/dist/lib/runtime-zone-search.d.ts +303 -0
  168. package/dist/lib/runtime-zone-search.js +596 -0
  169. package/dist/lib/runtime-zone-search.js.map +1 -0
  170. package/dist/lib/runtime-zone-tools.d.ts +2 -307
  171. package/dist/lib/runtime-zone-tools.js +2 -674
  172. package/dist/lib/runtime-zone-tools.js.map +1 -1
  173. package/dist/lib/schema-column-tools.d.ts +3 -0
  174. package/dist/lib/schema-column-tools.js +80 -0
  175. package/dist/lib/schema-column-tools.js.map +1 -0
  176. package/dist/lib/schema-mutation-coordinator.d.ts +28 -0
  177. package/dist/lib/schema-mutation-coordinator.js +154 -0
  178. package/dist/lib/schema-mutation-coordinator.js.map +1 -0
  179. package/dist/lib/schema-relation-contracts.d.ts +39 -0
  180. package/dist/lib/schema-relation-contracts.js +160 -0
  181. package/dist/lib/schema-relation-contracts.js.map +1 -0
  182. package/dist/lib/schema-relation-tools.d.ts +3 -0
  183. package/dist/lib/schema-relation-tools.js +61 -0
  184. package/dist/lib/schema-relation-tools.js.map +1 -0
  185. package/dist/lib/schema-table-contracts.d.ts +28 -0
  186. package/dist/lib/schema-table-contracts.js +263 -0
  187. package/dist/lib/schema-table-contracts.js.map +1 -0
  188. package/dist/lib/schema-table-tools.d.ts +3 -0
  189. package/dist/lib/schema-table-tools.js +297 -0
  190. package/dist/lib/schema-table-tools.js.map +1 -0
  191. package/dist/lib/schema-tool-operations.d.ts +150 -0
  192. package/dist/lib/schema-tool-operations.js +468 -0
  193. package/dist/lib/schema-tool-operations.js.map +1 -0
  194. package/dist/lib/schema-tool-types.d.ts +38 -0
  195. package/dist/lib/schema-tool-types.js +2 -0
  196. package/dist/lib/schema-tool-types.js.map +1 -0
  197. package/dist/lib/schema-verification.d.ts +14 -0
  198. package/dist/lib/schema-verification.js +105 -0
  199. package/dist/lib/schema-verification.js.map +1 -0
  200. package/dist/lib/script-tools.d.ts +4 -0
  201. package/dist/lib/script-tools.js +127 -0
  202. package/dist/lib/script-tools.js.map +1 -0
  203. package/dist/lib/system-tools.d.ts +4 -0
  204. package/dist/lib/system-tools.js +41 -0
  205. package/dist/lib/system-tools.js.map +1 -0
  206. package/dist/lib/table-tool-logic.d.ts +5 -0
  207. package/dist/lib/table-tool-logic.js +6 -0
  208. package/dist/lib/table-tool-logic.js.map +1 -0
  209. package/dist/lib/table-tools.d.ts +1 -84
  210. package/dist/lib/table-tools.js +7 -1522
  211. package/dist/lib/table-tools.js.map +1 -1
  212. package/dist/lib/tool-catalog.d.ts +2 -1
  213. package/dist/lib/tool-catalog.js +23 -2
  214. package/dist/lib/tool-catalog.js.map +1 -1
  215. package/dist/lib/tool-metadata-operations.d.ts +27 -0
  216. package/dist/lib/tool-metadata-operations.js +93 -0
  217. package/dist/lib/tool-metadata-operations.js.map +1 -0
  218. package/dist/lib/tool-permission-profile.d.ts +37 -0
  219. package/dist/lib/tool-permission-profile.js +106 -0
  220. package/dist/lib/tool-permission-profile.js.map +1 -0
  221. package/dist/lib/tool-record-operations.d.ts +102 -0
  222. package/dist/lib/tool-record-operations.js +260 -0
  223. package/dist/lib/tool-record-operations.js.map +1 -0
  224. package/dist/lib/tool-route-inspection.d.ts +47 -0
  225. package/dist/lib/tool-route-inspection.js +168 -0
  226. package/dist/lib/tool-route-inspection.js.map +1 -0
  227. package/dist/lib/tool-routing.d.ts +3 -417
  228. package/dist/lib/tool-routing.js +3 -1038
  229. package/dist/lib/tool-routing.js.map +1 -1
  230. package/dist/lib/tool-runtime-config.d.ts +33 -0
  231. package/dist/lib/tool-runtime-config.js +237 -0
  232. package/dist/lib/tool-runtime-config.js.map +1 -0
  233. package/dist/lib/tool-script-operations.d.ts +34 -0
  234. package/dist/lib/tool-script-operations.js +153 -0
  235. package/dist/lib/tool-script-operations.js.map +1 -0
  236. package/dist/lib/workflow-definitions.d.ts +366 -0
  237. package/dist/lib/workflow-definitions.js +703 -0
  238. package/dist/lib/workflow-definitions.js.map +1 -0
  239. package/dist/lib/workflow-planner.d.ts +45 -0
  240. package/dist/lib/workflow-planner.js +338 -0
  241. package/dist/lib/workflow-planner.js.map +1 -0
  242. package/dist/lib/workflow-types.d.ts +39 -0
  243. package/dist/lib/workflow-types.js +2 -0
  244. package/dist/lib/workflow-types.js.map +1 -0
  245. package/dist/mcp-server-entry.d.ts +0 -3
  246. package/dist/mcp-server-entry.js +2 -3249
  247. package/dist/mcp-server-entry.js.map +1 -1
  248. package/package.json +1 -1
@@ -1,653 +1,7 @@
1
- import { appendFile, chmod, readFile, writeFile, mkdir } from 'node:fs/promises';
2
- import { execFile as execFileCallback } from 'node:child_process';
3
- import { createInterface } from 'node:readline/promises';
4
- import { emitKeypressEvents } from 'node:readline';
5
1
  import { stdin as input, stdout as output, cwd } from 'node:process';
6
- import { dirname, join, relative } from 'node:path';
7
- import { promisify } from 'node:util';
8
- const SERVER_KEY = 'enfyra';
9
- const MCP_PACKAGE_SPEC = '@enfyra/mcp-server@latest';
10
- const PRIVATE_FILE_MODE = 0o600;
11
- const execFile = promisify(execFileCallback);
12
- const forceColor = process.env.FORCE_COLOR != null && process.env.FORCE_COLOR !== '0';
13
- const canStyle = forceColor || (output.isTTY && process.env.NO_COLOR == null);
14
- const style = {
15
- bold: (value) => canStyle ? `\x1B[1m${value}\x1B[22m` : value,
16
- dim: (value) => canStyle ? `\x1B[2m${value}\x1B[22m` : value,
17
- cyan: (value) => canStyle ? `\x1B[36m${value}\x1B[39m` : value,
18
- green: (value) => canStyle ? `\x1B[32m${value}\x1B[39m` : value,
19
- magenta: (value) => canStyle ? `\x1B[35m${value}\x1B[39m` : value,
20
- blue: (value) => canStyle ? `\x1B[34m${value}\x1B[39m` : value,
21
- yellow: (value) => canStyle ? `\x1B[33m${value}\x1B[39m` : value,
22
- underline: (value) => canStyle ? `\x1B[4m${value}\x1B[24m` : value,
23
- inverse: (value) => canStyle ? `\x1B[7m${value}\x1B[27m` : value,
24
- };
25
- const clients = {
26
- codex: {
27
- label: 'Codex',
28
- path: './.codex/config.toml',
29
- color: style.green,
30
- },
31
- claude: {
32
- label: 'Claude Code',
33
- path: './.mcp.json',
34
- color: style.magenta,
35
- },
36
- cursor: {
37
- label: 'Cursor',
38
- path: './.cursor/mcp.json',
39
- color: style.cyan,
40
- },
41
- vscode: {
42
- label: 'VS Code / Copilot',
43
- path: './.vscode/mcp.json',
44
- color: style.blue,
45
- },
46
- antigravity: {
47
- label: 'Antigravity',
48
- path: './.agents/mcp_config.json',
49
- color: style.yellow,
50
- },
51
- };
52
- async function writePrivateFile(path, content) {
53
- await writeFile(path, content, { encoding: 'utf8', mode: PRIVATE_FILE_MODE });
54
- await chmod(path, PRIVATE_FILE_MODE);
55
- }
56
- async function ensureProjectConfigIgnored(root, paths) {
57
- const gitignorePath = join(root, '.gitignore');
58
- let gitignore = '';
59
- try {
60
- gitignore = await readFile(gitignorePath, 'utf8');
61
- }
62
- catch (error) {
63
- if (error.code !== 'ENOENT')
64
- throw error;
65
- }
66
- const existing = new Set(gitignore.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
67
- const entries = paths
68
- .map((path) => relative(root, path).split('\\').join('/'))
69
- .filter((path) => path && !existing.has(path));
70
- if (!entries.length)
71
- return;
72
- const prefix = gitignore && !gitignore.endsWith('\n') ? '\n' : '';
73
- await appendFile(gitignorePath, `${prefix}${entries.join('\n')}\n`, {
74
- encoding: 'utf8',
75
- mode: PRIVATE_FILE_MODE,
76
- });
77
- }
78
- async function assertProjectConfigUntracked(root, paths) {
79
- const entries = paths
80
- .map((path) => relative(root, path).split('\\').join('/'))
81
- .filter(Boolean);
82
- if (!entries.length)
83
- return;
84
- try {
85
- const { stdout } = await execFile('git', [
86
- '-C',
87
- root,
88
- 'ls-files',
89
- '--',
90
- ...entries,
91
- ]);
92
- const tracked = stdout.trim().split(/\r?\n/).filter(Boolean);
93
- if (tracked.length) {
94
- throw new Error(`Refusing to write tracked MCP config files: ${tracked.join(', ')}. Remove them from Git tracking before storing a token.`);
95
- }
96
- }
97
- catch (error) {
98
- if (error?.code === 128)
99
- return;
100
- throw error;
101
- }
102
- }
103
- function statusIcon(kind) {
104
- if (kind === 'success')
105
- return canStyle ? style.green('✓') : 'Done';
106
- if (kind === 'warn')
107
- return canStyle ? style.yellow('!') : 'Warning';
108
- return canStyle ? style.cyan('•') : '-';
109
- }
110
- function isCancelError(error) {
111
- const item = error;
112
- return item?.code === 'ABORT_ERR' || (item?.message || '') === 'Cancelled';
113
- }
114
- function exitCancelled() {
115
- console.log('\nCancelled.');
116
- process.exit(130);
117
- }
118
- function printHelp() {
119
- console.log(`${style.bold('Enfyra MCP config')}
120
- ${style.dim('Write project-local MCP client config for Enfyra.')}
121
-
122
- ${style.bold('Usage')}
123
- npx @enfyra/mcp-server@latest config [options]
124
-
125
- ${style.bold('Supported clients')}
126
- Codex ./.codex/config.toml
127
- Claude Code ./.mcp.json
128
- Cursor ./.cursor/mcp.json
129
- VS Code ./.vscode/mcp.json
130
- Antigravity ./.agents/mcp_config.json
131
-
132
- ${style.bold('Options')}
133
- --app-url <url> Enfyra app/admin URL, for example https://demo.enfyra.io
134
- --api-token, -t <secret> ENFYRA_API_TOKEN
135
- --reconfig Always choose target again in interactive mode and replace the old enfyra config for that target
136
- --yes Non-interactive: no prompts (CI / scripts); use CLI, env, existing file, then defaults
137
-
138
- ${style.bold('Client selection')}
139
- Non-interactive default is all supported clients. In a TTY with no target flags, choose with ↑/↓.
140
-
141
- --claude-code, --claude, --claude-only Only ./.mcp.json (Claude Code project scope)
142
- --cursor, --cursor-only Only ./.cursor/mcp.json (Cursor)
143
- --codex, --codex-only Only ./.codex/config.toml (Codex project scope)
144
- --vscode, --copilot, --vscode-only Only ./.vscode/mcp.json (VS Code / Copilot)
145
- --antigravity, --antigravity-only Only ./.agents/mcp_config.json (Antigravity)
146
- Passing multiple target flags writes each selected target.
147
-
148
- -h, --help Show this help
149
-
150
- ${style.bold('Interactive mode')}
151
- Choose Codex, Claude Code, Cursor, VS Code, Antigravity, or all clients; then enter ENFYRA_APP_URL and ENFYRA_API_TOKEN.
152
- Existing Enfyra config and environment variables are used as defaults. Re-run anytime to update.
153
-
154
- ${style.bold('Examples')}
155
- npx @enfyra/mcp-server@latest config
156
- npx @enfyra/mcp-server@latest config --yes
157
- npx @enfyra/mcp-server@latest config --codex --cursor
158
- npx @enfyra/mcp-server@latest config --vscode
159
- npx @enfyra/mcp-server@latest config --antigravity
160
- npx @enfyra/mcp-server@latest config --claude-code
161
- npx @enfyra/mcp-server@latest config --reconfig
162
- npx @enfyra/mcp-server@latest config --app-url http://localhost:3000 -t 'efy_pat_...'
163
- ENFYRA_APP_URL=https://demo.enfyra.io ENFYRA_API_TOKEN=efy_pat_... npx @enfyra/mcp-server@latest config --yes
164
- `);
165
- }
166
- function parseArgs(argv) {
167
- const out = {
168
- appUrl: undefined,
169
- apiToken: undefined,
170
- claude: true,
171
- cursor: true,
172
- codex: true,
173
- help: false,
174
- yes: false,
175
- reconfig: false,
176
- vscode: true,
177
- antigravity: true,
178
- targetExplicit: false,
179
- };
180
- let pickClaude = false;
181
- let pickCursor = false;
182
- let pickCodex = false;
183
- let pickVscode = false;
184
- let pickAntigravity = false;
185
- for (let i = 0; i < argv.length; i += 1) {
186
- const a = argv[i];
187
- const next = () => {
188
- const v = argv[i + 1];
189
- if (v == null)
190
- throw new Error(`Missing value after ${a}`);
191
- i += 1;
192
- return v;
193
- };
194
- if (a === '--help' || a === '-h')
195
- out.help = true;
196
- else if (a === 'help')
197
- out.help = true;
198
- else if (a === '--yes')
199
- out.yes = true;
200
- else if (a === '--reconfig')
201
- out.reconfig = true;
202
- else if (a === '--app-url')
203
- out.appUrl = next();
204
- else if (a === '--api-url' || a === '-a') {
205
- throw new Error(`${a} is no longer supported for setup; use --app-url instead`);
206
- }
207
- else if (a === '--api-token' || a === '-t')
208
- out.apiToken = next();
209
- else if (a === '--email' || a === '-e' || a === '--password' || a === '-p') {
210
- throw new Error(`${a} is no longer supported; use --api-token instead`);
211
- }
212
- else if (a === '--claude-only' || a === '--claude-code' || a === '--claude')
213
- pickClaude = true;
214
- else if (a === '--cursor-only' || a === '--cursor')
215
- pickCursor = true;
216
- else if (a === '--codex-only' || a === '--codex')
217
- pickCodex = true;
218
- else if (a === '--vscode-only' || a === '--vscode' || a === '--copilot')
219
- pickVscode = true;
220
- else if (a === '--antigravity-only' || a === '--antigravity')
221
- pickAntigravity = true;
222
- else
223
- throw new Error(`Unknown argument: ${a}`);
224
- }
225
- out.targetExplicit = pickClaude || pickCursor || pickCodex || pickVscode || pickAntigravity;
226
- if (out.targetExplicit) {
227
- out.claude = pickClaude;
228
- out.cursor = pickCursor;
229
- out.codex = pickCodex;
230
- out.vscode = pickVscode;
231
- out.antigravity = pickAntigravity;
232
- }
233
- return out;
234
- }
235
- function buildServerEntry(apiUrl, apiToken) {
236
- return {
237
- command: 'npx',
238
- args: ['-y', MCP_PACKAGE_SPEC],
239
- env: {
240
- ENFYRA_API_URL: apiUrl,
241
- ENFYRA_API_TOKEN: apiToken,
242
- },
243
- };
244
- }
245
- function normalizeAppUrl(appUrl) {
246
- const raw = String(appUrl || '').trim().replace(/\/+$/, '');
247
- if (!raw)
248
- return '';
249
- return raw.replace(/\/(?:api|enfyra)$/i, '') || raw;
250
- }
251
- function deriveApiUrlFromAppUrl(appUrl) {
252
- const normalized = normalizeAppUrl(appUrl);
253
- return normalized ? `${normalized}/api` : 'http://localhost:3000/api';
254
- }
255
- function deriveAppUrlFromApiUrl(apiUrl) {
256
- return normalizeAppUrl(apiUrl);
257
- }
258
- function deriveMeUrl(appUrl) {
259
- const normalized = normalizeAppUrl(appUrl);
260
- return normalized ? `${normalized}/me` : '/me';
261
- }
262
- function resolveDefaultAppUrl(opts, existing) {
263
- const appCandidate = opts.appUrl ?? process.env.ENFYRA_APP_URL;
264
- if (appCandidate)
265
- return normalizeAppUrl(appCandidate);
266
- const apiCandidate = process.env.ENFYRA_API_URL ?? existing.apiUrl;
267
- if (apiCandidate)
268
- return deriveAppUrlFromApiUrl(apiCandidate);
269
- return 'http://localhost:3000';
270
- }
271
- async function mergeMcpFile(absPath, serverEntry) {
272
- let data = { mcpServers: {} };
273
- try {
274
- const raw = await readFile(absPath, 'utf8');
275
- const parsed = JSON.parse(raw);
276
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
277
- data = { ...parsed, mcpServers: parsed.mcpServers && typeof parsed.mcpServers === 'object' ? { ...parsed.mcpServers } : {} };
278
- }
279
- }
280
- catch (e) {
281
- if (e.code !== 'ENOENT')
282
- throw e;
283
- }
284
- data.mcpServers = { ...data.mcpServers, [SERVER_KEY]: serverEntry };
285
- const dir = dirname(absPath);
286
- await mkdir(dir, { recursive: true });
287
- await writePrivateFile(absPath, `${JSON.stringify(data, null, 2)}\n`);
288
- }
289
- async function mergeVscodeMcpFile(absPath, serverEntry) {
290
- let data = { servers: {} };
291
- try {
292
- const raw = await readFile(absPath, 'utf8');
293
- const parsed = JSON.parse(raw);
294
- if (parsed && typeof parsed === 'object') {
295
- data = {
296
- ...parsed,
297
- servers: parsed.servers && typeof parsed.servers === 'object' ? { ...parsed.servers } : {},
298
- };
299
- }
300
- }
301
- catch (e) {
302
- if (e.code !== 'ENOENT')
303
- throw e;
304
- }
305
- data.servers = {
306
- ...data.servers,
307
- [SERVER_KEY]: {
308
- type: 'stdio',
309
- ...serverEntry,
310
- },
311
- };
312
- await mkdir(dirname(absPath), { recursive: true });
313
- await writePrivateFile(absPath, `${JSON.stringify(data, null, 2)}\n`);
314
- }
315
- function tomlString(value) {
316
- return JSON.stringify(String(value ?? ''));
317
- }
318
- function buildCodexTomlBlock(apiUrl, apiToken) {
319
- return [
320
- '[mcp_servers.enfyra]',
321
- 'command = "npx"',
322
- `args = ["-y", "${MCP_PACKAGE_SPEC}"]`,
323
- '',
324
- '[mcp_servers.enfyra.env]',
325
- `ENFYRA_API_URL = ${tomlString(apiUrl)}`,
326
- `ENFYRA_API_TOKEN = ${tomlString(apiToken)}`,
327
- '',
328
- ].join('\n');
329
- }
330
- async function mergeCodexConfig(absPath, apiUrl, apiToken) {
331
- let raw = '';
332
- try {
333
- raw = await readFile(absPath, 'utf8');
334
- }
335
- catch (e) {
336
- if (e.code !== 'ENOENT')
337
- throw e;
338
- }
339
- const kept = [];
340
- let skip = false;
341
- for (const line of raw.split(/\r?\n/)) {
342
- const header = line.match(/^\s*\[([^\]]+)\]\s*$/);
343
- if (header) {
344
- const section = header[1].trim();
345
- skip = section === 'mcp_servers.enfyra' || section.startsWith('mcp_servers.enfyra.');
346
- }
347
- if (!skip)
348
- kept.push(line);
349
- }
350
- const prefix = kept.join('\n').trimEnd();
351
- const next = prefix ? `${prefix}\n\n${buildCodexTomlBlock(apiUrl, apiToken)}` : buildCodexTomlBlock(apiUrl, apiToken);
352
- await mkdir(dirname(absPath), { recursive: true });
353
- await writePrivateFile(absPath, next);
354
- }
355
- function parseTomlString(value) {
356
- const trimmed = String(value || '').trim();
357
- if (!trimmed)
358
- return '';
359
- try {
360
- return JSON.parse(trimmed);
361
- }
362
- catch {
363
- return trimmed.replace(/^['"]|['"]$/g, '');
364
- }
365
- }
366
- async function readCodexEnfyraEnv(absPath) {
367
- try {
368
- const raw = await readFile(absPath, 'utf8');
369
- const values = { apiUrl: '', apiToken: '' };
370
- let inEnv = false;
371
- for (const line of raw.split(/\r?\n/)) {
372
- const header = line.match(/^\s*\[([^\]]+)\]\s*$/);
373
- if (header) {
374
- inEnv = header[1].trim() === 'mcp_servers.enfyra.env';
375
- continue;
376
- }
377
- if (!inEnv)
378
- continue;
379
- const pair = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.+?)\s*$/);
380
- if (!pair)
381
- continue;
382
- const key = pair[1];
383
- const value = parseTomlString(pair[2]);
384
- if (key === 'ENFYRA_API_URL')
385
- values.apiUrl = value;
386
- if (key === 'ENFYRA_API_TOKEN')
387
- values.apiToken = value;
388
- }
389
- if (values.apiUrl || values.apiToken)
390
- return values;
391
- }
392
- catch {
393
- /* */
394
- }
395
- return null;
396
- }
397
- function getCodexConfigPath(root) {
398
- return join(root, '.codex', 'config.toml');
399
- }
400
- function getClaudeConfigPath(root) {
401
- return join(root, '.mcp.json');
402
- }
403
- function getCursorConfigPath(root) {
404
- return join(root, '.cursor', 'mcp.json');
405
- }
406
- function getVscodeConfigPath(root) {
407
- return join(root, '.vscode', 'mcp.json');
408
- }
409
- function getAntigravityConfigPath(root) {
410
- return join(root, '.agents', 'mcp_config.json');
411
- }
412
- function getClientPath(client, root) {
413
- if (client === 'claude')
414
- return getClaudeConfigPath(root);
415
- if (client === 'cursor')
416
- return getCursorConfigPath(root);
417
- if (client === 'codex')
418
- return getCodexConfigPath(root);
419
- if (client === 'vscode')
420
- return getVscodeConfigPath(root);
421
- if (client === 'antigravity')
422
- return getAntigravityConfigPath(root);
423
- throw new Error(`Unknown MCP client: ${client}`);
424
- }
425
- async function readMcpServerEnv(absPath, serverRootKey) {
426
- try {
427
- const raw = await readFile(absPath, 'utf8');
428
- const j = JSON.parse(raw);
429
- const e = j?.[serverRootKey]?.[SERVER_KEY]?.env;
430
- if (e && typeof e === 'object' && (e.ENFYRA_API_URL || e.ENFYRA_API_TOKEN)) {
431
- return {
432
- apiUrl: typeof e.ENFYRA_API_URL === 'string' ? e.ENFYRA_API_URL : '',
433
- apiToken: typeof e.ENFYRA_API_TOKEN === 'string' ? e.ENFYRA_API_TOKEN : '',
434
- };
435
- }
436
- }
437
- catch {
438
- /* */
439
- }
440
- return null;
441
- }
442
- async function loadExistingEnfyraEnv(root, readClaude, readCursor, readCodex, readVscode, readAntigravity) {
443
- const paths = [];
444
- if (readClaude)
445
- paths.push({ path: getClaudeConfigPath(root), rootKey: 'mcpServers' });
446
- if (readCursor)
447
- paths.push({ path: getCursorConfigPath(root), rootKey: 'mcpServers' });
448
- if (!readClaude && readCursor)
449
- paths.push({ path: getClaudeConfigPath(root), rootKey: 'mcpServers' });
450
- if (readVscode)
451
- paths.push({ path: getVscodeConfigPath(root), rootKey: 'servers' });
452
- if (readAntigravity)
453
- paths.push({ path: getAntigravityConfigPath(root), rootKey: 'mcpServers' });
454
- const seen = new Set();
455
- for (const entry of paths) {
456
- const key = `${entry.rootKey}:${entry.path}`;
457
- if (seen.has(key))
458
- continue;
459
- seen.add(key);
460
- const env = await readMcpServerEnv(entry.path, entry.rootKey);
461
- if (env)
462
- return env;
463
- }
464
- if (readCodex) {
465
- const codex = await readCodexEnfyraEnv(getCodexConfigPath(root));
466
- if (codex)
467
- return codex;
468
- }
469
- return { apiUrl: '', apiToken: '' };
470
- }
471
- async function promptTargetChoice() {
472
- const choices = [
473
- {
474
- client: 'codex',
475
- value: { claude: false, cursor: false, codex: true, vscode: false, antigravity: false },
476
- },
477
- {
478
- client: 'claude',
479
- value: { claude: true, cursor: false, codex: false, vscode: false, antigravity: false },
480
- },
481
- {
482
- client: 'cursor',
483
- value: { claude: false, cursor: true, codex: false, vscode: false, antigravity: false },
484
- },
485
- {
486
- client: 'vscode',
487
- value: { claude: false, cursor: false, codex: false, vscode: true, antigravity: false },
488
- },
489
- {
490
- client: 'antigravity',
491
- value: { claude: false, cursor: false, codex: false, vscode: false, antigravity: true },
492
- },
493
- {
494
- client: 'all',
495
- value: { claude: true, cursor: true, codex: true, vscode: true, antigravity: true },
496
- },
497
- ];
498
- if (input.setRawMode && output.isTTY) {
499
- return promptTargetSelect(choices, 5);
500
- }
501
- const rl = createInterface({ input, output });
502
- const line = (await rl.question('Where should Enfyra MCP config be written?\n'
503
- + ' [1] Codex ./.codex/config.toml\n'
504
- + ' [2] Claude Code ./.mcp.json\n'
505
- + ' [3] Cursor ./.cursor/mcp.json\n'
506
- + ' [4] VS Code ./.vscode/mcp.json\n'
507
- + ' [5] Antigravity ./.agents/mcp_config.json\n'
508
- + ' [6] All [default]\n'
509
- + 'Choice [6]: ')).trim().toLowerCase();
510
- await rl.close();
511
- if (line === '' || line === '6' || line === 'all' || line === 'a') {
512
- return { claude: true, cursor: true, codex: true, vscode: true, antigravity: true };
513
- }
514
- if (line === '1' || line === 'codex' || line === 'x') {
515
- return { claude: false, cursor: false, codex: true, vscode: false, antigravity: false };
516
- }
517
- if (line === '2' || line === 'claude' || line === 'claude-code') {
518
- return { claude: true, cursor: false, codex: false, vscode: false, antigravity: false };
519
- }
520
- if (line === '3' || line === 'cursor' || line === 'u') {
521
- return { claude: false, cursor: true, codex: false, vscode: false, antigravity: false };
522
- }
523
- if (line === '4' || line === 'vscode' || line === 'vs-code' || line === 'copilot') {
524
- return { claude: false, cursor: false, codex: false, vscode: true, antigravity: false };
525
- }
526
- if (line === '5' || line === 'antigravity') {
527
- return { claude: false, cursor: false, codex: false, vscode: false, antigravity: true };
528
- }
529
- return { claude: true, cursor: true, codex: true, vscode: true, antigravity: true };
530
- }
531
- async function promptTargetSelect(choices, initialIndex = 0) {
532
- let selected = Math.max(0, Math.min(initialIndex, choices.length - 1));
533
- let renderedLines = 0;
534
- const formatChoice = (choice, active) => {
535
- const indicator = active ? style.cyan('◆') : style.dim('◇');
536
- const accent = active ? style.cyan('│') : style.dim('│');
537
- if (choice.client === 'all') {
538
- const label = active ? style.bold(style.underline('All supported clients')) : 'All supported clients';
539
- const paddedLabel = label + ' '.repeat(22 - 'All supported clients'.length);
540
- const hint = active ? style.cyan('Codex + Claude Code + Cursor + VS Code + Antigravity') : style.dim('Codex + Claude Code + Cursor + VS Code + Antigravity');
541
- return `${accent} ${indicator} ${paddedLabel} ${hint}`;
542
- }
543
- const meta = clients[choice.client];
544
- const label = active ? style.bold(meta.color(meta.label)) : meta.color(meta.label);
545
- const paddedLabel = label + ' '.repeat(Math.max(1, 22 - meta.label.length));
546
- const path = active ? style.cyan(meta.path) : style.dim(meta.path);
547
- return `${accent} ${indicator} ${paddedLabel} ${path}`;
548
- };
549
- const render = () => {
550
- if (renderedLines > 0) {
551
- output.write(`\x1B[${renderedLines}A\x1B[0J`);
552
- }
553
- const lines = [
554
- `${style.cyan('◆')} ${style.bold('Enfyra MCP setup')}`,
555
- `${style.dim('│')} ${style.dim('Choose where to write the project config.')}`,
556
- style.dim('│'),
557
- ...choices.map((choice, index) => formatChoice(choice, index === selected)),
558
- style.dim('│'),
559
- style.dim('Choose one client config, or write all supported project configs.'),
560
- `${style.dim('└')} ${style.dim('Use ↑/↓ to move, Enter to select, Ctrl+C to cancel.')}`,
561
- ];
562
- renderedLines = lines.length;
563
- output.write(`${lines.join('\n')}\n`);
564
- };
565
- return new Promise((resolve, reject) => {
566
- const wasRaw = input.isRaw;
567
- const cleanup = () => {
568
- input.off('keypress', onKeypress);
569
- if (!wasRaw)
570
- input.setRawMode(false);
571
- output.write('\x1B[?25h');
572
- };
573
- const finish = () => {
574
- cleanup();
575
- resolve(choices[selected].value);
576
- };
577
- const onKeypress = (_str, key = {}) => {
578
- if (key.ctrl && key.name === 'c') {
579
- cleanup();
580
- output.write('\n');
581
- reject(new Error('Cancelled'));
582
- return;
583
- }
584
- if (key.name === 'up') {
585
- selected = selected <= 0 ? choices.length - 1 : selected - 1;
586
- render();
587
- return;
588
- }
589
- if (key.name === 'down') {
590
- selected = selected >= choices.length - 1 ? 0 : selected + 1;
591
- render();
592
- return;
593
- }
594
- if (key.name === 'return' || key.name === 'enter') {
595
- finish();
596
- }
597
- };
598
- emitKeypressEvents(input);
599
- input.setRawMode(true);
600
- input.resume();
601
- output.write('\x1B[?25l');
602
- input.on('keypress', onKeypress);
603
- render();
604
- });
605
- }
606
- async function promptConfig(opts, existing) {
607
- let appUrl = opts.appUrl ? normalizeAppUrl(opts.appUrl) : '';
608
- let apiToken = opts.apiToken;
609
- if (appUrl && apiToken !== undefined) {
610
- return { apiUrl: deriveApiUrlFromAppUrl(appUrl), apiToken };
611
- }
612
- const rl = createInterface({ input, output });
613
- const q = async (msg) => {
614
- try {
615
- return await rl.question(msg);
616
- }
617
- catch (error) {
618
- if (isCancelError(error)) {
619
- throw new Error('Cancelled');
620
- }
621
- throw error;
622
- }
623
- };
624
- const defaultAppUrl = resolveDefaultAppUrl(opts, existing);
625
- if (!appUrl) {
626
- console.log(`${style.cyan('◆')} ${style.bold('Connect to Enfyra')}`);
627
- console.log(`${style.dim('│')} Enter the Enfyra app URL.`);
628
- const line = (await q(`${style.dim('└')} ENFYRA_APP_URL ${style.dim(`[${defaultAppUrl}]`)}: `)).trim();
629
- appUrl = normalizeAppUrl(line || defaultAppUrl);
630
- }
631
- const apiUrl = deriveApiUrlFromAppUrl(appUrl);
632
- const defaultApiToken = opts.apiToken ?? process.env.ENFYRA_API_TOKEN ?? existing.apiToken ?? '';
633
- if (apiToken === undefined) {
634
- const hint = defaultApiToken ? ' (Enter = keep current)' : '';
635
- const meUrl = deriveMeUrl(appUrl);
636
- console.log('');
637
- console.log(`${style.cyan('◆')} ${style.bold('API token')}`);
638
- console.log(`${style.dim('│')} If you do not have a token yet, create one here: ${style.cyan(meUrl)}`);
639
- const line = (await q(`${style.dim('└')} ENFYRA_API_TOKEN${hint}: `)).trim();
640
- apiToken = line !== '' ? line : defaultApiToken;
641
- }
642
- await rl.close();
643
- return { apiUrl, apiToken };
644
- }
645
- function resolveNonInteractive(opts, existing) {
646
- const appUrl = resolveDefaultAppUrl(opts, existing);
647
- const apiUrl = deriveApiUrlFromAppUrl(appUrl);
648
- const apiToken = opts.apiToken ?? process.env.ENFYRA_API_TOKEN ?? existing.apiToken ?? '';
649
- return { apiUrl, apiToken };
650
- }
2
+ import { clients, exitCancelled, isCancelError, parseArgs, printHelp, statusIcon, style, } from './config-local-contracts.js';
3
+ import { assertProjectConfigUntracked, buildServerEntry, ensureProjectConfigIgnored, getClientPath, loadExistingEnfyraEnv, mergeCodexConfig, mergeMcpFile, mergeVscodeMcpFile, } from './config-local-adapters.js';
4
+ import { promptConfig, promptTargetChoice, resolveNonInteractive } from './config-local-prompts.js';
651
5
  export async function runLocalConfig(argv) {
652
6
  const onSigint = () => exitCancelled();
653
7
  const onUnhandledRejection = (error) => {