@godxjp/ui 27.4.1 → 27.6.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 (36) hide show
  1. package/dist/components/data-display/range-timeline.js +9 -6
  2. package/dist/components/data-entry/upload-file-kind.d.ts +25 -0
  3. package/dist/components/data-entry/upload-file-kind.js +88 -0
  4. package/dist/components/data-entry/upload.d.ts +2 -2
  5. package/dist/components/data-entry/upload.js +10 -6
  6. package/dist/components/ui/avatar.d.ts +1 -1
  7. package/dist/components/ui/avatar.js +2 -0
  8. package/dist/components/ui/segmented.d.ts +7 -2
  9. package/dist/components/ui/toggle.d.ts +2 -2
  10. package/dist/components/ui/toggle.js +4 -0
  11. package/dist/contracts/measurement.json +1 -1
  12. package/dist/props/components/data-display.prop.d.ts +14 -0
  13. package/dist/props/components/data-entry.prop.d.ts +28 -2
  14. package/dist/props/registry.d.ts +6 -1
  15. package/dist/props/registry.js +6 -1
  16. package/dist/styles/control.css +18 -6
  17. package/dist/styles/data-display-layout.css +40 -8
  18. package/dist/styles/data-entry-layout.css +22 -0
  19. package/dist/tokens/components/control.css +1 -0
  20. package/dist/tokens/components/data-display.css +26 -0
  21. package/dist/tokens/components/segmented.css +4 -0
  22. package/dist/tokens/components/upload.css +4 -0
  23. package/docs/CUSTOMER-THEMING.md +26 -0
  24. package/docs/data-display/avatar.tsx +128 -11
  25. package/docs/data-display/prose.tsx +64 -0
  26. package/docs/data-display/timeline.tsx +36 -0
  27. package/docs/data-entry/calendar.tsx +2 -3
  28. package/docs/data-entry/segmented.tsx +55 -5
  29. package/docs/data-entry/toggle-group.tsx +15 -3
  30. package/docs/data-entry/toggle.tsx +39 -1
  31. package/docs/data-entry/upload.tsx +38 -0
  32. package/package.json +2 -2
  33. package/scripts/_agent-setup.mjs +80 -1
  34. package/scripts/cli.mjs +5 -1
  35. package/scripts/init-agent-kit.mjs +3 -0
  36. package/scripts/postinstall.mjs +5 -0
@@ -16,12 +16,14 @@ import {
16
16
  existsSync,
17
17
  mkdirSync,
18
18
  readFileSync,
19
+ realpathSync,
19
20
  renameSync,
20
21
  statSync,
21
22
  unlinkSync,
22
23
  writeFileSync,
23
24
  } from "node:fs";
24
- import { basename, dirname, join } from "node:path";
25
+ import { homedir } from "node:os";
26
+ import { basename, dirname, join, resolve } from "node:path";
25
27
  import { fileURLToPath } from "node:url";
26
28
 
27
29
  /** This package's own root — the source of the version we stamp with. */
@@ -425,6 +427,83 @@ export function ensureMcpJson(root) {
425
427
  return created ? "created" : "added";
426
428
  }
427
429
 
430
+ /**
431
+ * Registrations of the catalog server OUTSIDE the project — READ-ONLY (gh#722).
432
+ *
433
+ * `.mcp.json` is not the only place an agent's MCP servers come from. Claude Code keeps
434
+ * user-scoped servers in the top-level `mcpServers` of `~/.claude.json` (under
435
+ * `$CLAUDE_CONFIG_DIR` when that is set) and local-scoped ones — private to one checkout — under
436
+ * `projects[<absolute project path>].mcpServers` of the same file. Both are live beside the
437
+ * project's entry. Measured: a user-scoped `godxjp-ui` serving a ≤ 21.0.0 catalog answered next
438
+ * to the project's pinned `godx-ui`, and an agent took a removed component's page from it.
439
+ *
440
+ * That file belongs to the user, spans every project, and is not ours to edit: this only READS
441
+ * it. A missing, unreadable or malformed file yields nothing, silently. Returns
442
+ * `{ key, scope, pin }` per entry — never `env`, which is where secrets live.
443
+ */
444
+ export function findOutOfProjectUiMcp(
445
+ root,
446
+ configDir = process.env.CLAUDE_CONFIG_DIR || homedir(),
447
+ ) {
448
+ try {
449
+ const read = readJsonFile(join(configDir, ".claude.json"));
450
+ if (read.state !== "ok") return [];
451
+ const found = [];
452
+ const collect = (servers, scope) => {
453
+ if (!servers || typeof servers !== "object" || Array.isArray(servers)) return;
454
+ for (const [key, entry] of Object.entries(servers)) {
455
+ if (!runsUiMcp(entry)) continue;
456
+ const parts = [entry.command, ...(Array.isArray(entry.args) ? entry.args : [])];
457
+ const pin = parts.find(
458
+ (part) => typeof part === "string" && /(^|\/)@godxjp\/ui-mcp(@|$)/.test(part),
459
+ );
460
+ found.push({ key, scope, pin });
461
+ }
462
+ };
463
+ collect(read.json.mcpServers, "user");
464
+ const projects = read.json.projects;
465
+ if (projects && typeof projects === "object" && !Array.isArray(projects)) {
466
+ const paths = new Set([resolve(root)]);
467
+ try {
468
+ paths.add(realpathSync(root));
469
+ } catch {
470
+ // A root that cannot be resolved is looked up by its given path only.
471
+ }
472
+ for (const path of paths) collect(projects[path]?.mcpServers, "local");
473
+ }
474
+ return found;
475
+ } catch {
476
+ return [];
477
+ }
478
+ }
479
+
480
+ const shellWord = (word) => (/^[\w.@/-]+$/.test(word) ? word : `'${word.replace(/'/g, "'\\''")}'`);
481
+
482
+ /**
483
+ * What `sync-rules` and `init-agent` print about out-of-project registrations: key, pin, that it
484
+ * was left untouched, and the command that updates it. Empty string when there are none.
485
+ */
486
+ export function outOfProjectUiMcpReport(root, configDir) {
487
+ const found = findOutOfProjectUiMcp(root, configDir);
488
+ if (found.length === 0) return "";
489
+ const expected = mcpServerFor(root).args[0];
490
+ let out =
491
+ `\n @godxjp/ui → @godxjp/ui-mcp is ALSO registered outside this project, in Claude Code's ` +
492
+ `.claude.json.\n It answers beside the project's .mcp.json entry (${expected}) and an agent ` +
493
+ `can call either — the tool names differ only by the key.\n`;
494
+ for (const { key, scope, pin } of found) {
495
+ const k = shellWord(key);
496
+ const runs = /@godxjp\/ui-mcp@\S+$/.test(pin ?? "")
497
+ ? pin
498
+ : `${pin ?? "@godxjp/ui-mcp"} (unpinned: resolves the latest release)`;
499
+ out +=
500
+ ` • "${key}" (${scope} scope) runs ${runs} — outside the project, left untouched.\n` +
501
+ ` remove it: claude mcp remove ${k} -s ${scope}\n` +
502
+ ` or re-pin: claude mcp remove ${k} -s ${scope} && claude mcp add ${k} -s ${scope} -- npx ${expected}\n`;
503
+ }
504
+ return out;
505
+ }
506
+
428
507
  /** Ensure `.claude/settings.json` has the audit PostToolUse + workflow SessionStart hooks. */
429
508
  export function ensureClaudeHooks(root) {
430
509
  const path = join(root, ".claude", "settings.json");
package/scripts/cli.mjs CHANGED
@@ -34,7 +34,11 @@ const HELP = {
34
34
  Refresh the package-owned agent files for the installed @godxjp/ui version: the godx-ui entry in
35
35
  .mcp.json, the managed CLAUDE.md block, .claude/godxjp-ui-workflow.md and .ai/rules/godxjp-ui.md.
36
36
  It is the postinstall step, run by hand — use it when the app installs with ignore-scripts=true,
37
- where postinstall never runs and the rules go stale. Silent no-op in CI and when opted out.`,
37
+ where postinstall never runs and the rules go stale. Silent no-op in CI and when opted out.
38
+
39
+ It also READS Claude Code's ~/.claude.json and reports any @godxjp/ui-mcp registered there (user
40
+ scope, or local scope for this project): key, pin, and the claude mcp command that updates it.
41
+ That file is outside the project and is never written; env values are never printed.`,
38
42
  audit: `godxjp-ui audit [dir …] [--changed] [--format json] [--quiet] [--rules]
39
43
 
40
44
  Static UI-standardization audit over source (regex, no browser, fast). Exits non-zero on errors.
@@ -4,6 +4,7 @@ import {
4
4
  ensureClaudeHooks,
5
5
  ensureClaudeMd,
6
6
  ensureMcpJson,
7
+ outOfProjectUiMcpReport,
7
8
  shouldSkip,
8
9
  writeWorkflowMd,
9
10
  } from "./_agent-setup.mjs";
@@ -28,6 +29,8 @@ console.log(
28
29
  );
29
30
  console.log(` • .claude/godxjp-ui-workflow.md — ${md ? "created" : "already present"}`);
30
31
  console.log(` • CLAUDE.md — godxjp-ui mandate (${claudeMd})`);
32
+ const outside = outOfProjectUiMcpReport(root);
33
+ if (outside) console.log(outside);
31
34
  console.log(`
32
35
  The auto-audit hook now runs on every Write/Edit of a .tsx file and feeds findings
33
36
  back to the agent — it cannot skip the audit. Restart your agent to load the MCP + hooks.
@@ -8,6 +8,7 @@ import {
8
8
  ensureClaudeMd,
9
9
  ensureMcpJson,
10
10
  ensureConsumerRules,
11
+ outOfProjectUiMcpReport,
11
12
  refreshGuineaPigSkill,
12
13
  shouldSkip,
13
14
  writeWorkflowMd,
@@ -25,6 +26,10 @@ try {
25
26
  if (r.startsWith("left untouched") || r.startsWith("present (custom godx-ui")) {
26
27
  console.log(`\n @godxjp/ui → .mcp.json ${r}\n`);
27
28
  }
29
+ // A registration outside the project is reported whatever the project file says, before any of
30
+ // the quiet exits below: it is live beside ours and nothing here will ever change it (gh#722).
31
+ const outside = outOfProjectUiMcpReport(root);
32
+ if (outside) console.log(outside);
28
33
  // The mandate is plain text the agent reads every turn (CLAUDE.md block + workflow file). It
29
34
  // changes nothing in the dev loop, so it is installed by default: an agent that never saw the
30
35
  // but no mandate). Only the hooks — which DO change the loop — stay behind `init-agent`.