@nqlib/nqui 0.5.2 → 0.5.4
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.
package/dist/styles.css
CHANGED
|
@@ -792,14 +792,11 @@
|
|
|
792
792
|
nqui Additional System Variables
|
|
793
793
|
============================================ */
|
|
794
794
|
|
|
795
|
-
/*
|
|
796
|
-
|
|
795
|
+
/* Default light theme variables (.mid / .dark blocks follow) */
|
|
796
|
+
/* ============================================
|
|
797
797
|
nqui Color System & Design Tokens
|
|
798
798
|
============================================ */
|
|
799
799
|
|
|
800
|
-
:root + html.light = warm paper; html.mid = separate token block (showcase / comparison).
|
|
801
|
-
* Dark = .dark. Showcase app uses next-themes classes light | mid | dark.
|
|
802
|
-
*/
|
|
803
800
|
:root {
|
|
804
801
|
/* ============================================
|
|
805
802
|
Z-Index Elevation Scale
|
|
@@ -1205,9 +1202,4 @@
|
|
|
1205
1202
|
--sidebar-accent-foreground: oklch(0.92 0 0);
|
|
1206
1203
|
--sidebar-border: oklch(1 0 0 / 10%);
|
|
1207
1204
|
--sidebar-ring: oklch(0.556 0 0);
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
/*
|
|
1211
|
-
* html.light — next-themes; surface tokens match :root (warm paper).
|
|
1212
|
-
* html.mid — next-themes; surfaces use .mid block above (distinct from light).
|
|
1213
|
-
*/
|
|
1205
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
## name: nqui
|
|
4
|
-
|
|
2
|
+
name: nqui
|
|
5
3
|
description: Hub for nqui component library skills and impeccable design skills. Use /nqui-components, /nqui-design-system, /impeccable, /audit, or specific skill names to invoke them.
|
|
4
|
+
---
|
|
6
5
|
|
|
7
6
|
# nqui Skills (Hub)
|
|
8
7
|
|
|
@@ -14,7 +13,6 @@ Installed into `.cursor/nqui-skills/` via `npx @nqlib/nqui init-skills`.
|
|
|
14
13
|
|
|
15
14
|
## nqui Component Library
|
|
16
15
|
|
|
17
|
-
|
|
18
16
|
| Skill | When to use |
|
|
19
17
|
| ------------------------------- | ------------------------------------------------------------------ |
|
|
20
18
|
| **nqui-components** | Implementing UI, choosing components, component props and examples |
|
|
@@ -24,14 +22,12 @@ Installed into `.cursor/nqui-skills/` via `npx @nqlib/nqui init-skills`.
|
|
|
24
22
|
| **nqui-bundle-size** | Bundle size best practices when adding deps or creating packages |
|
|
25
23
|
| **nqui-local-published-toggle** | Switching between local and published @nqlib/nqui |
|
|
26
24
|
|
|
27
|
-
|
|
28
25
|
---
|
|
29
26
|
|
|
30
27
|
## Impeccable Design Skills
|
|
31
28
|
|
|
32
29
|
Design quality and anti-pattern detection. Run `/impeccable teach` first to establish design context.
|
|
33
30
|
|
|
34
|
-
|
|
35
31
|
| Skill | When to use |
|
|
36
32
|
| -------------- | ----------------------------------------------------------------------------- |
|
|
37
33
|
| **impeccable** | Build distinctive, production-grade UI; avoid AI slop aesthetics |
|
|
@@ -52,7 +48,6 @@ Design quality and anti-pattern detection. Run `/impeccable teach` first to esta
|
|
|
52
48
|
| **/critique** | Heuristic-based UI review |
|
|
53
49
|
| **/overdrive** | Push good UI to excellent |
|
|
54
50
|
|
|
55
|
-
|
|
56
51
|
---
|
|
57
52
|
|
|
58
53
|
## Usage
|
|
@@ -62,4 +57,4 @@ Skills are invoked by name — e.g. `/nqui-components`, `/impeccable`, `/audit i
|
|
|
62
57
|
For component questions, always read the relevant doc first:
|
|
63
58
|
|
|
64
59
|
- `.cursor/nqui-skills/components/nqui-<name>.md` (after init-skills)
|
|
65
|
-
- `node_modules/@nqlib/nqui/docs/components/nqui-<name>.md` (npm install)
|
|
60
|
+
- `node_modules/@nqlib/nqui/docs/components/nqui-<name>.md` (npm install)
|
package/package.json
CHANGED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: nqui component implementation guide. Use when building UI with @nqlib/nqui.
|
|
3
|
+
globs: "**/*.{ts,tsx}"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# nqui Component Guidelines
|
|
8
|
+
|
|
9
|
+
When building UI with @nqlib/nqui, follow these rules so the AI builds components correctly.
|
|
10
|
+
|
|
11
|
+
## Install (full: nqui + all optional peers)
|
|
12
|
+
|
|
13
|
+
Run this when setting up a new project or when components fail due to missing peers:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @nqlib/nqui @hugeicons/react @hugeicons/core-free-icons cmdk @dnd-kit/core @dnd-kit/modifiers @dnd-kit/sortable @dnd-kit/utilities embla-carousel-react @tanstack/react-table react-day-picker date-fns sonner vaul react-resizable-panels
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Alternative (npm): `npm install @nqlib/nqui @hugeicons/react @hugeicons/core-free-icons cmdk @dnd-kit/core @dnd-kit/modifiers @dnd-kit/sortable @dnd-kit/utilities embla-carousel-react @tanstack/react-table react-day-picker date-fns sonner vaul react-resizable-panels`
|
|
20
|
+
|
|
21
|
+
Or use `npx @nqlib/nqui install-peers` to auto-detect package manager.
|
|
22
|
+
|
|
23
|
+
## Import
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { Button, ToggleGroup, ToggleGroupItem, Select } from "@nqlib/nqui"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**CSS:** `@import "@nqlib/nqui/styles"` (run `npx @nqlib/nqui init-css` first)
|
|
30
|
+
|
|
31
|
+
## CSS Setup (First-Run Fix)
|
|
32
|
+
|
|
33
|
+
`init-css` creates `nqui/index.css` and `nqui/nqui-setup.css` in the project root. **User must manually add the import** to their main CSS file. If nqui components render without styles or user reports "CSS import issue":
|
|
34
|
+
|
|
35
|
+
1. **Check** if the main CSS file has the nqui import. Main files: `app/globals.css` (Next.js), `src/index.css` (Vite), `app/root.css` (Remix).
|
|
36
|
+
|
|
37
|
+
2. **Fix options:**
|
|
38
|
+
- **Option A (recommended):** Add `@import "@nqlib/nqui/styles";` near the top of the main CSS file (after `@import "tailwindcss"`).
|
|
39
|
+
- **Option B:** If `nqui/nqui-setup.css` exists, copy its contents to the very top of the main CSS file.
|
|
40
|
+
|
|
41
|
+
3. **Next.js only:** Ensure `@source` directives exist for Tailwind v4:
|
|
42
|
+
```css
|
|
43
|
+
@source "./**/*.{js,ts,jsx,tsx,mdx}";
|
|
44
|
+
@source "../components/**/*.{js,ts,jsx,tsx,mdx}";
|
|
45
|
+
@source "../node_modules/@nqlib/nqui/dist/**/*.js";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
4. **Vite:** Simpler – just `@import "tailwindcss";` + `@import "tw-animate-css";` + `@import "@nqlib/nqui/styles";`
|
|
49
|
+
|
|
50
|
+
If user hasn't run init-css, suggest: `npx @nqlib/nqui init-css` then add the import as above.
|
|
51
|
+
|
|
52
|
+
## Component Selection Rules
|
|
53
|
+
|
|
54
|
+
### Inline/Toolbar Selection → ToggleGroup (never RadioGroup)
|
|
55
|
+
|
|
56
|
+
| Context | Use | NOT |
|
|
57
|
+
|---------|-----|-----|
|
|
58
|
+
| View mode (List/Grid), scale (Linear/Log), size (S/M/L) | **ToggleGroup** `type="single" variant="segmented"` | RadioGroup |
|
|
59
|
+
| Format toolbar (Bold/Italic/Underline) | **ToggleGroup** `type="multiple"` | Multiple Checkboxes |
|
|
60
|
+
| Toolbar actions (Undo/Redo) | **ButtonGroup** | — |
|
|
61
|
+
| Single on/off (Bold, Mute) | **Toggle** | — |
|
|
62
|
+
|
|
63
|
+
**Rule:** Inline/toolbar = ToggleGroup. RadioGroup only for form context (settings modal, stacked list).
|
|
64
|
+
|
|
65
|
+
### Quick Decision
|
|
66
|
+
|
|
67
|
+
- **ToggleGroup segmented** → 1 of N, 2–4 options, primary fill on selected
|
|
68
|
+
- **ToggleGroup single** → 1 of N, neutral styling
|
|
69
|
+
- **ToggleGroup multiple** → 0+ of N (bold/italic)
|
|
70
|
+
- **Select** → 1 of N, 5+ options or dropdown
|
|
71
|
+
- **ButtonGroup** → Actions (each click = action)
|
|
72
|
+
- **RadioGroup** → Form context only
|
|
73
|
+
|
|
74
|
+
## Context-First Design
|
|
75
|
+
|
|
76
|
+
**Rule:** Never show Toggle/ToggleGroup/ButtonGroup floating alone. Place in realistic context:
|
|
77
|
+
- Document editor: toolbar above content, `bg-muted/30`, `Separator` between groups
|
|
78
|
+
- Chart/settings: label + inline controls, `rounded-lg border bg-muted/30 p-3`
|
|
79
|
+
|
|
80
|
+
## Shared Conventions
|
|
81
|
+
|
|
82
|
+
- **Control sizes:** sm=h-6, default=h-7, lg=h-8
|
|
83
|
+
- **Enhanced vs Core:** Default is enhanced. Use `CoreButton`, `CoreBadge` for plain shadcn.
|
|
84
|
+
- **Z-index:** Use CSS vars only, e.g. `z-[var(--z-modal)]`. Never hardcode `z-10`, `z-50`.
|
|
85
|
+
- **Grouped controls:** ButtonGroup, ToggleGroup share container border; ToggleGroup uses item dividers.
|
|
86
|
+
|
|
87
|
+
## Skills (load for install or component questions)
|
|
88
|
+
|
|
89
|
+
- **Install/setup:** Load `.cursor/skills/nqui-install/SKILL.md` — commands to execute
|
|
90
|
+
- **Components:** Load `.cursor/skills/nqui-components/SKILL.md` — routing for per-component docs
|
|
91
|
+
- **After `init-skills`:** `.cursor/nqui-skills/COMPONENTS_INDEX.md` then **one** file under `.cursor/nqui-skills/components/nqui-<name>.md`
|
|
92
|
+
|
|
93
|
+
Fallback (no init-skills): `node_modules/@nqlib/nqui/docs/components/README.md` (index, skim sections) then `nqui-<name>.md`.
|
package/scripts/publish-npmjs.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
9
|
-
import { execSync } from 'child_process';
|
|
9
|
+
import { execSync, spawn } from 'child_process';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { dirname, join } from 'path';
|
|
12
12
|
|
|
@@ -16,116 +16,164 @@ const rootDir = join(__dirname, '..');
|
|
|
16
16
|
const packageJsonPath = join(rootDir, 'package.json');
|
|
17
17
|
const npmrcPath = join(rootDir, '.npmrc');
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
function printSslTroubleshooting() {
|
|
20
|
+
console.error(`
|
|
21
|
+
💡 TLS / network (e.g. ERR_SSL_SSL\\TLS_ALERT_BAD_RECORD_MAC) is usually environmental:
|
|
22
|
+
• Run publish again; transient failures often work on a second attempt
|
|
23
|
+
• Disable VPN or try another network; corporate proxies and inspection break TLS
|
|
24
|
+
• Update Node LTS; ensure no antivirus is MITM’ing npm traffic
|
|
25
|
+
• Retry later if registry.npmjs.com is flaking
|
|
26
|
+
• Set NPM_PUBLISH_RETRIES=5 for more attempts (default 3)
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
30
|
+
async function main() {
|
|
31
|
+
// Read package.json
|
|
32
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
25
33
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
for (const name of workspaceDeps) {
|
|
30
|
-
if (packageJson.dependencies?.[name] === 'workspace:*') {
|
|
31
|
-
delete packageJson.dependencies[name];
|
|
32
|
-
console.log(` Removed ${name} (workspace dep)`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
34
|
+
// Save originals for restore
|
|
35
|
+
const originalPublishConfig = packageJson.publishConfig;
|
|
36
|
+
const originalDependencies = { ...packageJson.dependencies };
|
|
35
37
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Write modified package.json
|
|
43
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
44
|
-
|
|
45
|
-
// Handle .npmrc file if it exists
|
|
46
|
-
let originalNpmrc = null;
|
|
47
|
-
let npmrcExists = false;
|
|
48
|
-
|
|
49
|
-
if (existsSync(npmrcPath)) {
|
|
50
|
-
npmrcExists = true;
|
|
51
|
-
originalNpmrc = readFileSync(npmrcPath, 'utf-8');
|
|
52
|
-
|
|
53
|
-
// Remove or comment out scoped registry line that points to GitHub Packages
|
|
54
|
-
const lines = originalNpmrc.split('\n');
|
|
55
|
-
const modifiedLines = lines.map(line => {
|
|
56
|
-
// Comment out scoped registry lines for @nqlib
|
|
57
|
-
if (line.trim().startsWith('@nqlib:registry=')) {
|
|
58
|
-
return `# ${line} # Temporarily disabled for npmjs.com publish`;
|
|
38
|
+
// Remove workspace:* deps (npm doesn't support workspace: protocol).
|
|
39
|
+
const workspaceDeps = ['@nqlib/nqcode', '@nqlib/nqappbuilder'];
|
|
40
|
+
for (const name of workspaceDeps) {
|
|
41
|
+
if (packageJson.dependencies?.[name] === 'workspace:*') {
|
|
42
|
+
delete packageJson.dependencies[name];
|
|
43
|
+
console.log(` Removed ${name} (workspace dep)`);
|
|
59
44
|
}
|
|
60
|
-
|
|
61
|
-
});
|
|
45
|
+
}
|
|
62
46
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
packageJson.publishConfig = {
|
|
48
|
+
registry: 'https://registry.npmjs.com',
|
|
49
|
+
access: 'public',
|
|
50
|
+
};
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
52
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
53
|
+
|
|
54
|
+
let originalNpmrc = null;
|
|
55
|
+
let npmrcExists = false;
|
|
56
|
+
|
|
57
|
+
if (existsSync(npmrcPath)) {
|
|
58
|
+
npmrcExists = true;
|
|
59
|
+
originalNpmrc = readFileSync(npmrcPath, 'utf-8');
|
|
60
|
+
const lines = originalNpmrc.split('\n');
|
|
61
|
+
const modifiedLines = lines.map((line) => {
|
|
62
|
+
if (line.trim().startsWith('@nqlib:registry=')) {
|
|
63
|
+
return `# ${line} # Temporarily disabled for npmjs.com publish`;
|
|
77
64
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.
|
|
82
|
-
console.error('💡 Please run: npm login --registry=https://registry.npmjs.com');
|
|
83
|
-
console.error('💡 Or create an access token at: https://www.npmjs.com/settings/YOUR_USERNAME/tokens');
|
|
84
|
-
throw new Error('Authentication required. Please login to npmjs.com first.');
|
|
65
|
+
return line;
|
|
66
|
+
});
|
|
67
|
+
writeFileSync(npmrcPath, modifiedLines.join('\n'));
|
|
68
|
+
console.log('📝 Temporarily modified .npmrc');
|
|
85
69
|
}
|
|
86
70
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
try {
|
|
72
|
+
console.log('🔐 Checking npm authentication...');
|
|
73
|
+
try {
|
|
74
|
+
const whoami = execSync('npm whoami --registry=https://registry.npmjs.com', {
|
|
75
|
+
encoding: 'utf-8',
|
|
76
|
+
cwd: rootDir,
|
|
77
|
+
env: {
|
|
78
|
+
...process.env,
|
|
79
|
+
npm_config_registry: 'https://registry.npmjs.com',
|
|
80
|
+
},
|
|
81
|
+
}).trim();
|
|
82
|
+
console.log(`✅ Logged in as: ${whoami}`);
|
|
83
|
+
} catch {
|
|
84
|
+
console.error('❌ Not logged in to npmjs.com');
|
|
85
|
+
console.error('💡 Please run: npm login --registry=https://registry.npmjs.com');
|
|
86
|
+
console.error(
|
|
87
|
+
'💡 Or create an access token at: https://www.npmjs.com/settings/YOUR_USERNAME/tokens'
|
|
88
|
+
);
|
|
89
|
+
throw new Error('Authentication required. Please login to npmjs.com first.');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const publishEnv = {
|
|
92
93
|
...process.env,
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
npm_config_registry: 'https://registry.npmjs.com',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const maxAttempts = Math.min(
|
|
98
|
+
5,
|
|
99
|
+
Math.max(1, parseInt(process.env.NPM_PUBLISH_RETRIES || '3', 10) || 3)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const runPublish = () =>
|
|
103
|
+
new Promise((resolve, reject) => {
|
|
104
|
+
const child = spawn(
|
|
105
|
+
'npm',
|
|
106
|
+
['publish', '--registry=https://registry.npmjs.com', '--access', 'public'],
|
|
107
|
+
{ stdio: 'inherit', cwd: rootDir, env: publishEnv, shell: false }
|
|
108
|
+
);
|
|
109
|
+
child.on('error', reject);
|
|
110
|
+
child.on('close', (code) => {
|
|
111
|
+
if (code === 0) resolve();
|
|
112
|
+
else {
|
|
113
|
+
const err = new Error(`npm publish exited with code ${code}`);
|
|
114
|
+
err.status = code;
|
|
115
|
+
reject(err);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log('📦 Publishing to npmjs.com...');
|
|
121
|
+
let lastError;
|
|
122
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
123
|
+
try {
|
|
124
|
+
await runPublish();
|
|
125
|
+
lastError = null;
|
|
126
|
+
break;
|
|
127
|
+
} catch (e) {
|
|
128
|
+
lastError = e;
|
|
129
|
+
if (attempt < maxAttempts) {
|
|
130
|
+
const wait = attempt * 2000;
|
|
131
|
+
console.warn(
|
|
132
|
+
`⚠️ Publish failed (attempt ${attempt}/${maxAttempts}). Retrying in ${wait / 1000}s (transient TLS/network often succeeds on retry)…`
|
|
133
|
+
);
|
|
134
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
95
137
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
} catch (error) {
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
if (lastError) throw lastError;
|
|
139
|
+
console.log('✅ Published to npmjs.com successfully!');
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error('❌ Failed to publish to npmjs.com');
|
|
142
|
+
if (error.message && error.message.includes('Authentication required')) {
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
const errText = `${error.message || ''} ${(error.output && error.output.toString()) || ''}`;
|
|
146
|
+
if (error.status === 404 || errText.includes('404')) {
|
|
147
|
+
console.error('💡 Package not found. This might be the first publish.');
|
|
148
|
+
console.error('💡 Make sure the @nqlib scope exists on npmjs.com');
|
|
149
|
+
console.error('💡 For scoped packages, you need to own the scope or be added to it');
|
|
150
|
+
}
|
|
151
|
+
if (error.status === 401 || errText.includes('401')) {
|
|
152
|
+
console.error(
|
|
153
|
+
'💡 Authentication failed. Please login: npm login --registry=https://registry.npmjs.com'
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
printSslTroubleshooting();
|
|
101
157
|
throw error;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
delete packageJson.publishConfig;
|
|
118
|
-
}
|
|
119
|
-
if (originalDependencies) {
|
|
120
|
-
packageJson.dependencies = originalDependencies;
|
|
121
|
-
}
|
|
122
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
123
|
-
console.log('🔄 Restored package.json');
|
|
124
|
-
|
|
125
|
-
// Restore .npmrc if it existed
|
|
126
|
-
if (npmrcExists && originalNpmrc !== null) {
|
|
127
|
-
writeFileSync(npmrcPath, originalNpmrc);
|
|
128
|
-
console.log('🔄 Restored .npmrc');
|
|
158
|
+
} finally {
|
|
159
|
+
if (originalPublishConfig) {
|
|
160
|
+
packageJson.publishConfig = originalPublishConfig;
|
|
161
|
+
} else {
|
|
162
|
+
delete packageJson.publishConfig;
|
|
163
|
+
}
|
|
164
|
+
if (originalDependencies) {
|
|
165
|
+
packageJson.dependencies = originalDependencies;
|
|
166
|
+
}
|
|
167
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
168
|
+
console.log('🔄 Restored package.json');
|
|
169
|
+
if (npmrcExists && originalNpmrc !== null) {
|
|
170
|
+
writeFileSync(npmrcPath, originalNpmrc);
|
|
171
|
+
console.log('🔄 Restored .npmrc');
|
|
172
|
+
}
|
|
129
173
|
}
|
|
130
174
|
}
|
|
131
175
|
|
|
176
|
+
main().catch((e) => {
|
|
177
|
+
if (e && e.message) console.error(e.message);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
});
|
|
@@ -6,8 +6,30 @@
|
|
|
6
6
|
* The skill content itself is read from the SSOT by download-skills.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { readFileSync, existsSync } from 'fs';
|
|
10
|
+
import { dirname, resolve } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
9
12
|
import { FULL_PEER_LIST } from './peer-deps.js';
|
|
10
13
|
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Full body for `.cursor/rules/nqui-components.mdc` (shipped next to this file in the npm package).
|
|
18
|
+
*/
|
|
19
|
+
export function buildCursorRule() {
|
|
20
|
+
const shipped = resolve(__dirname, 'cursor-rule-nqui-components.mdc');
|
|
21
|
+
if (existsSync(shipped)) {
|
|
22
|
+
return readFileSync(shipped, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
const monorepo = resolve(__dirname, '../.cursor/rules/nqui-components.mdc');
|
|
25
|
+
if (existsSync(monorepo)) {
|
|
26
|
+
return readFileSync(monorepo, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
throw new Error(
|
|
29
|
+
'nqui: missing cursor rule template. Expected cursor-rule-nqui-components.mdc next to skill-templates.js'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
11
33
|
const fullInstallCmd = `pnpm add @nqlib/nqui ${FULL_PEER_LIST.join(' ')}`;
|
|
12
34
|
const npmInstallCmd = `npm install @nqlib/nqui ${FULL_PEER_LIST.join(' ')}`;
|
|
13
35
|
|