@devground/ui-conventions 0.1.0 → 0.2.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.
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ /**
7
+ * Copies a directory tree, never overwriting a file that already exists at the
8
+ * destination.
9
+ *
10
+ * This guard is the package's core promise: re-running the installer after an
11
+ * upgrade pulls in new files without clobbering local edits to a skill. It lives
12
+ * in its own module (rather than inline in `setup.js`) so it can be tested —
13
+ * `setup.js` runs its work at import time, so anything defined there is
14
+ * untestable without executing the installer.
15
+ *
16
+ * @param {string} src Source directory.
17
+ * @param {string} dst Destination directory (created if missing).
18
+ * @returns {{ written: number, skipped: number }} Files copied vs. left alone.
19
+ */
20
+ function copyDirGuarded(src, dst) {
21
+ fs.mkdirSync(dst, { recursive: true });
22
+ let written = 0;
23
+ let skipped = 0;
24
+
25
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
26
+ const srcPath = path.join(src, entry.name);
27
+ const dstPath = path.join(dst, entry.name);
28
+
29
+ if (entry.isDirectory()) {
30
+ const sub = copyDirGuarded(srcPath, dstPath);
31
+ written += sub.written;
32
+ skipped += sub.skipped;
33
+ } else if (entry.isFile()) {
34
+ if (fs.existsSync(dstPath)) {
35
+ skipped++;
36
+ } else {
37
+ fs.copyFileSync(srcPath, dstPath);
38
+ written++;
39
+ }
40
+ }
41
+ }
42
+
43
+ return { written, skipped };
44
+ }
45
+
46
+ module.exports = { copyDirGuarded };
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@devground/ui-conventions",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "UI convention skill for Claude Code — loads a project's frontend conventions (own components vs browser primitives, es-CL input formatting for RUT/phone/currency, accessibility and focus, error/loading states, microinteractions) as context BEFORE generating or editing UI, with an optional per-project overlay.",
5
5
  "bin": {
6
6
  "devground-ui-conventions": "./setup.js"
7
7
  },
8
8
  "files": [
9
9
  "setup.js",
10
- "skills/"
10
+ "skills/",
11
+ "lib/",
12
+ "!lib/*.test.js"
11
13
  ],
12
14
  "keywords": [
13
15
  "ui",
@@ -37,5 +39,19 @@
37
39
  "bugs": {
38
40
  "url": "https://github.com/elkisdm/devground/issues"
39
41
  },
40
- "scripts": {}
42
+ "devground": {
43
+ "status": "supported",
44
+ "graduatedBy": "ADR-0032",
45
+ "graduatedAt": "2026-09-07"
46
+ },
47
+ "devDependencies": {
48
+ "vitest": "^2.1.0",
49
+ "@vitest/coverage-v8": "^2.1.0",
50
+ "@devground/vitest-config": "0.3.0"
51
+ },
52
+ "scripts": {
53
+ "test": "vitest run",
54
+ "test:watch": "vitest",
55
+ "test:coverage": "vitest run --coverage"
56
+ }
41
57
  }
package/setup.js CHANGED
@@ -26,29 +26,7 @@ function info(msg) {
26
26
  console.log(` \x1b[36m→\x1b[0m ${msg}`);
27
27
  }
28
28
 
29
- /** Copies a tree, skipping files that already exist at the destination. */
30
- function copyDirGuarded(src, dst) {
31
- fs.mkdirSync(dst, { recursive: true });
32
- let written = 0;
33
- let skipped = 0;
34
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
35
- const srcPath = path.join(src, entry.name);
36
- const dstPath = path.join(dst, entry.name);
37
- if (entry.isDirectory()) {
38
- const sub = copyDirGuarded(srcPath, dstPath);
39
- written += sub.written;
40
- skipped += sub.skipped;
41
- } else if (entry.isFile()) {
42
- if (fs.existsSync(dstPath)) {
43
- skipped++;
44
- } else {
45
- fs.copyFileSync(srcPath, dstPath);
46
- written++;
47
- }
48
- }
49
- }
50
- return { written, skipped };
51
- }
29
+ const { copyDirGuarded } = require('./lib/copy-guarded.js');
52
30
 
53
31
  const global = process.argv.includes('--global');
54
32
  const baseDir = global ? os.homedir() : process.cwd();