@mindfiredigital/ignix-lite-cli 1.4.4 → 1.6.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.
- package/package.json +7 -3
- package/.turbo/turbo-build.log +0 -13
- package/CHANGELOG.md +0 -77
- package/src/commands/add.ts +0 -146
- package/src/commands/build.ts +0 -70
- package/src/commands/check-a11y.ts +0 -61
- package/src/commands/info.ts +0 -66
- package/src/commands/init.ts +0 -91
- package/src/commands/list.ts +0 -22
- package/src/commands/mcp.ts +0 -233
- package/src/commands/preview.ts +0 -81
- package/src/commands/theme.ts +0 -96
- package/src/commands/validate.ts +0 -51
- package/src/index.ts +0 -91
- package/tsconfig.json +0 -15
- package/tsup.config.ts +0 -11
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindfiredigital/ignix-lite-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"description": "CLI tool for Ignix-Lite project scaffolding, validation, and theming",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"ignix-lite": "./dist/index.js"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
10
14
|
"dependencies": {
|
|
11
15
|
"commander": "^13.1.0",
|
|
12
16
|
"node-html-parser": "^7.1.0",
|
|
@@ -14,8 +18,8 @@
|
|
|
14
18
|
"picocolors": "^1.1.1",
|
|
15
19
|
"prompts": "^2.4.2",
|
|
16
20
|
"zod": "^3.24.2",
|
|
17
|
-
"@mindfiredigital/ignix-lite-engine": "1.4.
|
|
18
|
-
"@mindfiredigital/ignix-lite-mcp": "1.6.
|
|
21
|
+
"@mindfiredigital/ignix-lite-engine": "1.4.4",
|
|
22
|
+
"@mindfiredigital/ignix-lite-mcp": "1.6.5"
|
|
19
23
|
},
|
|
20
24
|
"devDependencies": {
|
|
21
25
|
"@types/node": "^25.8.0",
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @mindfiredigital/ignix-lite-cli@1.4.4 build /home/runner/work/ignix-lite/ignix-lite/packages/cli
|
|
3
|
-
> tsup
|
|
4
|
-
|
|
5
|
-
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
-
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v8.5.1
|
|
8
|
-
[34mCLI[39m Using tsup config: /home/runner/work/ignix-lite/ignix-lite/packages/cli/tsup.config.ts
|
|
9
|
-
[34mCLI[39m Target: es2022
|
|
10
|
-
[34mCLI[39m Cleaning output folder
|
|
11
|
-
[34mESM[39m Build start
|
|
12
|
-
[32mESM[39m [1mdist/index.js [22m[32m29.18 KB[39m
|
|
13
|
-
[32mESM[39m ⚡️ Build success in 25ms
|
package/CHANGELOG.md
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# @mindfiredigital/ignix-lite-cli
|
|
2
|
-
|
|
3
|
-
## 1.4.4
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- Updated dependencies []:
|
|
8
|
-
- @mindfiredigital/ignix-lite-mcp@1.6.4
|
|
9
|
-
- @mindfiredigital/ignix-lite-engine@1.4.3
|
|
10
|
-
|
|
11
|
-
## 1.4.3
|
|
12
|
-
|
|
13
|
-
### Patch Changes
|
|
14
|
-
|
|
15
|
-
- resolve package dependency issues
|
|
16
|
-
|
|
17
|
-
- Updated dependencies []:
|
|
18
|
-
- @mindfiredigital/ignix-lite-engine@1.4.2
|
|
19
|
-
- @mindfiredigital/ignix-lite-mcp@1.6.3
|
|
20
|
-
|
|
21
|
-
## 1.4.1
|
|
22
|
-
|
|
23
|
-
### Patch Changes
|
|
24
|
-
|
|
25
|
-
- resolve package dependency issue
|
|
26
|
-
|
|
27
|
-
- Updated dependencies []:
|
|
28
|
-
- @mindfiredigital/ignix-lite-mcp@1.6.1
|
|
29
|
-
- @mindfiredigital/ignix-lite-engine@1.4.1
|
|
30
|
-
|
|
31
|
-
## 1.4.0
|
|
32
|
-
|
|
33
|
-
### Minor Changes
|
|
34
|
-
|
|
35
|
-
- resolve package dependencies workspace protocol and release update
|
|
36
|
-
|
|
37
|
-
### Patch Changes
|
|
38
|
-
|
|
39
|
-
- Updated dependencies []:
|
|
40
|
-
- @mindfiredigital/ignix-lite-mcp@1.6.0
|
|
41
|
-
- @mindfiredigital/ignix-lite-engine@1.4.0
|
|
42
|
-
|
|
43
|
-
## 1.3.0
|
|
44
|
-
|
|
45
|
-
### Minor Changes
|
|
46
|
-
|
|
47
|
-
- resolve package dependencies workspace protocol and release update
|
|
48
|
-
|
|
49
|
-
### Patch Changes
|
|
50
|
-
|
|
51
|
-
- Updated dependencies []:
|
|
52
|
-
- @mindfiredigital/ignix-lite-mcp@1.5.0
|
|
53
|
-
- @mindfiredigital/ignix-lite-engine@1.3.0
|
|
54
|
-
|
|
55
|
-
## 1.2.0
|
|
56
|
-
|
|
57
|
-
### Minor Changes
|
|
58
|
-
|
|
59
|
-
- implement cli commands and decouple mcp server engine
|
|
60
|
-
|
|
61
|
-
### Patch Changes
|
|
62
|
-
|
|
63
|
-
- Updated dependencies []:
|
|
64
|
-
- @mindfiredigital/ignix-lite-mcp@1.4.0
|
|
65
|
-
- @mindfiredigital/ignix-lite-engine@1.2.0
|
|
66
|
-
|
|
67
|
-
## 1.1.0
|
|
68
|
-
|
|
69
|
-
### Minor Changes
|
|
70
|
-
|
|
71
|
-
- introduce expanded CLI and decoupled engine validation
|
|
72
|
-
|
|
73
|
-
### Patch Changes
|
|
74
|
-
|
|
75
|
-
- Updated dependencies []:
|
|
76
|
-
- @mindfiredigital/ignix-lite-mcp@1.3.0
|
|
77
|
-
- @mindfiredigital/ignix-lite-engine@1.1.0
|
package/src/commands/add.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import pc from 'picocolors'
|
|
2
|
-
|
|
3
|
-
const COMPONENT_TEMPLATES: Record<string, string> = {
|
|
4
|
-
accordion: `<details>
|
|
5
|
-
<summary>Accordion Title</summary>
|
|
6
|
-
<p>Accordion contents goes here...</p>
|
|
7
|
-
</details>`,
|
|
8
|
-
alert: `<aside data-intent="info">
|
|
9
|
-
<strong>Head's up!</strong>
|
|
10
|
-
<span>This is a semantic alert component</span>
|
|
11
|
-
</aside>`,
|
|
12
|
-
avatar: `<span data-size="md">JD</span>`,
|
|
13
|
-
badge: `<mark data-intent="success">Saved</mark>`,
|
|
14
|
-
breadcrumb: `<nav aria-label="Breadcrumb">
|
|
15
|
-
<ol>
|
|
16
|
-
<li><a href="/">Home</a></li>
|
|
17
|
-
<li><a href="/docs" aria-current="page">Docs</a></li>
|
|
18
|
-
</ol>
|
|
19
|
-
</nav>`,
|
|
20
|
-
button: `<button data-intent="primary">Save</button>`,
|
|
21
|
-
card: `<article>
|
|
22
|
-
<h2 slot="title">Card Title</h2>
|
|
23
|
-
<p slot="body">
|
|
24
|
-
This is the main card body content.
|
|
25
|
-
</p>
|
|
26
|
-
</article>`,
|
|
27
|
-
checkbox: `<label>
|
|
28
|
-
<input type="checkbox" />
|
|
29
|
-
Remember me
|
|
30
|
-
</label>`,
|
|
31
|
-
codeblock: `<pre><code data-lang="typescript">const greet = () => "Hello World";</code></pre>`,
|
|
32
|
-
combobox: `<ix-combobox>
|
|
33
|
-
<label slot="control">
|
|
34
|
-
Search
|
|
35
|
-
<input type="text" placeholder="Search options..." />
|
|
36
|
-
</label>
|
|
37
|
-
<ul hidden>
|
|
38
|
-
<li data-value="1">Option A</li>
|
|
39
|
-
<li data-value="2">Option B</li>
|
|
40
|
-
</ul>
|
|
41
|
-
</ix-combobox>`,
|
|
42
|
-
dialog: `<dialog id="confirm-modal" data-intent="danger">
|
|
43
|
-
<h2>Confirm Action</h2>
|
|
44
|
-
<p>Are you sure you want to proceed?</p>
|
|
45
|
-
<button>Cancel</button>
|
|
46
|
-
<button>Delete</button>
|
|
47
|
-
</dialog>`,
|
|
48
|
-
divider: `<hr />`,
|
|
49
|
-
dropdown: `<ix-dropdown>
|
|
50
|
-
<button slot="trigger">Options ▾</button>
|
|
51
|
-
<ul slot="menu" hidden>
|
|
52
|
-
<li><button>Profile</button></li>
|
|
53
|
-
<li><button>Settings</button></li>
|
|
54
|
-
</ul>
|
|
55
|
-
</ix-dropdown>`,
|
|
56
|
-
form: `<form>
|
|
57
|
-
<label>
|
|
58
|
-
Name
|
|
59
|
-
<input type="text" required />
|
|
60
|
-
</label>
|
|
61
|
-
<button type="submit" data-intent="primary">Submit</button>
|
|
62
|
-
</form>`,
|
|
63
|
-
grid: `<section data-grid="3">
|
|
64
|
-
<section>Column 1</section>
|
|
65
|
-
<section>Column 2</section>
|
|
66
|
-
<section>Column 3</section>
|
|
67
|
-
</section>`,
|
|
68
|
-
|
|
69
|
-
input: `<label>
|
|
70
|
-
Username
|
|
71
|
-
<input type="text" required placeholder="Enter Username..." />
|
|
72
|
-
</label>`,
|
|
73
|
-
meter: `<meter value="70" min="0" max="100" low="30" high="70" optimum="100"></meter>`,
|
|
74
|
-
navigation: `<nav aria-label="Main Navigation">
|
|
75
|
-
<ul>
|
|
76
|
-
<li><a href="/" aria-current="page">Home</a></li>
|
|
77
|
-
<li><a href="/docs">Docs</a></li>
|
|
78
|
-
<li><a href="/blog">Blog</a></li>
|
|
79
|
-
</ul>
|
|
80
|
-
</nav>`,
|
|
81
|
-
progress: `<progress value="50" max="100"></progress>`,
|
|
82
|
-
radio: `<label>
|
|
83
|
-
<input type="radio" name="options" value="a" />
|
|
84
|
-
Option A
|
|
85
|
-
</label>`,
|
|
86
|
-
select: `<label>
|
|
87
|
-
Options
|
|
88
|
-
<select data-intent="primary">
|
|
89
|
-
<option value="1">Option 1</option>
|
|
90
|
-
<option value="2">Option 2</option>
|
|
91
|
-
</select>
|
|
92
|
-
</label>`,
|
|
93
|
-
skeleton: `<span aria-busy="true" data-shape="text"></span>`,
|
|
94
|
-
tabs: `<ix-tabs>
|
|
95
|
-
<button slot="tab" aria-selected="true">Tab 1</button>
|
|
96
|
-
<button slot="tab">Tab 2</button>
|
|
97
|
-
<section slot="panel">Content for Tab 1</section>
|
|
98
|
-
<section slot="panel" hidden>Content for Tab 2</section>
|
|
99
|
-
</ix-tabs>`,
|
|
100
|
-
table: `<table>
|
|
101
|
-
<thead>
|
|
102
|
-
<tr>
|
|
103
|
-
<th>Name</th>
|
|
104
|
-
<th>Role</th>
|
|
105
|
-
</tr>
|
|
106
|
-
</thead>
|
|
107
|
-
<tbody>
|
|
108
|
-
<tr>
|
|
109
|
-
<td>Alice</td>
|
|
110
|
-
<td>Developer</td>
|
|
111
|
-
</tr>
|
|
112
|
-
</tbody>
|
|
113
|
-
</table>`,
|
|
114
|
-
textarea: `<label>
|
|
115
|
-
Message
|
|
116
|
-
<textarea data-intent="primary" placeholder="Enter your message..."></textarea>
|
|
117
|
-
</label>`,
|
|
118
|
-
toast: `<ix-toast>
|
|
119
|
-
<aside data-intent="success" data-open="true">
|
|
120
|
-
<strong>Success!</strong>
|
|
121
|
-
<span>Action completed.</span>
|
|
122
|
-
</aside>
|
|
123
|
-
</ix-toast>`,
|
|
124
|
-
tooltip: `<ix-tooltip content="Helpful information">
|
|
125
|
-
<span>Hover me</span>
|
|
126
|
-
</ix-tooltip>`
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export async function addCommand(component: string) {
|
|
130
|
-
const normalized = component.toLowerCase().trim()
|
|
131
|
-
const template = COMPONENT_TEMPLATES[normalized]
|
|
132
|
-
|
|
133
|
-
if (!template) {
|
|
134
|
-
console.log(pc.red(`Component "${component}" not found.`))
|
|
135
|
-
|
|
136
|
-
console.log(
|
|
137
|
-
pc.yellow(
|
|
138
|
-
`Available components : ${Object.keys(COMPONENT_TEMPLATES).join(', ')}`
|
|
139
|
-
)
|
|
140
|
-
)
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
console.log(pc.cyan(`\nTemplate for <${component}>:\n`))
|
|
144
|
-
console.log(template)
|
|
145
|
-
console.log('\n')
|
|
146
|
-
}
|
package/src/commands/build.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import pc from 'picocolors'
|
|
4
|
-
import { howToBuild } from '@mindfiredigital/ignix-lite-engine'
|
|
5
|
-
|
|
6
|
-
export async function buildCommand(
|
|
7
|
-
prompt: string,
|
|
8
|
-
options: {
|
|
9
|
-
output?: string
|
|
10
|
-
emmetOnly?: boolean
|
|
11
|
-
}
|
|
12
|
-
) {
|
|
13
|
-
const response = await howToBuild(prompt)
|
|
14
|
-
if (!response.content || response.content.length === 0) {
|
|
15
|
-
console.log(
|
|
16
|
-
pc.red('Error: Intent synthesis engine returned an empty response.')
|
|
17
|
-
)
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
let data: {
|
|
22
|
-
source: string
|
|
23
|
-
suggestion?: string
|
|
24
|
-
emmet?: string
|
|
25
|
-
html?: string
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
data = JSON.parse(response.content[0].text)
|
|
29
|
-
} catch {
|
|
30
|
-
console.log(
|
|
31
|
-
pc.red('Error: Failed to parse response from intent synthesis engine.')
|
|
32
|
-
)
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!data || data.source === 'no-match') {
|
|
37
|
-
console.log(pc.red(`\nCould not synthesize UI for: "${prompt}"`))
|
|
38
|
-
console.log(
|
|
39
|
-
pc.yellow(
|
|
40
|
-
`Suggestion: ${data?.suggestion || 'Try clarifying your request.'}\n`
|
|
41
|
-
)
|
|
42
|
-
)
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const outputContent = options.emmetOnly ? data.emmet : data.html
|
|
47
|
-
if (!outputContent) {
|
|
48
|
-
console.log(
|
|
49
|
-
pc.red('Error: Response does not contain any synthesized code.')
|
|
50
|
-
)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (options.output) {
|
|
55
|
-
try {
|
|
56
|
-
const absolutePath = path.resolve(process.cwd(), options.output)
|
|
57
|
-
writeFileSync(absolutePath, outputContent, 'utf8')
|
|
58
|
-
console.log(
|
|
59
|
-
pc.green(`\nSuccessfully wrote output to ${pc.blue(options.output)}\n`)
|
|
60
|
-
)
|
|
61
|
-
} catch (err: unknown) {
|
|
62
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
63
|
-
console.log(pc.red(`Error: Failed to write output to file. ${msg}`))
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
console.log(pc.cyan('\nSynthesized Output:'))
|
|
67
|
-
console.log(outputContent)
|
|
68
|
-
console.log()
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import pc from 'picocolors'
|
|
4
|
-
import { auditA11y } from '@mindfiredigital/ignix-lite-engine'
|
|
5
|
-
|
|
6
|
-
export async function checkA11yCommand(filePath: string) {
|
|
7
|
-
const absolutePath = path.resolve(process.cwd(), filePath)
|
|
8
|
-
|
|
9
|
-
if (!existsSync(absolutePath)) {
|
|
10
|
-
console.log(pc.red(`Error: File not found at ${filePath}`))
|
|
11
|
-
process.exit(1)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const html = readFileSync(absolutePath, 'utf8')
|
|
15
|
-
const result = auditA11y(html)
|
|
16
|
-
|
|
17
|
-
console.log(pc.bold(pc.cyan(`\n♿ Accessibility Audit Report`)))
|
|
18
|
-
console.log(pc.gray('═'.repeat(60)))
|
|
19
|
-
console.log(`${pc.bold('File:')} ${pc.blue(filePath)}`)
|
|
20
|
-
console.log(`${pc.bold('Standards:')} WCAG 2.2 ${pc.bold(result.wcag)}`)
|
|
21
|
-
console.log(
|
|
22
|
-
`${pc.bold('Summary:')} Passed ${result.passes.length} rules, Found ${result.issues.length} issue(s)`
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
if (result.issues.length === 0) {
|
|
26
|
-
console.log(
|
|
27
|
-
pc.bold(
|
|
28
|
-
pc.green(`\n✔ PASS: No accessibility issues found! Score: 100/100`)
|
|
29
|
-
)
|
|
30
|
-
)
|
|
31
|
-
} else {
|
|
32
|
-
console.log(
|
|
33
|
-
pc.bold(
|
|
34
|
-
pc.red(
|
|
35
|
-
`\n✘ FAIL: Accessibility check failed. Score: ${result.score}/100\n`
|
|
36
|
-
)
|
|
37
|
-
)
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
result.issues.forEach((issue, idx) => {
|
|
41
|
-
const isError = issue.type === 'error'
|
|
42
|
-
const labelColor = isError ? pc.red : pc.yellow
|
|
43
|
-
const borderChar = isError ? '✘' : '⚠'
|
|
44
|
-
|
|
45
|
-
console.log(
|
|
46
|
-
pc.bold(
|
|
47
|
-
labelColor(
|
|
48
|
-
`[Issue ${idx + 1}] ${borderChar} ${issue.rule} (${issue.type.toUpperCase()})`
|
|
49
|
-
)
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
console.log(` ${pc.bold('Element:')} ${issue.element}`)
|
|
53
|
-
console.log(` ${pc.bold('Message:')} ${issue.message}`)
|
|
54
|
-
if (issue.fix) {
|
|
55
|
-
console.log(` ${pc.bold('Fix:')} ${pc.green(issue.fix)}`)
|
|
56
|
-
}
|
|
57
|
-
console.log()
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
console.log()
|
|
61
|
-
}
|
package/src/commands/info.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import pc from 'picocolors'
|
|
2
|
-
import { manifests } from '@mindfiredigital/ignix-lite-engine'
|
|
3
|
-
|
|
4
|
-
export function infoCommand(component: string) {
|
|
5
|
-
const name = component.toLowerCase().trim()
|
|
6
|
-
const manifest = manifests[name]
|
|
7
|
-
|
|
8
|
-
if (!manifest) {
|
|
9
|
-
console.log(pc.red(`\nError: Component "${component}" does not exist.`))
|
|
10
|
-
console.log(
|
|
11
|
-
`Run ${pc.yellow('ignix-lite list')} to see all available components.\n`
|
|
12
|
-
)
|
|
13
|
-
process.exit(1)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
console.log(pc.bold(pc.cyan(`\n📦 Component: <${name.toUpperCase()}>`)))
|
|
17
|
-
console.log(pc.gray('═'.repeat(60)))
|
|
18
|
-
console.log(`${pc.bold('Description:')} ${manifest.description}`)
|
|
19
|
-
console.log(
|
|
20
|
-
`${pc.bold('HTML Wrapper:')} ${pc.yellow(`<${manifest.element}>`)}`
|
|
21
|
-
)
|
|
22
|
-
console.log(`${pc.bold('Default Emmet:')} ${pc.green(manifest.emmet)}`)
|
|
23
|
-
|
|
24
|
-
if (manifest.props && Object.keys(manifest.props).length > 0) {
|
|
25
|
-
console.log(pc.bold(pc.blue('\n⚙ Attributes & Options:')))
|
|
26
|
-
console.log(pc.gray(' ' + '─'.repeat(56)))
|
|
27
|
-
Object.entries(manifest.props).forEach(([propName, propDef]) => {
|
|
28
|
-
const typeStr = pc.magenta(propDef.type)
|
|
29
|
-
const valuesStr = propDef.values
|
|
30
|
-
? pc.dim(` [${propDef.values.join(', ')}]`)
|
|
31
|
-
: ''
|
|
32
|
-
const defaultStr =
|
|
33
|
-
propDef.default !== undefined
|
|
34
|
-
? ` (default: ${pc.bold(String(propDef.default))})`
|
|
35
|
-
: ''
|
|
36
|
-
console.log(
|
|
37
|
-
` ${pc.cyan('•')} ${pc.bold(propName.padEnd(15))} ${typeStr}${valuesStr}${defaultStr}`
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (manifest.slots && Object.keys(manifest.slots).length > 0) {
|
|
43
|
-
console.log(pc.bold(pc.blue('\n📥 Slots:')))
|
|
44
|
-
console.log(pc.gray(' ' + '─'.repeat(56)))
|
|
45
|
-
Object.entries(manifest.slots).forEach(([slotName, slotDef]) => {
|
|
46
|
-
const elementsStr = slotDef.element
|
|
47
|
-
? pc.dim(` (tags: ${slotDef.element.join(', ')})`)
|
|
48
|
-
: ''
|
|
49
|
-
const requiredStr = slotDef.required ? pc.bold(pc.red(' (required)')) : ''
|
|
50
|
-
console.log(
|
|
51
|
-
` ${pc.cyan('•')} ${pc.bold(slotName.padEnd(15))} ${requiredStr}${elementsStr}`
|
|
52
|
-
)
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (manifest.do && manifest.do.length > 0) {
|
|
57
|
-
console.log(pc.bold(pc.green('\n✔ Best Practices (Do):')))
|
|
58
|
-
manifest.do.forEach((rule) => console.log(` ${pc.green('+')} ${rule}`))
|
|
59
|
-
}
|
|
60
|
-
if (manifest.dont && manifest.dont.length > 0) {
|
|
61
|
-
console.log(pc.bold(pc.red("\n✘ Avoid (Don't):")))
|
|
62
|
-
manifest.dont.forEach((rule) => console.log(` ${pc.red('-')} ${rule}`))
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
console.log()
|
|
66
|
-
}
|
package/src/commands/init.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import prompts from 'prompts'
|
|
4
|
-
import pc from 'picocolors'
|
|
5
|
-
import ora from 'ora'
|
|
6
|
-
|
|
7
|
-
export async function initCommand() {
|
|
8
|
-
console.log(
|
|
9
|
-
pc.cyan("Welcome to Ignix-Lite! Let's get your project set up.\n")
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
const response = await prompts([
|
|
13
|
-
{
|
|
14
|
-
type: 'select',
|
|
15
|
-
name: 'framework',
|
|
16
|
-
message: 'Which framework are you using?',
|
|
17
|
-
choices: [
|
|
18
|
-
{ title: 'React', value: 'react' },
|
|
19
|
-
{ title: 'Vue', value: 'vue' },
|
|
20
|
-
{ title: 'Svelte', value: 'svelte' },
|
|
21
|
-
{ title: 'Vanilla HTML', value: 'vanilla' }
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
type: 'text',
|
|
26
|
-
name: 'stylePath',
|
|
27
|
-
message:
|
|
28
|
-
'Path to your main CSS file (where Ignix-Lite variables will be added):',
|
|
29
|
-
initial: 'src/index.css'
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
type: 'text',
|
|
33
|
-
name: 'primaryColor',
|
|
34
|
-
message: 'Default primary theme color (hex):',
|
|
35
|
-
initial: '#6366f1',
|
|
36
|
-
validate: (value: string) => {
|
|
37
|
-
const hexRegex = /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/
|
|
38
|
-
return hexRegex.test(value)
|
|
39
|
-
? true
|
|
40
|
-
: 'Please enter a valid hex color code (e.g. #6366f1 or #fff)'
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
])
|
|
44
|
-
|
|
45
|
-
if (!response.framework || !response.stylePath) {
|
|
46
|
-
console.log(pc.red('\nSetup cancelled.'))
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const spinner = ora('Initializing project...').start()
|
|
51
|
-
|
|
52
|
-
// 1. Create ignix.config.json
|
|
53
|
-
const config = {
|
|
54
|
-
framework: response.framework,
|
|
55
|
-
style: response.stylePath,
|
|
56
|
-
theme: {
|
|
57
|
-
primary: response.primaryColor
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
fs.writeFileSync('ignix.config.json', JSON.stringify(config, null, 2))
|
|
62
|
-
|
|
63
|
-
// 2. Ensure CSS file exists and add initial theme block
|
|
64
|
-
const cssDir = path.dirname(response.stylePath)
|
|
65
|
-
if (!fs.existsSync(cssDir)) {
|
|
66
|
-
fs.mkdirSync(cssDir, { recursive: true })
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const defaultThemeVars = `/* Ignix-Lite Custom Theme Variables */
|
|
70
|
-
:root {
|
|
71
|
-
--ix-primary: ${response.primaryColor};
|
|
72
|
-
--ix-primary-hover: ${response.primaryColor}d0;
|
|
73
|
-
--ix-primary-contrast: #ffffff;
|
|
74
|
-
--ix-primary-bg: ${response.primaryColor}1a;
|
|
75
|
-
}
|
|
76
|
-
`
|
|
77
|
-
|
|
78
|
-
if (fs.existsSync(response.stylePath)) {
|
|
79
|
-
let content = fs.readFileSync(response.stylePath, 'utf-8')
|
|
80
|
-
if (!content.includes('--ix-primary')) {
|
|
81
|
-
content = defaultThemeVars + '\n' + content
|
|
82
|
-
fs.writeFileSync(response.stylePath, content)
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
fs.writeFileSync(response.stylePath, defaultThemeVars)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
spinner.succeed(pc.green('Ignix-Lite initialized successfully!'))
|
|
89
|
-
console.log(`\nCreated ${pc.blue('ignix.config.json')}`)
|
|
90
|
-
console.log(`Updated theme variables in ${pc.blue(response.stylePath)}`)
|
|
91
|
-
}
|
package/src/commands/list.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import pc from 'picocolors'
|
|
2
|
-
import { manifests } from '@mindfiredigital/ignix-lite-engine'
|
|
3
|
-
|
|
4
|
-
export function listCommand() {
|
|
5
|
-
const components = Object.keys(manifests).sort()
|
|
6
|
-
|
|
7
|
-
console.log(pc.bold(pc.cyan('\n🔥 Ignix-Lite Components Catalog')))
|
|
8
|
-
console.log(pc.gray('═'.repeat(70)))
|
|
9
|
-
|
|
10
|
-
components.forEach((name) => {
|
|
11
|
-
const desc =
|
|
12
|
-
manifests[name].description || pc.gray('No description available')
|
|
13
|
-
console.log(
|
|
14
|
-
` ${pc.bold(pc.green('●'))} ${pc.bold(name.padEnd(15))} ${pc.dim('→')} ${desc}`
|
|
15
|
-
)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
console.log(pc.gray('═'.repeat(70)))
|
|
19
|
-
console.log(
|
|
20
|
-
pc.cyan(`Total: ${pc.bold(components.length)} components ready to use!\n`)
|
|
21
|
-
)
|
|
22
|
-
}
|
package/src/commands/mcp.ts
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { fileURLToPath } from 'url'
|
|
4
|
-
import { spawn } from 'child_process'
|
|
5
|
-
import pc from 'picocolors'
|
|
6
|
-
import ora from 'ora'
|
|
7
|
-
|
|
8
|
-
function resolveMcpServerPath(): string {
|
|
9
|
-
try {
|
|
10
|
-
const resolvedUrl = import.meta.resolve('@mindfiredigital/ignix-lite-mcp')
|
|
11
|
-
return fileURLToPath(resolvedUrl)
|
|
12
|
-
} catch {
|
|
13
|
-
const thisDir = path.dirname(fileURLToPath(import.meta.url))
|
|
14
|
-
return path.resolve(thisDir, '../../mcp/dist/server.js')
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** Read a JSON file safely; returns {} if not found or invalid */
|
|
19
|
-
function readJson(filePath: string): Record<string, unknown> {
|
|
20
|
-
try {
|
|
21
|
-
return JSON.parse(readFileSync(filePath, 'utf-8'))
|
|
22
|
-
} catch {
|
|
23
|
-
return {}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Write a JSON file, creating parent directories as needed */
|
|
28
|
-
function writeJson(filePath: string, data: unknown): void {
|
|
29
|
-
mkdirSync(path.dirname(filePath), { recursive: true })
|
|
30
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8')
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** The shared MCP server entry */
|
|
34
|
-
function mcpEntry(serverPath: string) {
|
|
35
|
-
return {
|
|
36
|
-
command: 'node',
|
|
37
|
-
args: [serverPath]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function setupClaudeDesktop(serverPath: string): void {
|
|
42
|
-
const spinner = ora('Configuring Claude Desktop...').start()
|
|
43
|
-
try {
|
|
44
|
-
const configDir =
|
|
45
|
-
process.platform === 'win32'
|
|
46
|
-
? path.join(process.env.APPDATA || '', 'Claude')
|
|
47
|
-
: path.join(
|
|
48
|
-
process.env.HOME || '',
|
|
49
|
-
'Library',
|
|
50
|
-
'Application Support',
|
|
51
|
-
'Claude'
|
|
52
|
-
)
|
|
53
|
-
const configPath = path.join(configDir, 'claude_desktop_config.json')
|
|
54
|
-
const config = readJson(configPath) as {
|
|
55
|
-
mcpServers?: Record<string, unknown>
|
|
56
|
-
}
|
|
57
|
-
config.mcpServers = config.mcpServers || {}
|
|
58
|
-
config.mcpServers['ignix-lite'] = mcpEntry(serverPath)
|
|
59
|
-
writeJson(configPath, config)
|
|
60
|
-
spinner.succeed(pc.green('Claude Desktop configured successfully!'))
|
|
61
|
-
console.log(pc.gray(` Config: ${configPath}`))
|
|
62
|
-
console.log(pc.yellow('\n ⚡ Restart Claude Desktop to apply changes.\n'))
|
|
63
|
-
} catch (err) {
|
|
64
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
65
|
-
spinner.fail(pc.red(`Failed to configure Claude Desktop: ${msg}`))
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function setupClaudeCode(serverPath: string): void {
|
|
70
|
-
const spinner = ora('Configuring Claude Code (claude CLI)...').start()
|
|
71
|
-
try {
|
|
72
|
-
// User-level config: ~/.claude.json
|
|
73
|
-
const configPath =
|
|
74
|
-
process.platform === 'win32'
|
|
75
|
-
? path.join(process.env.USERPROFILE || '', '.claude.json')
|
|
76
|
-
: path.join(process.env.HOME || '', '.claude.json')
|
|
77
|
-
|
|
78
|
-
const config = readJson(configPath) as {
|
|
79
|
-
mcpServers?: Record<string, unknown>
|
|
80
|
-
}
|
|
81
|
-
config.mcpServers = config.mcpServers || {}
|
|
82
|
-
config.mcpServers['ignix-lite'] = mcpEntry(serverPath)
|
|
83
|
-
writeJson(configPath, config)
|
|
84
|
-
spinner.succeed(pc.green('Claude Code configured successfully!'))
|
|
85
|
-
console.log(pc.gray(` Config: ${configPath}`))
|
|
86
|
-
console.log(
|
|
87
|
-
pc.yellow(
|
|
88
|
-
'\n ⚡ Run "claude" in any project to start using Ignix-Lite tools.\n'
|
|
89
|
-
)
|
|
90
|
-
)
|
|
91
|
-
} catch (err) {
|
|
92
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
93
|
-
spinner.fail(pc.red(`Failed to configure Claude Code: ${msg}`))
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function setupGemini(serverPath: string): void {
|
|
98
|
-
const spinner = ora('Configuring Gemini CLI...').start()
|
|
99
|
-
try {
|
|
100
|
-
// Gemini CLI reads ~/.gemini/settings.json
|
|
101
|
-
const configDir =
|
|
102
|
-
process.platform === 'win32'
|
|
103
|
-
? path.join(process.env.USERPROFILE || '', '.gemini')
|
|
104
|
-
: path.join(process.env.HOME || '', '.gemini')
|
|
105
|
-
const configPath = path.join(configDir, 'settings.json')
|
|
106
|
-
|
|
107
|
-
const config = readJson(configPath) as {
|
|
108
|
-
mcpServers?: Record<string, unknown>
|
|
109
|
-
}
|
|
110
|
-
config.mcpServers = config.mcpServers || {}
|
|
111
|
-
config.mcpServers['ignix-lite'] = mcpEntry(serverPath)
|
|
112
|
-
writeJson(configPath, config)
|
|
113
|
-
spinner.succeed(pc.green('Gemini CLI configured successfully!'))
|
|
114
|
-
console.log(pc.gray(` Config: ${configPath}`))
|
|
115
|
-
console.log(
|
|
116
|
-
pc.yellow(
|
|
117
|
-
'\n ⚡ Start a new Gemini CLI session to activate Ignix-Lite tools.\n'
|
|
118
|
-
)
|
|
119
|
-
)
|
|
120
|
-
} catch (err) {
|
|
121
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
122
|
-
spinner.fail(pc.red(`Failed to configure Gemini CLI: ${msg}`))
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function setupCursor(serverPath: string): void {
|
|
127
|
-
const spinner = ora('Configuring Cursor...').start()
|
|
128
|
-
try {
|
|
129
|
-
// Cursor reads ~/.cursor/mcp.json (global scope)
|
|
130
|
-
const configDir =
|
|
131
|
-
process.platform === 'win32'
|
|
132
|
-
? path.join(process.env.USERPROFILE || '', '.cursor')
|
|
133
|
-
: path.join(process.env.HOME || '', '.cursor')
|
|
134
|
-
const configPath = path.join(configDir, 'mcp.json')
|
|
135
|
-
|
|
136
|
-
const config = readJson(configPath) as {
|
|
137
|
-
mcpServers?: Record<string, unknown>
|
|
138
|
-
}
|
|
139
|
-
config.mcpServers = config.mcpServers || {}
|
|
140
|
-
config.mcpServers['ignix-lite'] = mcpEntry(serverPath)
|
|
141
|
-
writeJson(configPath, config)
|
|
142
|
-
spinner.succeed(pc.green('Cursor configured successfully!'))
|
|
143
|
-
console.log(pc.gray(` Config: ${configPath}`))
|
|
144
|
-
console.log(
|
|
145
|
-
pc.yellow(
|
|
146
|
-
'\n ⚡ Reload Cursor (Ctrl+Shift+P → "Reload Window") to activate Ignix-Lite tools.\n'
|
|
147
|
-
)
|
|
148
|
-
)
|
|
149
|
-
} catch (err) {
|
|
150
|
-
const msg = err instanceof Error ? err.message : String(err)
|
|
151
|
-
spinner.fail(pc.red(`Failed to configure Cursor: ${msg}`))
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const SUPPORTED_CLIENTS = [
|
|
156
|
-
'claude',
|
|
157
|
-
'claude-desktop',
|
|
158
|
-
'claude-code',
|
|
159
|
-
'gemini',
|
|
160
|
-
'cursor'
|
|
161
|
-
]
|
|
162
|
-
|
|
163
|
-
export async function mcpSetupCommand(client?: string): Promise<void> {
|
|
164
|
-
const serverPath = resolveMcpServerPath()
|
|
165
|
-
const target = (client || '').toLowerCase().trim()
|
|
166
|
-
|
|
167
|
-
if (!target) {
|
|
168
|
-
console.log(pc.cyan('\nWhich client do you want to configure?\n'))
|
|
169
|
-
console.log(
|
|
170
|
-
` ${pc.bold('claude')} Claude Desktop (auto-configure)`
|
|
171
|
-
)
|
|
172
|
-
console.log(
|
|
173
|
-
` ${pc.bold('claude-code')} Claude Code CLI (auto-configure)`
|
|
174
|
-
)
|
|
175
|
-
console.log(
|
|
176
|
-
` ${pc.bold('gemini')} Gemini CLI (auto-configure)`
|
|
177
|
-
)
|
|
178
|
-
console.log(
|
|
179
|
-
` ${pc.bold('cursor')} Cursor editor (auto-configure)`
|
|
180
|
-
)
|
|
181
|
-
console.log()
|
|
182
|
-
console.log(
|
|
183
|
-
pc.gray(
|
|
184
|
-
'Usage: ignix-lite mcp setup <client> (e.g. ignix-lite mcp setup cursor)'
|
|
185
|
-
)
|
|
186
|
-
)
|
|
187
|
-
console.log()
|
|
188
|
-
return
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
switch (target) {
|
|
192
|
-
case 'claude':
|
|
193
|
-
case 'claude-desktop':
|
|
194
|
-
setupClaudeDesktop(serverPath)
|
|
195
|
-
break
|
|
196
|
-
|
|
197
|
-
case 'claude-code':
|
|
198
|
-
setupClaudeCode(serverPath)
|
|
199
|
-
break
|
|
200
|
-
|
|
201
|
-
case 'gemini':
|
|
202
|
-
setupGemini(serverPath)
|
|
203
|
-
break
|
|
204
|
-
|
|
205
|
-
case 'cursor':
|
|
206
|
-
setupCursor(serverPath)
|
|
207
|
-
break
|
|
208
|
-
|
|
209
|
-
default:
|
|
210
|
-
console.log(pc.red(`\nUnknown client: "${client}"\n`))
|
|
211
|
-
console.log(`Supported clients: ${pc.bold(SUPPORTED_CLIENTS.join(', '))}`)
|
|
212
|
-
console.log()
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export function mcpStartCommand(): void {
|
|
217
|
-
const serverPath = resolveMcpServerPath()
|
|
218
|
-
|
|
219
|
-
console.log(pc.cyan(`\nStarting Ignix-Lite MCP Server...`))
|
|
220
|
-
console.log(`Running: ${pc.green('node ' + serverPath)}\n`)
|
|
221
|
-
|
|
222
|
-
const child = spawn('node', [serverPath], { stdio: 'inherit' })
|
|
223
|
-
|
|
224
|
-
child.on('error', (err) => {
|
|
225
|
-
console.log(pc.red(`\nFailed to start MCP Server: ${err.message}`))
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
child.on('close', (code) => {
|
|
229
|
-
if (code !== 0) {
|
|
230
|
-
console.log(pc.red(`\nMCP Server exited with code ${code}`))
|
|
231
|
-
}
|
|
232
|
-
})
|
|
233
|
-
}
|
package/src/commands/preview.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync, writeFileSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import pc from 'picocolors'
|
|
4
|
-
import ora from 'ora'
|
|
5
|
-
import { preview } from '@mindfiredigital/ignix-lite-engine'
|
|
6
|
-
|
|
7
|
-
export async function previewCommand(
|
|
8
|
-
filePath: string,
|
|
9
|
-
options: { output: string; width: string; theme?: string }
|
|
10
|
-
) {
|
|
11
|
-
const absolutePath = path.resolve(process.cwd(), filePath)
|
|
12
|
-
|
|
13
|
-
if (!existsSync(absolutePath)) {
|
|
14
|
-
console.log(pc.red(`Error: File not found at ${filePath}`))
|
|
15
|
-
process.exit(1)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const spinner = ora(
|
|
19
|
-
'Launching headless browser and rendering preview...'
|
|
20
|
-
).start()
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const inputContent = readFileSync(absolutePath, 'utf8')
|
|
24
|
-
const widthNum = parseInt(options.width, 10) || 400
|
|
25
|
-
|
|
26
|
-
const response = await preview({
|
|
27
|
-
input: inputContent,
|
|
28
|
-
options: {
|
|
29
|
-
width: widthNum,
|
|
30
|
-
theme: options.theme
|
|
31
|
-
}
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
if (!response.content || response.content.length === 0) {
|
|
35
|
-
spinner.fail(
|
|
36
|
-
pc.red('Render failed: Received empty response from preview engine.')
|
|
37
|
-
)
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let result: {
|
|
42
|
-
error?: string
|
|
43
|
-
png?: string
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
result = JSON.parse(response.content[0].text)
|
|
47
|
-
} catch {
|
|
48
|
-
spinner.fail(
|
|
49
|
-
pc.red('Render failed: Invalid JSON response from preview engine.')
|
|
50
|
-
)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (result.error) {
|
|
55
|
-
spinner.fail(pc.red(`Render failed: ${result.error}`))
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!result.png || typeof result.png !== 'string') {
|
|
60
|
-
spinner.fail(
|
|
61
|
-
pc.red('Render failed: Preview engine did not return base64 PNG data.')
|
|
62
|
-
)
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const base64Data = result.png.replace(/^data:image\/png;base64,/, '')
|
|
67
|
-
const buffer = Buffer.from(base64Data, 'base64')
|
|
68
|
-
|
|
69
|
-
const outputPath = path.resolve(process.cwd(), options.output)
|
|
70
|
-
writeFileSync(outputPath, buffer)
|
|
71
|
-
|
|
72
|
-
spinner.succeed(
|
|
73
|
-
pc.green(
|
|
74
|
-
`Visual preview generated successfully! Saved to ${pc.blue(options.output)}`
|
|
75
|
-
)
|
|
76
|
-
)
|
|
77
|
-
} catch (error) {
|
|
78
|
-
const msg = error instanceof Error ? error.message : String(error)
|
|
79
|
-
spinner.fail(pc.red(`Preview failed: ${msg}`))
|
|
80
|
-
}
|
|
81
|
-
}
|
package/src/commands/theme.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import pc from 'picocolors'
|
|
4
|
-
import ora from 'ora'
|
|
5
|
-
import { resolveTokens, buildCss } from '@mindfiredigital/ignix-lite-engine'
|
|
6
|
-
|
|
7
|
-
export async function themeCommand(
|
|
8
|
-
prompt?: string,
|
|
9
|
-
options: { primary?: string; styleFile?: string } = {}
|
|
10
|
-
) {
|
|
11
|
-
const spinner = ora('Generating theme tokens...').start()
|
|
12
|
-
|
|
13
|
-
let stylePath = options.styleFile
|
|
14
|
-
|
|
15
|
-
if (!stylePath) {
|
|
16
|
-
const configPath = 'ignix.config.json'
|
|
17
|
-
if (!fs.existsSync(configPath)) {
|
|
18
|
-
spinner.fail(
|
|
19
|
-
pc.red(
|
|
20
|
-
'ignix.config.json not found. Run "ignix-lite init" first or specify --style-file.'
|
|
21
|
-
)
|
|
22
|
-
)
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
|
28
|
-
stylePath = config.style
|
|
29
|
-
} catch {
|
|
30
|
-
spinner.fail(pc.red('Failed to read ignix.config.json.'))
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!stylePath) {
|
|
36
|
-
spinner.fail(
|
|
37
|
-
pc.red('Style path not configured. Specify -s or --style-file option.')
|
|
38
|
-
)
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const queryParts = [prompt || '', options.primary || ''].filter(Boolean)
|
|
43
|
-
const query = queryParts.join(' ').trim()
|
|
44
|
-
|
|
45
|
-
if (!query) {
|
|
46
|
-
spinner.fail(
|
|
47
|
-
pc.yellow(
|
|
48
|
-
'Please provide a prompt or primary color, e.g.: ignix-lite theme "dark round blue"'
|
|
49
|
-
)
|
|
50
|
-
)
|
|
51
|
-
return
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const tokens = resolveTokens(query)
|
|
56
|
-
const cssBlock = buildCss(tokens)
|
|
57
|
-
|
|
58
|
-
const absoluteStylePath = path.resolve(process.cwd(), stylePath)
|
|
59
|
-
if (!absoluteStylePath.startsWith(process.cwd())) {
|
|
60
|
-
spinner.fail(
|
|
61
|
-
pc.red('Error: Style file path must be within the project workspace.')
|
|
62
|
-
)
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const cssDir = path.dirname(absoluteStylePath)
|
|
67
|
-
|
|
68
|
-
if (!fs.existsSync(cssDir)) {
|
|
69
|
-
fs.mkdirSync(cssDir, { recursive: true })
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const themeRegex =
|
|
73
|
-
/\/\* Ignix-Lite Custom Theme Variables \*\/[\s\S]*?\}\n?/g
|
|
74
|
-
|
|
75
|
-
if (fs.existsSync(absoluteStylePath)) {
|
|
76
|
-
let content = fs.readFileSync(absoluteStylePath, 'utf-8')
|
|
77
|
-
if (themeRegex.test(content)) {
|
|
78
|
-
content = content.replace(themeRegex, cssBlock + '\n')
|
|
79
|
-
} else {
|
|
80
|
-
content = cssBlock + '\n\n' + content
|
|
81
|
-
}
|
|
82
|
-
fs.writeFileSync(absoluteStylePath, content)
|
|
83
|
-
} else {
|
|
84
|
-
fs.writeFileSync(absoluteStylePath, cssBlock)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
spinner.succeed(
|
|
88
|
-
pc.green(`Theme successfully updated in ${pc.blue(stylePath)}`)
|
|
89
|
-
)
|
|
90
|
-
console.log(pc.gray(`Resolved primary color: ${tokens.resolvedPrimary}`))
|
|
91
|
-
console.log(pc.gray(`Mode: ${tokens.isDark ? 'Dark' : 'Light'}\n`))
|
|
92
|
-
} catch (error) {
|
|
93
|
-
const msg = error instanceof Error ? error.message : String(error)
|
|
94
|
-
spinner.fail(pc.red(`Failed to generate theme: ${msg}`))
|
|
95
|
-
}
|
|
96
|
-
}
|
package/src/commands/validate.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import pc from 'picocolors'
|
|
4
|
-
import { validateHtml } from '@mindfiredigital/ignix-lite-engine'
|
|
5
|
-
|
|
6
|
-
export async function validateCommand(filePath: string) {
|
|
7
|
-
const absolutePath = path.resolve(process.cwd(), filePath)
|
|
8
|
-
|
|
9
|
-
if (!existsSync(absolutePath)) {
|
|
10
|
-
console.log(pc.red(`Error: File not found at ${filePath}`))
|
|
11
|
-
process.exit(1)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const html = readFileSync(absolutePath, 'utf8')
|
|
15
|
-
const result = validateHtml(html)
|
|
16
|
-
|
|
17
|
-
console.log(pc.bold(pc.cyan(`\n🔍 Validation Report`)))
|
|
18
|
-
console.log(pc.gray('═'.repeat(60)))
|
|
19
|
-
console.log(`${pc.bold('File:')} ${pc.blue(filePath)}`)
|
|
20
|
-
|
|
21
|
-
if (result.valid) {
|
|
22
|
-
console.log(
|
|
23
|
-
pc.bold(
|
|
24
|
-
pc.green(
|
|
25
|
-
`\n✔ PASS: All checks passed! Score: ${result.score ?? 100}/100`
|
|
26
|
-
)
|
|
27
|
-
)
|
|
28
|
-
)
|
|
29
|
-
} else {
|
|
30
|
-
console.log(
|
|
31
|
-
pc.bold(
|
|
32
|
-
pc.red(
|
|
33
|
-
`\n✘ FAIL: Validation failed with ${result.errors.length} violation(s)`
|
|
34
|
-
)
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
console.log(`${pc.bold('Score:')} ${pc.yellow(`${result.score}/100\n`)}`)
|
|
38
|
-
|
|
39
|
-
result.errors.forEach((err, idx) => {
|
|
40
|
-
console.log(pc.bold(pc.red(`[Violation ${idx + 1}]`)))
|
|
41
|
-
console.log(` ${pc.bold('Line:')} ${err.line}`)
|
|
42
|
-
console.log(` ${pc.bold('Element:')} <${err.element}>`)
|
|
43
|
-
console.log(` ${pc.bold('Problem:')} ${pc.yellow(err.message)}`)
|
|
44
|
-
if (err.fix) {
|
|
45
|
-
console.log(` ${pc.bold('Fix:')} ${pc.green(err.fix)}`)
|
|
46
|
-
}
|
|
47
|
-
console.log()
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
console.log()
|
|
51
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander'
|
|
2
|
-
import { initCommand } from './commands/init.js'
|
|
3
|
-
import { themeCommand } from './commands/theme.js'
|
|
4
|
-
import { addCommand } from './commands/add.js'
|
|
5
|
-
import { validateCommand } from './commands/validate.js'
|
|
6
|
-
import { checkA11yCommand } from './commands/check-a11y.js'
|
|
7
|
-
import { listCommand } from './commands/list.js'
|
|
8
|
-
import { infoCommand } from './commands/info.js'
|
|
9
|
-
import { buildCommand } from './commands/build.js'
|
|
10
|
-
import { previewCommand } from './commands/preview.js'
|
|
11
|
-
import { mcpSetupCommand, mcpStartCommand } from './commands/mcp.js'
|
|
12
|
-
|
|
13
|
-
const program = new Command()
|
|
14
|
-
|
|
15
|
-
program
|
|
16
|
-
.name('ignix-lite')
|
|
17
|
-
.description(
|
|
18
|
-
'CLI tool for project initialization, component scaffolding, and local validation in Ignix-Lite'
|
|
19
|
-
)
|
|
20
|
-
.version('1.0.0')
|
|
21
|
-
|
|
22
|
-
program
|
|
23
|
-
.command('init')
|
|
24
|
-
.description('Initialize Ignix-Lite in your project')
|
|
25
|
-
.action(initCommand)
|
|
26
|
-
|
|
27
|
-
program
|
|
28
|
-
.command('theme [prompt]')
|
|
29
|
-
.description(
|
|
30
|
-
'Generate theme variables based on design prompts or primary color'
|
|
31
|
-
)
|
|
32
|
-
.option('-p, --primary <color>', 'Primary color (hex/hsl) explicitly')
|
|
33
|
-
.option('-s, --style-file <path>', 'Stylesheet target path')
|
|
34
|
-
.action(themeCommand)
|
|
35
|
-
|
|
36
|
-
program
|
|
37
|
-
.command('add <component>')
|
|
38
|
-
.description('Add or print an Ignix-Lite component template')
|
|
39
|
-
.action(addCommand)
|
|
40
|
-
|
|
41
|
-
program
|
|
42
|
-
.command('validate <file>')
|
|
43
|
-
.description('Validate a markup file against Ignix-Lite design rules')
|
|
44
|
-
.action(validateCommand)
|
|
45
|
-
|
|
46
|
-
program
|
|
47
|
-
.command('check-a11y <file>')
|
|
48
|
-
.description('Audit a local markup file for WCAG accessibility issues')
|
|
49
|
-
.action(checkA11yCommand)
|
|
50
|
-
|
|
51
|
-
program
|
|
52
|
-
.command('list')
|
|
53
|
-
.description('List all available Ignix-Lite components')
|
|
54
|
-
.action(listCommand)
|
|
55
|
-
program
|
|
56
|
-
.command('info <component>')
|
|
57
|
-
.description('Show detailed manifest and guidelines for a component')
|
|
58
|
-
.action(infoCommand)
|
|
59
|
-
|
|
60
|
-
program
|
|
61
|
-
.command('build <prompt>')
|
|
62
|
-
.description('Generate Ignix-Lite HTML/Emmet from a natural language prompt')
|
|
63
|
-
.option('-o, --output <file>', 'Path to write the synthesized HTML output')
|
|
64
|
-
.option('-e, --emmet-only', 'Output the compiled Emmet shorthand only')
|
|
65
|
-
.action(buildCommand)
|
|
66
|
-
|
|
67
|
-
program
|
|
68
|
-
.command('preview <file>')
|
|
69
|
-
.description('Generate a visual PNG preview of an HTML or Emmet file')
|
|
70
|
-
.option('-o, --output <file>', 'Output image destination', 'preview.png')
|
|
71
|
-
.option('-w, --width <pixels>', 'Viewport width', '400')
|
|
72
|
-
.option('-t, --theme <light|dark>', 'Emulated color scheme theme')
|
|
73
|
-
.action(previewCommand)
|
|
74
|
-
|
|
75
|
-
const mcp = program
|
|
76
|
-
.command('mcp')
|
|
77
|
-
.description('Manage the Ignix-Lite MCP server')
|
|
78
|
-
|
|
79
|
-
mcp
|
|
80
|
-
.command('setup [client]')
|
|
81
|
-
.description(
|
|
82
|
-
'Configure the MCP server for an editor/client (claude, cursor, gemini)'
|
|
83
|
-
)
|
|
84
|
-
.action(mcpSetupCommand)
|
|
85
|
-
|
|
86
|
-
mcp
|
|
87
|
-
.command('start')
|
|
88
|
-
.description('Start the Ignix-Lite MCP server')
|
|
89
|
-
.action(mcpStartCommand)
|
|
90
|
-
|
|
91
|
-
program.parse(process.argv)
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*"]
|
|
15
|
-
}
|