@retailcrm/embed-ui-v1-endpoint 0.9.22-alpha.4 → 0.9.22-alpha.5

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.
@@ -3,6 +3,7 @@
3
3
  import fs from 'node:fs'
4
4
  import path from 'node:path'
5
5
  import process from 'node:process'
6
+ import { spawnSync } from 'node:child_process'
6
7
 
7
8
  const PACKAGE_NAME = '@retailcrm/embed-ui-v1-endpoint'
8
9
  const DEFAULT_NEWLINE = '\n'
@@ -10,20 +11,23 @@ const AGENTS_SECTION_HEADER = '## @retailcrm/embed-ui-v1-endpoint'
10
11
  const README_MCP_SECTION_HEADER = '## MCP For AI Assistants'
11
12
  const README_MCP_MARKER = 'embed-ui-v1-endpoint://targets'
12
13
  const MCP_SERVER_NAME = 'retailcrm-embed-ui-v1-endpoint'
13
- const MCP_SERVER_CONFIG = {
14
- command: 'npx',
15
- args: ['-y', '-p', PACKAGE_NAME, 'embed-ui-v1-endpoint-mcp'],
16
- }
14
+ const MCP_BIN_NAME = process.platform === 'win32' ? 'embed-ui-v1-endpoint-mcp.cmd' : 'embed-ui-v1-endpoint-mcp'
17
15
  const MCP_CLIENT_CONFIGS = {
16
+ codex: {
17
+ type: 'codex',
18
+ },
18
19
  cursor: {
20
+ type: 'file',
19
21
  filePath: '.cursor/mcp.json',
20
22
  rootField: 'mcpServers',
21
23
  },
22
24
  junie: {
25
+ type: 'file',
23
26
  filePath: '.junie/mcp/mcp.json',
24
27
  rootField: 'mcpServers',
25
28
  },
26
29
  vscode: {
30
+ type: 'file',
27
31
  filePath: '.vscode/mcp.json',
28
32
  rootField: 'servers',
29
33
  },
@@ -35,7 +39,7 @@ const HELP_TEXT = `Usage:
35
39
 
36
40
  Options:
37
41
  -f, --force Replace existing managed sections and MCP server entries
38
- --mcp-client-configs Comma-separated MCP client configs to create (cursor,junie,vscode)
42
+ --mcp-client-configs Comma-separated MCP client configs to create (codex,cursor,junie,vscode)
39
43
  --dry-run Print planned config changes without writing files
40
44
  -h, --help Show this help
41
45
 
@@ -44,9 +48,30 @@ Examples:
44
48
  npx ${PACKAGE_NAME} init-agents ./my-project
45
49
  npx ${PACKAGE_NAME} init-agents --force
46
50
  npx ${PACKAGE_NAME} init-config ./my-project
47
- npx ${PACKAGE_NAME} init-config ./my-project --mcp-client-configs cursor,junie,vscode
51
+ npx ${PACKAGE_NAME} init-config ./my-project --mcp-client-configs codex,cursor,junie,vscode
48
52
  `
49
53
 
54
+ const resolveLocalMcpBinPath = (target) => path.join(target, 'node_modules', '.bin', MCP_BIN_NAME)
55
+
56
+ const createMcpServerConfig = (target) => ({
57
+ command: resolveLocalMcpBinPath(target),
58
+ })
59
+
60
+ const formatShellCommand = (command, args = []) => [command, ...args].map((part) => part.includes(' ') ? `"${part}"` : part).join(' ')
61
+
62
+ const createCodexAddCommand = (target) => [
63
+ 'codex',
64
+ 'mcp',
65
+ 'add',
66
+ MCP_SERVER_NAME,
67
+ '--',
68
+ resolveLocalMcpBinPath(target),
69
+ ]
70
+
71
+ const printMcpNotice = (message) => {
72
+ console.log(`MCP: ${message}`)
73
+ }
74
+
50
75
  const parseArgs = (argv) => {
51
76
  const options = {
52
77
  command: null,
@@ -128,15 +153,15 @@ When working with \`${PACKAGE_NAME}\` in this project:
128
153
  5. When the task involves widget targets, target placement, target contexts, target metadata, or choosing a target, use the package MCP server if it is available.
129
154
  6. First read \`embed-ui-v1-endpoint://targets\` to discover available target profiles.
130
155
  7. Then read the relevant \`embed-ui-v1-endpoint://targets/<encoded-target>\` resource before answering or changing code related to that target.
131
- 8. If MCP resources are not available, use the generated YAML profiles from \`./node_modules/${PACKAGE_NAME}/docs/targets/*.yml\` as the fallback source.
132
- 9. Prefer target profiles over guessing target placement, contexts, or semantic intent from names alone.
156
+ 8. A project \`.mcp.json\` may require restarting or reconnecting the AI client before MCP resources appear in the current session.
157
+ 9. If MCP resources are not available, use the generated YAML profiles from \`./node_modules/${PACKAGE_NAME}/docs/targets/*.yml\` as the fallback source.
158
+ 10. Prefer target profiles over guessing target placement, contexts, or semantic intent from names alone.
133
159
 
134
160
  Suggested MCP stdio server configuration:
135
161
 
136
162
  \`\`\`json
137
163
  {
138
- "command": "npx",
139
- "args": ["-y", "-p", "${PACKAGE_NAME}", "embed-ui-v1-endpoint-mcp"]
164
+ "command": "./node_modules/.bin/embed-ui-v1-endpoint-mcp"
140
165
  }
141
166
  \`\`\`
142
167
  `
@@ -145,17 +170,19 @@ Suggested MCP stdio server configuration:
145
170
  const createMcpReadmeSection = (clientConfigs) => {
146
171
  const clientConfigText = clientConfigs.length
147
172
  ? `Client MCP configs were also requested: ${clientConfigs.map((clientConfig) => `\`${clientConfig}\``).join(', ')}. Review the generated files and restart the AI client if it is already open.`
148
- : 'Client MCP configs are not created by default. For supported project-level configs, rerun init with `--mcp-client-configs cursor,junie,vscode`.'
173
+ : 'Client MCP configs are not created by default. For supported configs, rerun init with `--mcp-client-configs codex,cursor,junie,vscode`.'
149
174
 
150
175
  return `${README_MCP_SECTION_HEADER}
151
176
 
152
177
  The project has an MCP server configuration for \`${PACKAGE_NAME}\`.
153
178
  It exposes AI-friendly widget target descriptions as MCP resources.
179
+ If the AI client was already running, restart or reconnect it before expecting these resources
180
+ to appear in that session.
154
181
 
155
182
  Basic check:
156
183
 
157
184
  \`\`\`bash
158
- npx -p ${PACKAGE_NAME} embed-ui-v1-endpoint-mcp
185
+ ./node_modules/.bin/embed-ui-v1-endpoint-mcp
159
186
  \`\`\`
160
187
 
161
188
  Primary resources:
@@ -170,6 +197,21 @@ ${clientConfigText}
170
197
  Some clients store MCP servers in a user-level config outside this repository. Init does not edit
171
198
  those files. Add the same server manually and restart the client.
172
199
 
200
+ Codex CLI:
201
+
202
+ \`\`\`bash
203
+ codex mcp add ${MCP_SERVER_NAME} -- "$(realpath ./node_modules/.bin/embed-ui-v1-endpoint-mcp)"
204
+ codex mcp list
205
+ codex mcp get ${MCP_SERVER_NAME}
206
+ \`\`\`
207
+
208
+ Equivalent \`~/.codex/config.toml\` block:
209
+
210
+ \`\`\`toml
211
+ [mcp_servers.${MCP_SERVER_NAME}]
212
+ command = "/absolute/path/to/project/node_modules/.bin/embed-ui-v1-endpoint-mcp"
213
+ \`\`\`
214
+
173
215
  Claude Desktop config paths:
174
216
 
175
217
  - macOS: \`~/Library/Application Support/Claude/claude_desktop_config.json\`
@@ -181,8 +223,7 @@ Config snippet:
181
223
  {
182
224
  "mcpServers": {
183
225
  "${MCP_SERVER_NAME}": {
184
- "command": "npx",
185
- "args": ["-y", "-p", "${PACKAGE_NAME}", "embed-ui-v1-endpoint-mcp"]
226
+ "command": "/absolute/path/to/project/node_modules/.bin/embed-ui-v1-endpoint-mcp"
186
227
  }
187
228
  }
188
229
  }
@@ -314,7 +355,7 @@ const initAgents = (target, force) => {
314
355
  console.log(`The ${PACKAGE_NAME} instructions were appended to the end of the file.`)
315
356
  }
316
357
 
317
- const writeMcpServerConfig = (target, relativePath, rootField, options) => {
358
+ const writeMcpServerConfig = (target, relativePath, rootField, options, serverConfig) => {
318
359
  const filePath = path.join(target, relativePath)
319
360
  const fileExists = fs.existsSync(filePath)
320
361
  const config = readJsonObject(filePath)
@@ -323,14 +364,69 @@ const writeMcpServerConfig = (target, relativePath, rootField, options) => {
323
364
  if (servers[MCP_SERVER_NAME] && !options.force) {
324
365
  console.log(`${relativePath} already contains ${MCP_SERVER_NAME}`)
325
366
  console.log('Nothing was changed. Re-run with --force to refresh that server entry.')
326
- return
367
+ return false
327
368
  }
328
369
 
329
- servers[MCP_SERVER_NAME] = MCP_SERVER_CONFIG
370
+ servers[MCP_SERVER_NAME] = serverConfig
330
371
  writeJson(filePath, config, options.dryRun)
331
372
 
332
373
  const action = fileExists ? 'updated' : 'created'
333
374
  console.log(`${relativePath} ${options.dryRun ? `would be ${action}` : `was ${action}`}`)
375
+ return true
376
+ }
377
+
378
+ const isCodexMcpAddAvailable = () => {
379
+ const result = spawnSync('codex', ['mcp', 'add', '--help'], {
380
+ encoding: 'utf8',
381
+ stdio: ['ignore', 'pipe', 'pipe'],
382
+ })
383
+
384
+ return !result.error && result.status === 0
385
+ }
386
+
387
+ const runCodexMcpAdd = (target, options) => {
388
+ const localMcpBinPath = resolveLocalMcpBinPath(target)
389
+ const codexCommand = createCodexAddCommand(target)
390
+ const codexCommandText = formatShellCommand(codexCommand[0], codexCommand.slice(1))
391
+
392
+ if (!fs.existsSync(localMcpBinPath)) {
393
+ printMcpNotice(`Codex MCP auto-connect skipped: local MCP binary was not found at ${localMcpBinPath}. Run package install, then run: ${codexCommandText}`)
394
+ return
395
+ }
396
+
397
+ if (!isCodexMcpAddAvailable()) {
398
+ printMcpNotice(`Codex MCP auto-connect skipped: "codex mcp add" is not available. Run manually after installing Codex CLI support: ${codexCommandText}`)
399
+ return
400
+ }
401
+
402
+ if (options.dryRun) {
403
+ printMcpNotice(`Codex MCP server would be registered with local binary: ${codexCommandText}`)
404
+ return
405
+ }
406
+
407
+ const result = spawnSync(codexCommand[0], codexCommand.slice(1), {
408
+ encoding: 'utf8',
409
+ stdio: ['ignore', 'pipe', 'pipe'],
410
+ })
411
+
412
+ if (result.error || result.status !== 0) {
413
+ const output = [result.stderr, result.stdout]
414
+ .filter((value) => typeof value === 'string' && value.trim())
415
+ .map((value) => value.trim())
416
+ .join(' ')
417
+
418
+ printMcpNotice(`Codex MCP auto-connect failed${output ? `: ${output}` : ''}. Run manually: ${codexCommandText}`)
419
+ return
420
+ }
421
+
422
+ printMcpNotice('Codex MCP server was registered with the local v1-endpoint binary. Restart Codex session to use new resources.')
423
+ }
424
+
425
+ const printFileClientMcpNotice = (clientConfig, target) => {
426
+ const config = MCP_CLIENT_CONFIGS[clientConfig]
427
+
428
+ printMcpNotice(`${clientConfig} MCP config points to local binary ${resolveLocalMcpBinPath(target)}. Restart or reconnect the client to use new resources.`)
429
+ printMcpNotice(`${clientConfig} config file: ${path.join(target, config.filePath)}`)
334
430
  }
335
431
 
336
432
  const resolveMcpClientConfigs = (tokens) => {
@@ -379,12 +475,24 @@ const initConfig = (target, options) => {
379
475
  }
380
476
 
381
477
  const clientConfigs = resolveMcpClientConfigs(options.mcpClientConfigs)
478
+ const serverConfig = createMcpServerConfig(target)
382
479
 
383
- writeMcpServerConfig(target, '.mcp.json', 'mcpServers', options)
480
+ writeMcpServerConfig(target, '.mcp.json', 'mcpServers', options, serverConfig)
481
+ printMcpNotice(`Project MCP config points to local binary ${serverConfig.command}. Restart or reconnect MCP clients to use new resources.`)
482
+ if (!fs.existsSync(serverConfig.command)) {
483
+ printMcpNotice(`Local MCP binary is not available yet. Install project dependencies before starting MCP clients: ${serverConfig.command}`)
484
+ }
384
485
 
385
486
  for (const clientConfig of clientConfigs) {
386
487
  const config = MCP_CLIENT_CONFIGS[clientConfig]
387
- writeMcpServerConfig(target, config.filePath, config.rootField, options)
488
+
489
+ if (config.type === 'codex') {
490
+ runCodexMcpAdd(target, options)
491
+ continue
492
+ }
493
+
494
+ writeMcpServerConfig(target, config.filePath, config.rootField, options, serverConfig)
495
+ printFileClientMcpNotice(clientConfig, target)
388
496
  }
389
497
 
390
498
  updateMcpReadmeNotes(target, clientConfigs, options)
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "embed-ui-v1-endpoint-mcp": "./bin/embed-ui-v1-endpoint-mcp.mjs"
6
6
  },
7
7
  "type": "module",
8
- "version": "0.9.22-alpha.4",
8
+ "version": "0.9.22-alpha.5",
9
9
  "description": "Endpoint API for integrations in RetailCRM",
10
10
  "license": "MIT",
11
11
  "author": "RetailDriverLLC <integration@retailcrm.ru>",
@@ -97,17 +97,17 @@
97
97
  "peerDependencies": {
98
98
  "@omnicajs/vue-remote": "^0.2.23",
99
99
  "@remote-ui/rpc": "^1.4",
100
- "@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.4",
101
- "@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.4",
100
+ "@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.5",
101
+ "@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.5",
102
102
  "pinia": "^2.2",
103
103
  "vue": "^3.5"
104
104
  },
105
105
  "dependencies": {
106
106
  "@modelcontextprotocol/sdk": "^1.29.0",
107
107
  "@remote-ui/rpc": "^1.4.7",
108
- "@retailcrm/embed-ui-v1-components": "^0.9.22-alpha.4",
109
- "@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.4",
110
- "@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.4"
108
+ "@retailcrm/embed-ui-v1-components": "^0.9.22-alpha.5",
109
+ "@retailcrm/embed-ui-v1-contexts": "^0.9.22-alpha.5",
110
+ "@retailcrm/embed-ui-v1-types": "^0.9.22-alpha.5"
111
111
  },
112
112
  "devDependencies": {
113
113
  "@retailcrm/image-preview": "^1.0.2",