openuispec 0.1.36 → 0.1.38

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 (3) hide show
  1. package/README.md +3 -2
  2. package/cli/init.ts +74 -42
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -52,7 +52,7 @@ cd your-project
52
52
  openuispec init
53
53
  ```
54
54
 
55
- This scaffolds a spec directory, starter tokens, adds rules to `CLAUDE.md` / `AGENTS.md`, and configures the MCP server in `.claude.json` so AI assistants track spec changes automatically.
55
+ This scaffolds a spec directory, starter tokens, adds rules to `CLAUDE.md` / `AGENTS.md`, and configures the MCP server so AI assistants track spec changes automatically.
56
56
  Use `openuispec init --no-configure-targets` if you want to scaffold first and choose target stacks later.
57
57
 
58
58
  Then hand your spec to any AI code generator:
@@ -251,8 +251,9 @@ OpenUISpec includes an MCP (Model Context Protocol) server that exposes CLI comm
251
251
 
252
252
  ### Setup
253
253
 
254
- `openuispec init` automatically configures the MCP server in `.claude.json`. For existing projects, add it manually:
254
+ `openuispec init` automatically configures the MCP server for your coding agent. For existing projects, run `openuispec update-rules` or add the config manually:
255
255
 
256
+ **Claude Code** (`.mcp.json`), **VS Code / Copilot** (`.vscode/mcp.json`):
256
257
  ```json
257
258
  {
258
259
  "mcpServers": {
package/cli/init.ts CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  readdirSync,
15
15
  existsSync,
16
16
  appendFileSync,
17
+ unlinkSync,
17
18
  } from "node:fs";
18
19
  import { join, relative, dirname, resolve } from "node:path";
19
20
  import { fileURLToPath } from "node:url";
@@ -263,7 +264,7 @@ Do NOT guess the file format — skipping this step will produce invalid YAML th
263
264
 
264
265
  ## MCP Tools (recommended for AI assistants)
265
266
 
266
- When the openuispec MCP server is configured (see \`.claude.json\`), AI assistants should use these tools instead of CLI commands:
267
+ When the openuispec MCP server is configured, AI assistants should use these tools instead of CLI commands:
267
268
 
268
269
  | Tool | When to use |
269
270
  |------|-------------|
@@ -471,28 +472,82 @@ export function updateRules(): void {
471
472
  }
472
473
 
473
474
  // Ensure MCP server is configured
474
- const claudeJsonPath = join(cwd, ".claude.json");
475
- const mcpConfig = {
476
- command: "npx",
477
- args: ["openuispec-mcp"],
478
- };
475
+ configureMcp(cwd, true);
476
+ }
477
+
478
+ // ── shared MCP config ───────────────────────────────────────────────
479
+
480
+ const EXPECTED_MCP_CONFIG = {
481
+ command: "openuispec",
482
+ args: ["mcp"],
483
+ };
484
+
485
+ /**
486
+ * MCP config files by agent:
487
+ * .mcp.json — Claude Code (project scope)
488
+ * .vscode/mcp.json — VS Code / Copilot Chat
489
+ *
490
+ * All use the same { mcpServers: { openuispec: { command, args } } } shape.
491
+ */
492
+ const MCP_CONFIG_PATHS = [
493
+ ".mcp.json",
494
+ join(".vscode", "mcp.json"),
495
+ ];
496
+
497
+ function configureMcp(cwd: string, showRestart: boolean, quiet: boolean = false): void {
498
+ for (const relPath of MCP_CONFIG_PATHS) {
499
+ const configPath = join(cwd, relPath);
500
+
501
+ // .vscode/mcp.json: only write if .vscode/ already exists
502
+ if (relPath.startsWith(".vscode") && !existsSync(join(cwd, ".vscode"))) continue;
479
503
 
480
- try {
481
- let claudeJson: Record<string, any> = {};
482
504
  try {
483
- claudeJson = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
505
+ let config: Record<string, any> = {};
506
+ try {
507
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
508
+ } catch {
509
+ // file doesn't exist or isn't valid JSON — start fresh
510
+ }
511
+
512
+ if (!config.mcpServers) config.mcpServers = {};
513
+
514
+ const existing = config.mcpServers.openuispec;
515
+ const needsUpdate =
516
+ !existing ||
517
+ existing.command !== EXPECTED_MCP_CONFIG.command ||
518
+ JSON.stringify(existing.args) !== JSON.stringify(EXPECTED_MCP_CONFIG.args);
519
+
520
+ if (needsUpdate) {
521
+ config.mcpServers.openuispec = { ...EXPECTED_MCP_CONFIG };
522
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
523
+ if (!quiet) console.log(` ${existing ? "update" : "create"} ${relPath} (MCP server configured)`);
524
+ } else {
525
+ if (!quiet) console.log(` skip ${relPath} (openuispec MCP already configured)`);
526
+ }
484
527
  } catch {
485
- // file doesn't exist or isn't valid JSON — start fresh
528
+ if (!quiet) console.log(` skip ${relPath} (could not configure MCP server)`);
486
529
  }
487
- if (!claudeJson.mcpServers) claudeJson.mcpServers = {};
488
- if (!claudeJson.mcpServers.openuispec) {
489
- claudeJson.mcpServers.openuispec = mcpConfig;
490
- writeFileSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
491
- console.log(` create .claude.json (MCP server configured)`);
492
- console.log(`\n Restart Claude Code to activate the MCP server.`);
530
+ }
531
+
532
+ if (showRestart) console.log(`\n Restart your AI coding agent to activate the MCP server.`);
533
+
534
+ // Clean up stale .claude.json MCP config from older versions
535
+ const claudeJsonPath = join(cwd, ".claude.json");
536
+ try {
537
+ const claudeJson = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
538
+ if (claudeJson.mcpServers?.openuispec) {
539
+ delete claudeJson.mcpServers.openuispec;
540
+ if (Object.keys(claudeJson.mcpServers).length === 0) delete claudeJson.mcpServers;
541
+ if (Object.keys(claudeJson).length === 0) {
542
+ unlinkSync(claudeJsonPath);
543
+ if (!quiet) console.log(` remove .claude.json (migrated MCP config)`);
544
+ } else {
545
+ writeFileSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
546
+ if (!quiet) console.log(` update .claude.json (removed stale MCP config)`);
547
+ }
493
548
  }
494
549
  } catch {
495
- // non-criticalskip silently
550
+ // .claude.json doesn't exist or not parseable nothing to clean up
496
551
  }
497
552
  }
498
553
 
@@ -761,30 +816,7 @@ export async function init(argv: string[] = []): Promise<void> {
761
816
 
762
817
  // ── MCP server configuration ────────────────────────────────────
763
818
 
764
- const claudeJsonPath = join(cwd, ".claude.json");
765
- const mcpConfig = {
766
- command: "openuispec",
767
- args: ["mcp"],
768
- };
769
-
770
- try {
771
- let claudeJson: Record<string, any> = {};
772
- try {
773
- claudeJson = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
774
- } catch {
775
- // file doesn't exist or isn't valid JSON — start fresh
776
- }
777
- if (!claudeJson.mcpServers) claudeJson.mcpServers = {};
778
- if (!claudeJson.mcpServers.openuispec) {
779
- claudeJson.mcpServers.openuispec = mcpConfig;
780
- writeFileSync(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
781
- if (!quiet) console.log(` create .claude.json (MCP server configured)`);
782
- } else {
783
- if (!quiet) console.log(` skip .claude.json (openuispec MCP already configured)`);
784
- }
785
- } catch {
786
- if (!quiet) console.log(` skip .claude.json (could not configure MCP server)`);
787
- }
819
+ configureMcp(cwd, false, quiet);
788
820
 
789
821
  if (answers.configureTargets) {
790
822
  if (!quiet) console.log("\nConfiguring target stacks...\n");
@@ -831,7 +863,7 @@ Commands:
831
863
  openuispec drift --snapshot --target ios Save current state + git baseline after target output exists
832
864
 
833
865
  AI rules have been added to CLAUDE.md and AGENTS.md.
834
- MCP server configured in .claude.json (AI assistants will use openuispec tools automatically).
866
+ MCP server configured (AI assistants will use openuispec tools automatically).
835
867
 
836
868
  Docs: https://openuispec.rsteam.uz
837
869
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openuispec",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "A semantic UI specification format for AI-native, platform-native app development",