@chemx/create-chemx 26.9.16-41 → 26.9.17-1100
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/README.md +181 -2
- package/assets/chemx-starter-kit-logo.gif +0 -0
- package/blueprints/_view-template.scss +24 -0
- package/blueprints/atoms/a-button.vue +43 -0
- package/blueprints/molecule-capsule/_m-sample-card.scss +75 -0
- package/blueprints/molecule-capsule/index.ts +2 -0
- package/blueprints/molecule-capsule/m-chemx-badge/_m-chemx-badge.scss +76 -0
- package/blueprints/molecule-capsule/m-chemx-badge/index.ts +3 -0
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.spec.ts +74 -0
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.tsx +39 -0
- package/blueprints/molecule-capsule/m-chemx-badge/m-chemx-badge.vue +42 -0
- package/blueprints/molecule-capsule/m-chemx-badge/types.d.ts +12 -0
- package/blueprints/molecule-capsule/m-sample-card.spec.ts +74 -0
- package/blueprints/molecule-capsule/m-sample-card.tsx +72 -0
- package/blueprints/molecule-capsule/m-tab-button/_m-tab-button.scss +49 -0
- package/blueprints/molecule-capsule/m-tab-button/index.ts +3 -0
- package/blueprints/molecule-capsule/m-tab-button/m-tab-button.controller.ts +40 -0
- package/blueprints/molecule-capsule/m-tab-button/m-tab-button.spec.ts +40 -0
- package/blueprints/molecule-capsule/m-tab-button/m-tab-button.vue +38 -0
- package/blueprints/molecule-capsule/m-tab-button/types.d.ts +14 -0
- package/blueprints/molecule-capsule/types.d.ts +12 -0
- package/blueprints/shims-vue.d.ts +4 -0
- package/blueprints/view-template.tsx +20 -0
- package/blueprints/workflows/chemx-audit.yml +79 -0
- package/cli/audit/ast-visitors.js +73 -0
- package/cli/audit/autofix.js +4 -5
- package/cli/audit/extended-visitors.js +243 -0
- package/cli/audit/pattern-detector.js +90 -3
- package/cli/audit/pattern-detector.spec.js +36 -1
- package/cli/audit/prompts.js +10 -12
- package/cli/audit/reporter-utils.js +13 -22
- package/cli/audit/roadmap.js +5 -20
- package/cli/audit/rules-predicates.js +3 -2
- package/cli/audit/rules-registry.js +25 -0
- package/cli/audit/rules.js +4 -0
- package/cli/audit/rules.spec.js +205 -0
- package/cli/audit-preflight-git.js +54 -0
- package/cli/audit-preflight-scope.js +87 -0
- package/cli/audit-preflight.d.ts +16 -0
- package/cli/audit-preflight.js +85 -0
- package/cli/audit-preflight.spec.js +115 -0
- package/cli/audit.js +48 -22
- package/cli/build/detector.js +40 -23
- package/cli/build/detector.spec.js +81 -0
- package/cli/build.d.ts +2 -1
- package/cli/build.js +16 -12
- package/cli/columnar.d.ts +14 -0
- package/cli/columnar.js +52 -0
- package/cli/columnar.spec.js +49 -0
- package/cli/generator-templates/controller.js +36 -0
- package/cli/generator-templates/hooks.js +60 -0
- package/cli/generator-templates/naming.js +14 -0
- package/cli/generator-templates/react.js +63 -0
- package/cli/generator-templates/specs.js +38 -0
- package/cli/generator-templates/styles.js +64 -0
- package/cli/generator-templates/svelte.js +66 -0
- package/cli/generator-templates/types.js +29 -0
- package/cli/generator-templates/views.js +76 -0
- package/cli/generator-templates/vue.js +62 -0
- package/cli/generator-templates.d.ts +35 -0
- package/cli/generator-templates.js +28 -480
- package/cli/generator-templates.spec.js +108 -0
- package/cli/generator.js +2 -2
- package/cli/generator.spec.js +61 -1
- package/cli/help.js +38 -4
- package/cli/index.js +112 -14
- package/cli/installer-templates.js +67 -13
- package/cli/installer.d.ts +2 -0
- package/cli/installer.js +48 -21
- package/cli/installer.spec.js +72 -0
- package/cli/license.js +22 -1
- package/cli/mcp/antigravity.js +59 -0
- package/cli/mcp/index.js +2 -1
- package/cli/mcp/installer.js +54 -22
- package/cli/mcp/installer.spec.js +24 -1
- package/cli/mcp/manifests.js +332 -0
- package/cli/mcp/prompts.js +28 -0
- package/cli/mcp/resources.js +175 -64
- package/cli/mcp/server.js +51 -5
- package/cli/mcp/server.spec.js +247 -1
- package/cli/mcp/tools.js +386 -194
- package/cli/mcp/types.d.ts +37 -0
- package/cli/navigator-actions.js +23 -10
- package/cli/navigator-banner-helpers.js +33 -0
- package/cli/navigator-banner.js +19 -38
- package/cli/navigator-banner.spec.js +68 -0
- package/cli/navigator-guide.js +73 -0
- package/cli/navigator-menu.js +20 -0
- package/cli/navigator.js +1 -0
- package/cli/patcher.d.ts +73 -0
- package/cli/patcher.js +249 -4
- package/cli/patcher.spec.js +148 -0
- package/cli/postinstall.js +27 -0
- package/cli/project-detector.js +20 -2
- package/cli/project-detector.spec.js +19 -0
- package/cli/reader.js +18 -4
- package/cli/scaffold.js +26 -4
- package/cli/search-commands.js +10 -8
- package/cli/search-queries.js +8 -3
- package/cli/search-schema.js +5 -0
- package/cli/search.d.ts +16 -0
- package/cli/search.js +103 -11
- package/cli/silence-warnings.js +17 -0
- package/cli/team/index.js +30 -0
- package/cli/team/team-adversarial-locks.spec.js +105 -0
- package/cli/team/team-adversarial-telemetry.spec.js +93 -0
- package/cli/team/team-commands.js +199 -0
- package/cli/team/team-db-agents.js +79 -0
- package/cli/team/team-db-feed.js +84 -0
- package/cli/team/team-db-lock-promotion.js +91 -0
- package/cli/team/team-db-locks.js +94 -0
- package/cli/team/team-db-task-helpers.js +94 -0
- package/cli/team/team-db-tasks.js +90 -0
- package/cli/team/team-db.js +93 -0
- package/cli/team/team-format.js +80 -0
- package/cli/team/team-lock-concurrency.spec.js +182 -0
- package/cli/team/team-schema.js +74 -0
- package/cli/team/team-telemetry.js +104 -0
- package/cli/team/team-triage.js +88 -0
- package/cli/team/team.spec.js +344 -0
- package/cli/terminal.js +36 -1
- package/cli/ui-actions-helpers.js +66 -0
- package/cli/ui-actions.js +85 -0
- package/cli/ui-attention.js +74 -0
- package/cli/ui-client-api.js +49 -0
- package/cli/ui-client-cert.js +27 -0
- package/cli/ui-client-script.js +83 -0
- package/cli/ui-db-studio.js +79 -0
- package/cli/ui-handlers.js +95 -0
- package/cli/ui-html.js +35 -0
- package/cli/ui-server-routes.js +63 -0
- package/cli/ui-server.js +75 -0
- package/cli/ui-styles.js +34 -0
- package/cli/ui-template-views.js +63 -0
- package/cli/ui-template.js +91 -0
- package/cli/ui.spec.js +305 -0
- package/cli/verify.js +367 -0
- package/cli/verify.spec.js +98 -0
- package/docs/CHANGELOG.md +10 -0
- package/package.json +13 -15
- package/scripts/postinstall.mjs +27 -0
- package/scripts/pre-commit.sh +135 -0
- package/scripts/publish-both.mjs +108 -0
- package/cli/mcp.js +0 -326
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Chemical X Protocol: Starter Kit
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="./assets/chemx-starter-kit-logo.gif" alt="Chemical X Starter Kit Comic Logo" width="380" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
3
7
|
[](https://chemicalx.xophz.com)
|
|
4
8
|
[](https://github.com/Chemical-X-Protocol/awesome-secret-sauce)
|
|
5
9
|
[](https://github.com/Chemical-X-Protocol/benchmarks)
|
|
@@ -27,15 +31,190 @@ starter-kit/
|
|
|
27
31
|
│ ├── useSelfCleaningTimer.ts # Unmount-safe timer and RAF hook
|
|
28
32
|
│ └── useTwoStageDecision.ts # Concept to Decision composition
|
|
29
33
|
└── cli/
|
|
30
|
-
|
|
34
|
+
├── index.js # CLI router & capsule generator
|
|
35
|
+
├── verify.js # Zero-token-burn verification engine
|
|
36
|
+
├── audit.js # 7-Pillar static AST audit
|
|
37
|
+
└── mcp/ # Model Context Protocol stdio server
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Zero-Token-Burn Verification Pipeline
|
|
43
|
+
|
|
44
|
+
Running raw, unthrottled `npm test`, `tsc --noEmit`, or build tools dumps thousands of lines of passing checkmarks, compiler noise, and bundle asset tables into an AI agent's context window. This burns tokens prematurely and degrades context quality.
|
|
45
|
+
|
|
46
|
+
Chemical X wraps tests, typechecks, and builds into silent, failure-focused verification tools available via CLI and native MCP tools:
|
|
47
|
+
|
|
48
|
+
### Side-by-Side Benchmark Reports
|
|
49
|
+
|
|
50
|
+
#### 1. Test Suite: `npm test` vs `chemx test`
|
|
51
|
+
|
|
52
|
+
Ran across the starter-kit test suite (143 test cases across 8 spec suites):
|
|
53
|
+
|
|
54
|
+
| Metric | Raw `npm test` | Chemical X `chemx test` | Improvement |
|
|
55
|
+
| :--- | :--- | :--- | :--- |
|
|
56
|
+
| **Execution Time** | **~3.1s - 7.5s** | **~3.5s - 3.7s** | Identical underlying test speed |
|
|
57
|
+
| **Output Lines** | **957 lines** | **1 line** | **99.9% line reduction** |
|
|
58
|
+
| **Characters Streamed** | **49,246 characters** | **44 characters** | **99.9% character reduction** |
|
|
59
|
+
| **Agent Token Cost** | **~12,960 tokens** | **~12 tokens** | **12,948 tokens saved (99.9%)** |
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
# Raw npm test: Floods context with ~13,000 tokens of passing checkmarks
|
|
63
|
+
✔ resolveTargetDir: returns custom directory if provided as first argument (1.64ms)
|
|
64
|
+
✔ search-db: indexes symbols with line ranges and finds definition (56.65ms)
|
|
65
|
+
✔ Verify: parseTestOutput strips passing checkmarks and extracts only failing tests (1.01ms)
|
|
66
|
+
... [940 MORE LINES OF PASSING CHECKMARKS & TIMINGS] ...
|
|
67
|
+
ℹ tests 143 | pass 143 | fail 0 | duration_ms 3002.57ms
|
|
68
|
+
|
|
69
|
+
# Chemical X: Pinpoint single-line summary
|
|
70
|
+
$ npx chemx test
|
|
71
|
+
✔ All tests passed (143 tests in 3500ms)
|
|
31
72
|
```
|
|
32
73
|
|
|
74
|
+
#### 2. TypeScript Typecheck: `npm run typecheck` vs `chemx typecheck`
|
|
75
|
+
|
|
76
|
+
| Metric | Raw `npm run typecheck` | Chemical X `chemx typecheck` | Difference |
|
|
77
|
+
| :--- | :--- | :--- | :--- |
|
|
78
|
+
| **Execution Time** | **1.85s** | **2.06s** | **+0.21s** (lightweight wrapper) |
|
|
79
|
+
| **Output Characters** | 54 characters | **40 characters** | **26% reduction** |
|
|
80
|
+
| **Context Token Cost** | ~14 tokens | **~10 tokens** | **~28% reduction** |
|
|
81
|
+
| **Clean Output** | npm script banner noise | Single clean status line | Zero CLI banner noise |
|
|
82
|
+
| **JSON Mode (`--json`)** | Not supported | **~30 tokens** structured JSON | Direct agent ingestion |
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Clean, banner-free terminal verification
|
|
86
|
+
$ npx chemx typecheck
|
|
87
|
+
✔ TypeScript typecheck clean (1820ms)
|
|
88
|
+
|
|
89
|
+
# Machine-readable output for AI agents
|
|
90
|
+
$ npx chemx typecheck --json
|
|
91
|
+
{
|
|
92
|
+
"success": true,
|
|
93
|
+
"exitCode": 0,
|
|
94
|
+
"command": "npm run typecheck",
|
|
95
|
+
"durationMs": 1820,
|
|
96
|
+
"errorCount": 0,
|
|
97
|
+
"errors": []
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### 3. Production Build: Raw Build vs `chemx build`
|
|
102
|
+
|
|
103
|
+
| Metric | Raw Production Build | Chemical X `chemx build` | Chemical X `--silent` |
|
|
104
|
+
| :--- | :--- | :--- | :--- |
|
|
105
|
+
| **Terminal Output** | Multi-page asset size tables & chunks | Single status line | **0 lines (completely silent)** |
|
|
106
|
+
| **Token Cost (Success)** | **~2,000 - 8,000 tokens** | **~15 tokens** | **0 tokens** |
|
|
107
|
+
| **Failure Diagnosis** | Scatted across hundreds of lines | Categorized diagnostic buckets | Exact failure lines only |
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
$ npx chemx build
|
|
111
|
+
Auditing build: npx tsc --noEmit
|
|
112
|
+
✔ Build Succeeded (5.20s)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### 4. Full Pipeline: `chemx verify` Grand Total
|
|
116
|
+
|
|
117
|
+
When an AI agent runs a complete pre-commit or post-refactor verification pass:
|
|
118
|
+
|
|
119
|
+
| Verification Stage | Raw Unthrottled Shell Commands | Chemical X `chemx verify` |
|
|
120
|
+
| :--- | :--- | :--- |
|
|
121
|
+
| **7-Pillar AST Audit** | ~4,000 tokens | Included |
|
|
122
|
+
| **TypeScript Compilation** | ~14 tokens | Included |
|
|
123
|
+
| **Project Test Suite** | ~12,960 tokens | Included |
|
|
124
|
+
| **Total Context Burn** | **~17,000+ tokens** | **~45 tokens** |
|
|
125
|
+
| **Context Savings** | Baseline | **99.7% Token Reduction** |
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
$ npx chemx verify --dir=blueprints
|
|
129
|
+
|
|
130
|
+
⚡ Chemical X: Token-Conserving Project Verification
|
|
131
|
+
|
|
132
|
+
✔ AST Architecture: A+ (100/100, 0 violations)
|
|
133
|
+
✔ TypeScript: Clean (0 errors)
|
|
134
|
+
✔ Test Suite: Passed (143/143)
|
|
135
|
+
|
|
136
|
+
All verification checks passed with zero context burn!
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Model Context Protocol (MCP) Server
|
|
142
|
+
|
|
143
|
+
Chemical X includes a high-performance, zero-dependency JSON-RPC 2.0 Stdio MCP server that connects directly to AI agent hosts (Cursor, Claude Desktop, Windsurf, Antigravity, VS Code).
|
|
144
|
+
|
|
145
|
+
### Automatic 1-Step Installation
|
|
146
|
+
|
|
147
|
+
Run the interactive installer in your workspace root:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx chemx install-mcp
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This automatically registers the Chemical X server in:
|
|
154
|
+
- `.cursor/mcp.json` (Cursor IDE)
|
|
155
|
+
- `.vscode/mcp.json` (VS Code)
|
|
156
|
+
- `~/.gemini/config/mcp_config.json` (Antigravity)
|
|
157
|
+
- Injects `chemx:mcp`, `chemx:verify`, `chemx:test`, and `chemx:typecheck` into your `package.json` scripts
|
|
158
|
+
|
|
159
|
+
### Manual MCP Server Configuration
|
|
160
|
+
|
|
161
|
+
To configure manually in your MCP client settings (e.g. `claude_desktop_config.json` or `.cursor/mcp.json`):
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"mcpServers": {
|
|
166
|
+
"chemical-x": {
|
|
167
|
+
"command": "npx",
|
|
168
|
+
"args": ["-y", "chemx", "mcp"]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Available MCP Tools (14 Tools)
|
|
175
|
+
|
|
176
|
+
| Tool Name | Scope | Purpose |
|
|
177
|
+
| :--- | :--- | :--- |
|
|
178
|
+
| `chemx_verify` | Verification | Full pipeline gatekeeper: AST Audit + Typecheck + Tests into a ~45-token card. |
|
|
179
|
+
| `chemx_typecheck` | Verification | Silent TypeScript typecheck audit. Drops compiler noise; returns structured diagnostics on error. |
|
|
180
|
+
| `chemx_test` | Verification | Silent project test runner. Suppresses passing checkmarks; returns ONLY failing test assertions. |
|
|
181
|
+
| `chemx_audit_build` | Verification | Wrap build commands with silent execution and catalog compiler diagnostics into structured categories. |
|
|
182
|
+
| `chemx_audit` | Quality | Run the full 7-Pillar Chemical X static AST audit. Returns health score, grade (A+ to F), and hazard list. |
|
|
183
|
+
| `chemx_check` | Quality | Verify a single file or capsule against molecular boundary rules (< 100L, 2-stage booleans, zero raw DOM). |
|
|
184
|
+
| `chemx_q` | Discovery | AST search index query machine. Query symbols, capsules, props, and hooks with minimal token burn. |
|
|
185
|
+
| `chemx_query_patterns` | Discovery | Detect duplicated state machines, cloned UI layouts, and parallel hooks before decomposing monoliths. |
|
|
186
|
+
| `chemx_read` | Reading | Token-minified file reader. Extracts AST outlines, stripped comments, or symbol blocks (80%+ token savings). |
|
|
187
|
+
| `chemx_patch` | Editing | Surgically patch files with exact search and replace blocks without whole-file context dumps. |
|
|
188
|
+
| `chemx_write` | Editing | Create or overwrite files with automatic SQLite AST indexing and boundary compliance checks. |
|
|
189
|
+
| `chemx_autofix` | Remediation | Deterministically remediate safe violations (typography hyphens, markdown fences, AI slop comments). |
|
|
190
|
+
| `chemx_generate_capsule` | Scaffolding | Deterministically generate a crystalline capsule directory (component, controller, SCSS, types, index). |
|
|
191
|
+
| `chemx_get_refactor_prompt` | Prompting | Synthesize targeted refactoring prompts for Grade F critical hazards, hotspots, and slop artifacts. |
|
|
192
|
+
|
|
193
|
+
### Living Resources & Prompts
|
|
194
|
+
|
|
195
|
+
* **Resources**:
|
|
196
|
+
* `chemx://directives`: Mandatory Chemical X Molecular Architecture directives (AGENTS.md).
|
|
197
|
+
* `chemx://scorecard`: Live Molecular Health Index (MHI) grade, score, metrics, and active hazards.
|
|
198
|
+
* `chemx://blueprints/molecule`: Compliant molecule blueprint adhering to zero raw DOM standards.
|
|
199
|
+
* `chemx://blueprints/view-template`: Declarative 10-20 line Table-of-Contents view blueprint.
|
|
200
|
+
* **Prompts**:
|
|
201
|
+
* `chemx_remediate_hotspot`: Dynamically inspects candidate file AST metrics and generates targeted decomposition instructions.
|
|
202
|
+
* `chemx_harmonize_patterns`: Generates Pre-Split Pattern Discovery instructions to extract shared capsules.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
33
206
|
## Release Versioning: Minute-Precision CalVer
|
|
34
207
|
|
|
35
208
|
This package adheres to **Minute-Precision Calendar Versioning** (`YY.MM.DD-MMMM`):
|
|
36
|
-
- `YY.MM.DD`: Release date (e.g. `26.9.
|
|
209
|
+
- `YY.MM.DD`: Release date (e.g. `26.9.17` for Sept 17, 2026).
|
|
37
210
|
- `MMMM`: Minute of the day (0 to 1439).
|
|
38
211
|
|
|
212
|
+
Check installed version at any time:
|
|
213
|
+
```bash
|
|
214
|
+
npx chemx --version
|
|
215
|
+
# create-chemx v26.9.17-606
|
|
216
|
+
```
|
|
217
|
+
|
|
39
218
|
Because autonomous coding agent models update frequently, this package is continuously integrated and deployed via automated CI whenever new agent directives, AST checks, or framework rules are tuned. Rapid version iterations reflect active, daily alignment rather than breaking SemVer shifts.
|
|
40
219
|
|
|
41
220
|
> [!NOTE]
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.view-template {
|
|
2
|
+
padding: 24px;
|
|
3
|
+
background: #0b1329;
|
|
4
|
+
color: #e2e8f0;
|
|
5
|
+
min-height: 100vh;
|
|
6
|
+
|
|
7
|
+
&__header {
|
|
8
|
+
margin-bottom: 24px;
|
|
9
|
+
border-bottom: 1px solid #1e293b;
|
|
10
|
+
padding-bottom: 16px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&__title {
|
|
14
|
+
margin: 0;
|
|
15
|
+
font-size: 24px;
|
|
16
|
+
color: #62c9ff;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&__content {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 20px;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Chemical X Protocol: Foundational Atom Tier
|
|
4
|
+
* Directive: Atoms are the ONLY tier where raw DOM/HTML elements are permitted.
|
|
5
|
+
*/
|
|
6
|
+
interface Props {
|
|
7
|
+
type?: 'button' | 'submit' | 'reset';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
ariaLabel?: string;
|
|
10
|
+
variant?: 'primary' | 'ghost' | 'glass';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
+
type: 'button',
|
|
15
|
+
disabled: false,
|
|
16
|
+
ariaLabel: undefined,
|
|
17
|
+
variant: 'primary'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const emit = defineEmits<{
|
|
21
|
+
(e: 'click', event: MouseEvent): void;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const handleClick = (event: MouseEvent) => {
|
|
25
|
+
if (props.disabled) return;
|
|
26
|
+
emit('click', event);
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<button
|
|
32
|
+
:type="props.type"
|
|
33
|
+
:disabled="props.disabled"
|
|
34
|
+
:aria-label="props.ariaLabel"
|
|
35
|
+
class="a-button cursor-pointer"
|
|
36
|
+
:data-variant="props.variant"
|
|
37
|
+
@click="handleClick"
|
|
38
|
+
>
|
|
39
|
+
<slot name="prepend" />
|
|
40
|
+
<slot />
|
|
41
|
+
<slot name="append" />
|
|
42
|
+
</button>
|
|
43
|
+
</template>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
.m-sample-card {
|
|
2
|
+
background: #131e3a;
|
|
3
|
+
border: 1px solid #1e293b;
|
|
4
|
+
border-radius: 8px;
|
|
5
|
+
padding: 16px;
|
|
6
|
+
|
|
7
|
+
&__header {
|
|
8
|
+
display: flex;
|
|
9
|
+
justify-content: space-between;
|
|
10
|
+
align-items: flex-start;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&__title-group {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&__title {
|
|
19
|
+
margin: 0;
|
|
20
|
+
font-size: 16px;
|
|
21
|
+
color: #ffffff;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&__subtitle {
|
|
25
|
+
margin: 4px 0 0;
|
|
26
|
+
font-size: 12px;
|
|
27
|
+
color: #94a3b8;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&__badge {
|
|
31
|
+
font-size: 11px;
|
|
32
|
+
padding: 2px 8px;
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
background: #0b1329;
|
|
35
|
+
|
|
36
|
+
&--archived {
|
|
37
|
+
color: #f87171;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&--high-value {
|
|
41
|
+
color: #4ade80;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&--standard {
|
|
45
|
+
color: #86efac;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&__body {
|
|
50
|
+
margin-top: 16px;
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-content: space-between;
|
|
53
|
+
align-items: center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&__value {
|
|
57
|
+
font-size: 20px;
|
|
58
|
+
font-weight: bold;
|
|
59
|
+
color: #62c9ff;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&__action {
|
|
63
|
+
padding: 6px 12px;
|
|
64
|
+
background: #1e293b;
|
|
65
|
+
border: 1px solid #334155;
|
|
66
|
+
color: #ffffff;
|
|
67
|
+
border-radius: 4px;
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
transition: background-color 0.15s ease-in-out;
|
|
70
|
+
|
|
71
|
+
&:hover {
|
|
72
|
+
background: #334155;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
.m-chemx-badge {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: 0.5rem;
|
|
5
|
+
padding: 0.25rem 0.75rem;
|
|
6
|
+
border-radius: 9999px;
|
|
7
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
8
|
+
font-size: 0.7rem;
|
|
9
|
+
text-decoration: none;
|
|
10
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
11
|
+
background: rgba(9, 13, 22, 0.85);
|
|
12
|
+
backdrop-filter: blur(8px);
|
|
13
|
+
-webkit-backdrop-filter: blur(8px);
|
|
14
|
+
color: #cbd5e1;
|
|
15
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
16
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
border-color: rgba(56, 189, 248, 0.5);
|
|
20
|
+
box-shadow: 0 0 12px rgba(56, 189, 248, 0.25);
|
|
21
|
+
transform: scale(1.02);
|
|
22
|
+
color: #f8fafc;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&__dot {
|
|
26
|
+
width: 0.5rem;
|
|
27
|
+
height: 0.5rem;
|
|
28
|
+
border-radius: 50%;
|
|
29
|
+
background-color: #a3e635;
|
|
30
|
+
box-shadow: 0 0 8px rgba(163, 230, 53, 0.6);
|
|
31
|
+
animation: chemx-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&__label {
|
|
35
|
+
font-weight: 500;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&__grade {
|
|
39
|
+
padding: 0.1rem 0.4rem;
|
|
40
|
+
border-radius: 9999px;
|
|
41
|
+
font-weight: 700;
|
|
42
|
+
font-size: 0.65rem;
|
|
43
|
+
letter-spacing: -0.02em;
|
|
44
|
+
|
|
45
|
+
&--a {
|
|
46
|
+
background: rgba(163, 230, 53, 0.15);
|
|
47
|
+
color: #a3e635;
|
|
48
|
+
border: 1px solid rgba(163, 230, 53, 0.3);
|
|
49
|
+
}
|
|
50
|
+
&--b {
|
|
51
|
+
background: rgba(56, 189, 248, 0.15);
|
|
52
|
+
color: #38bdf8;
|
|
53
|
+
border: 1px solid rgba(56, 189, 248, 0.3);
|
|
54
|
+
}
|
|
55
|
+
&--c {
|
|
56
|
+
background: rgba(251, 191, 36, 0.15);
|
|
57
|
+
color: #fbbf24;
|
|
58
|
+
border: 1px solid rgba(251, 191, 36, 0.3);
|
|
59
|
+
}
|
|
60
|
+
&--d {
|
|
61
|
+
background: rgba(249, 115, 22, 0.15);
|
|
62
|
+
color: #f97316;
|
|
63
|
+
border: 1px solid rgba(249, 115, 22, 0.3);
|
|
64
|
+
}
|
|
65
|
+
&--f {
|
|
66
|
+
background: rgba(244, 63, 133, 0.15);
|
|
67
|
+
color: #f43f85;
|
|
68
|
+
border: 1px solid rgba(244, 63, 133, 0.3);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@keyframes chemx-pulse {
|
|
74
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
75
|
+
50% { opacity: 0.5; transform: scale(0.9); }
|
|
76
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
4
|
+
import { MChemxBadge, resolveGradeClass } from './m-chemx-badge';
|
|
5
|
+
|
|
6
|
+
describe('m-chemx-badge: resolveGradeClass', () => {
|
|
7
|
+
it('resolves tier-a grade class for grade A variants', () => {
|
|
8
|
+
expect(resolveGradeClass('A+')).toBe('m-chemx-badge__grade--a');
|
|
9
|
+
expect(resolveGradeClass('a')).toBe('m-chemx-badge__grade--a');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('resolves tier-b grade class for grade B variants', () => {
|
|
13
|
+
expect(resolveGradeClass('B+')).toBe('m-chemx-badge__grade--b');
|
|
14
|
+
expect(resolveGradeClass('b')).toBe('m-chemx-badge__grade--b');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('resolves tier-c grade class for grade C variants', () => {
|
|
18
|
+
expect(resolveGradeClass('C')).toBe('m-chemx-badge__grade--c');
|
|
19
|
+
expect(resolveGradeClass('c')).toBe('m-chemx-badge__grade--c');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('resolves tier-d grade class for grade D variants', () => {
|
|
23
|
+
expect(resolveGradeClass('D')).toBe('m-chemx-badge__grade--d');
|
|
24
|
+
expect(resolveGradeClass('d')).toBe('m-chemx-badge__grade--d');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('resolves tier-f grade class for grade F and unclassified inputs', () => {
|
|
28
|
+
expect(resolveGradeClass('F')).toBe('m-chemx-badge__grade--f');
|
|
29
|
+
expect(resolveGradeClass('unknown')).toBe('m-chemx-badge__grade--f');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('m-chemx-badge: MChemxBadge Component', () => {
|
|
34
|
+
it('renders default badge markup with secure attributes', () => {
|
|
35
|
+
const html = renderToStaticMarkup(React.createElement(MChemxBadge));
|
|
36
|
+
|
|
37
|
+
expect(html).toContain('href="https://chemicalx.xophz.com"');
|
|
38
|
+
expect(html).toContain('target="_blank"');
|
|
39
|
+
expect(html).toContain('rel="noopener noreferrer"');
|
|
40
|
+
expect(html).toContain('title="Verified by Chemical X Molecular Architecture Protocol"');
|
|
41
|
+
expect(html).toContain('class="m-chemx-badge"');
|
|
42
|
+
expect(html).toContain('class="m-chemx-badge__dot"');
|
|
43
|
+
expect(html).toContain('AI Slop cleaned with Chemical X');
|
|
44
|
+
expect(html).toContain('class="m-chemx-badge__grade m-chemx-badge__grade--a"');
|
|
45
|
+
expect(html).toContain('[A+]');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('prioritizes reportUrl over standard href when provided', () => {
|
|
49
|
+
const customReport = 'https://reports.chemicalx.xophz.com/audit/42';
|
|
50
|
+
const html = renderToStaticMarkup(
|
|
51
|
+
React.createElement(MChemxBadge, {
|
|
52
|
+
reportUrl: customReport,
|
|
53
|
+
href: 'https://fallback.com'
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(html).toContain(`href="${customReport}"`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('applies custom label, grade, and className correctly', () => {
|
|
61
|
+
const html = renderToStaticMarkup(
|
|
62
|
+
React.createElement(MChemxBadge, {
|
|
63
|
+
label: 'Custom Verified Audit',
|
|
64
|
+
grade: 'B',
|
|
65
|
+
className: 'custom-anchor-modifier'
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(html).toContain('class="m-chemx-badge custom-anchor-modifier"');
|
|
70
|
+
expect(html).toContain('Custom Verified Audit');
|
|
71
|
+
expect(html).toContain('class="m-chemx-badge__grade m-chemx-badge__grade--b"');
|
|
72
|
+
expect(html).toContain('[B]');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { MChemxBadgeProps } from './types';
|
|
3
|
+
|
|
4
|
+
export const resolveGradeClass = (grade: string): string => {
|
|
5
|
+
const g = grade.toUpperCase();
|
|
6
|
+
if (g.startsWith('A')) return 'm-chemx-badge__grade--a';
|
|
7
|
+
if (g.startsWith('B')) return 'm-chemx-badge__grade--b';
|
|
8
|
+
if (g.startsWith('C')) return 'm-chemx-badge__grade--c';
|
|
9
|
+
if (g.startsWith('D')) return 'm-chemx-badge__grade--d';
|
|
10
|
+
return 'm-chemx-badge__grade--f';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const MChemxBadge: React.FC<MChemxBadgeProps> = ({
|
|
14
|
+
label = 'AI Slop cleaned with Chemical X',
|
|
15
|
+
grade = 'A+',
|
|
16
|
+
href = 'https://chemicalx.xophz.com',
|
|
17
|
+
reportUrl,
|
|
18
|
+
className = ''
|
|
19
|
+
}) => {
|
|
20
|
+
const gradeClass = resolveGradeClass(grade);
|
|
21
|
+
const targetHref = reportUrl || href;
|
|
22
|
+
const rootClass = `m-chemx-badge ${className}`.trim();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<a
|
|
26
|
+
href={targetHref}
|
|
27
|
+
target="_blank"
|
|
28
|
+
rel="noopener noreferrer"
|
|
29
|
+
className={rootClass}
|
|
30
|
+
title="Verified by Chemical X Molecular Architecture Protocol"
|
|
31
|
+
>
|
|
32
|
+
<span className="m-chemx-badge__dot" />
|
|
33
|
+
<span className="m-chemx-badge__label">{label}</span>
|
|
34
|
+
<span className={`m-chemx-badge__grade ${gradeClass}`}>[{grade}]</span>
|
|
35
|
+
</a>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default MChemxBadge;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import type { MChemxBadgeProps } from './types';
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(defineProps<MChemxBadgeProps>(), {
|
|
6
|
+
label: 'AI Slop cleaned with Chemical X',
|
|
7
|
+
grade: 'A+',
|
|
8
|
+
href: 'https://chemicalx.xophz.com',
|
|
9
|
+
reportUrl: undefined,
|
|
10
|
+
className: ''
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// 1. Composables & Stores
|
|
14
|
+
|
|
15
|
+
// 2. Reactive Primitives
|
|
16
|
+
|
|
17
|
+
// 3. Computed State
|
|
18
|
+
const targetHref = computed(() => props.reportUrl || props.href);
|
|
19
|
+
const gradeClass = computed(() => {
|
|
20
|
+
const g = props.grade.toUpperCase();
|
|
21
|
+
if (g.startsWith('A')) return 'm-chemx-badge__grade--a';
|
|
22
|
+
if (g.startsWith('B')) return 'm-chemx-badge__grade--b';
|
|
23
|
+
if (g.startsWith('C')) return 'm-chemx-badge__grade--c';
|
|
24
|
+
if (g.startsWith('D')) return 'm-chemx-badge__grade--d';
|
|
25
|
+
return 'm-chemx-badge__grade--f';
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<a
|
|
31
|
+
:href="targetHref"
|
|
32
|
+
target="_blank"
|
|
33
|
+
rel="noopener noreferrer"
|
|
34
|
+
class="m-chemx-badge"
|
|
35
|
+
:class="className"
|
|
36
|
+
title="Verified by Chemical X Molecular Architecture Protocol"
|
|
37
|
+
>
|
|
38
|
+
<span class="m-chemx-badge__dot" />
|
|
39
|
+
<span class="m-chemx-badge__label">{{ label }}</span>
|
|
40
|
+
<span class="m-chemx-badge__grade" :class="gradeClass">[{{ grade }}]</span>
|
|
41
|
+
</a>
|
|
42
|
+
</template>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
4
|
+
import { MSampleCard, resolveBadgeDescriptor } from './m-sample-card';
|
|
5
|
+
|
|
6
|
+
describe('m-sample-card: resolveBadgeDescriptor', () => {
|
|
7
|
+
it('returns archived badge descriptor when status is archived', () => {
|
|
8
|
+
const descriptor = resolveBadgeDescriptor('archived', false);
|
|
9
|
+
expect(descriptor.text).toBe('archived');
|
|
10
|
+
expect(descriptor.className).toBe('m-sample-card__badge m-sample-card__badge--archived');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('returns high-value badge descriptor when active and value exceeds threshold', () => {
|
|
14
|
+
const descriptor = resolveBadgeDescriptor('active', true);
|
|
15
|
+
expect(descriptor.text).toBe('active');
|
|
16
|
+
expect(descriptor.className).toBe('m-sample-card__badge m-sample-card__badge--high-value');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('returns standard badge descriptor when active and value is within standard range', () => {
|
|
20
|
+
const descriptor = resolveBadgeDescriptor('active', false);
|
|
21
|
+
expect(descriptor.text).toBe('active');
|
|
22
|
+
expect(descriptor.className).toBe('m-sample-card__badge m-sample-card__badge--standard');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('m-sample-card: MSampleCard Component', () => {
|
|
27
|
+
it('renders title, formatted value, and standard badge correctly', () => {
|
|
28
|
+
const html = renderToStaticMarkup(
|
|
29
|
+
React.createElement(MSampleCard, {
|
|
30
|
+
title: 'Core Subscription',
|
|
31
|
+
subtitle: 'Monthly compute tier',
|
|
32
|
+
value: 750
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(html).toContain('class="m-sample-card"');
|
|
37
|
+
expect(html).toContain('Core Subscription');
|
|
38
|
+
expect(html).toContain('Monthly compute tier');
|
|
39
|
+
expect(html).toContain('$750');
|
|
40
|
+
expect(html).toContain('m-sample-card__badge--standard');
|
|
41
|
+
expect(html).not.toContain('m-sample-card__action');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('renders high-value modifier when numeric value exceeds 1000', () => {
|
|
45
|
+
const html = renderToStaticMarkup(
|
|
46
|
+
React.createElement(MSampleCard, {
|
|
47
|
+
title: 'Enterprise Cluster',
|
|
48
|
+
value: 2500
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(html).toContain('Enterprise Cluster');
|
|
53
|
+
expect(html).toContain('$2,500');
|
|
54
|
+
expect(html).toContain('m-sample-card__badge--high-value');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('renders action button and triggers onAction callback when clicked', () => {
|
|
58
|
+
const handleAction = vi.fn();
|
|
59
|
+
const vnode = MSampleCard({
|
|
60
|
+
title: 'Actionable Unit',
|
|
61
|
+
value: 1200,
|
|
62
|
+
onAction: handleAction
|
|
63
|
+
}) as React.ReactElement;
|
|
64
|
+
|
|
65
|
+
const bodyNode = (vnode.props.children as React.ReactElement[])[1];
|
|
66
|
+
const buttonNode = (bodyNode.props.children as React.ReactElement[])[1];
|
|
67
|
+
|
|
68
|
+
expect(buttonNode).toBeDefined();
|
|
69
|
+
expect(buttonNode.props.className).toBe('m-sample-card__action');
|
|
70
|
+
|
|
71
|
+
buttonNode.props.onClick();
|
|
72
|
+
expect(handleAction).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
});
|