@chemx/starter-kit 26.9.9-700 → 26.9.9-786

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/cli/audit.js CHANGED
@@ -183,6 +183,18 @@ export const auditFile = (filePath, relativePath) => {
183
183
  return violations;
184
184
  };
185
185
 
186
+ const IGNORED_DIRS = new Set(['node_modules', 'dist', 'build', 'vendor', '.git', '.next', '.turbo', '.output', 'out']);
187
+
188
+ const isSourceFile = (name) => {
189
+ return (
190
+ /\.(tsx|ts|jsx|js|vue)$/.test(name) &&
191
+ !name.endsWith('.d.ts') &&
192
+ !name.includes('.test.') &&
193
+ !name.includes('.spec.') &&
194
+ !name.includes('.min.')
195
+ );
196
+ };
197
+
186
198
  export const scanDirectory = (targetDir, baseDir) => {
187
199
  let results = [];
188
200
  if (!fs.existsSync(targetDir)) return results;
@@ -193,10 +205,10 @@ export const scanDirectory = (targetDir, baseDir) => {
193
205
  const relPath = path.relative(baseDir, fullPath);
194
206
 
195
207
  if (entry.isDirectory()) {
196
- if (!['node_modules', 'dist', '.git', '.next', 'out'].includes(entry.name)) {
208
+ if (!IGNORED_DIRS.has(entry.name)) {
197
209
  results = results.concat(scanDirectory(fullPath, baseDir));
198
210
  }
199
- } else if (/\.(tsx|ts|jsx|js|vue)$/.test(entry.name) && !entry.name.endsWith('.d.ts') && !entry.name.includes('.test.')) {
211
+ } else if (isSourceFile(entry.name)) {
200
212
  results = results.concat(auditFile(fullPath, relPath));
201
213
  }
202
214
  }
@@ -211,10 +223,10 @@ const countTotalScannedFiles = (targetDir) => {
211
223
  for (const entry of entries) {
212
224
  const fullPath = path.join(targetDir, entry.name);
213
225
  if (entry.isDirectory()) {
214
- if (!['node_modules', 'dist', '.git', '.next', 'out'].includes(entry.name)) {
226
+ if (!IGNORED_DIRS.has(entry.name)) {
215
227
  count += countTotalScannedFiles(fullPath);
216
228
  }
217
- } else if (/\.(tsx|ts|jsx|js|vue)$/.test(entry.name) && !entry.name.endsWith('.d.ts') && !entry.name.includes('.test.')) {
229
+ } else if (isSourceFile(entry.name)) {
218
230
  count += 1;
219
231
  }
220
232
  }
package/cli/index.js CHANGED
@@ -1,59 +1,65 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import os from 'node:os';
6
- import readline from 'node:readline';
7
- import { spawnSync } from 'node:child_process';
8
- import { runAudit as executeAstAudit, auditFile } from './audit.js';
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import os from "node:os";
6
+ import readline from "node:readline";
7
+ import { spawnSync } from "node:child_process";
8
+ import { runAudit as executeAstAudit, auditFile } from "./audit.js";
9
9
 
10
10
  const rawArgs = process.argv.slice(2);
11
- const invokedBin = path.basename(process.argv[1] || '');
12
- const isCreateInvoked = invokedBin.includes('create-chemx') || (rawArgs[0] && rawArgs[0] === 'create');
11
+ const invokedBin = path.basename(process.argv[1] || "");
12
+ const isCreateInvoked =
13
+ invokedBin.includes("create-chemx") || (rawArgs[0] && rawArgs[0] === "create");
13
14
 
14
- const CONFIG_DIR = path.join(os.homedir(), '.chemical-x');
15
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
16
- const DEVICE_FILE = path.join(CONFIG_DIR, 'device_id');
15
+ const CONFIG_DIR = path.join(os.homedir(), ".chemical-x");
16
+ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
17
+ const DEVICE_FILE = path.join(CONFIG_DIR, "device_id");
17
18
 
18
- const API_BASE = process.env.CHEMICAL_X_API_URL || 'https://chemicalx.xophz.com';
19
- const URL_STANDARD = 'https://mycompassconsulting.com/buy/chemical-x/standard';
20
- const URL_MASTER = 'https://mycompassconsulting.com/buy/chemical-x/master';
19
+ const API_BASE = process.env.CHEMICAL_X_API_URL || "https://chemicalx.xophz.com";
20
+ const URL_LEARN = "https://chemicalx.xophz.com";
21
+ const URL_STANDARD = "https://mycompassconsulting.com/buy/chemical-x/standard";
22
+ const URL_MASTER = "https://mycompassconsulting.com/buy/chemical-x/master";
21
23
 
22
24
  if (!fs.existsSync(CONFIG_DIR)) {
23
- try { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } catch {}
25
+ try {
26
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
27
+ } catch {}
24
28
  }
25
29
 
26
30
  const openBrowser = (url) => {
27
31
  const platform = process.platform;
28
32
  try {
29
- if (platform === 'darwin') spawnSync('open', [url], { stdio: 'ignore' });
30
- else if (platform === 'win32') spawnSync('cmd.exe', ['/c', 'start', '""', url], { stdio: 'ignore' });
31
- else spawnSync('xdg-open', [url], { stdio: 'ignore' });
33
+ if (platform === "darwin") spawnSync("open", [url], { stdio: "ignore" });
34
+ else if (platform === "win32")
35
+ spawnSync("cmd.exe", ["/c", "start", '""', url], { stdio: "ignore" });
36
+ else spawnSync("xdg-open", [url], { stdio: "ignore" });
32
37
  } catch {}
33
38
  };
34
39
 
35
40
  const hasGum = () => {
36
41
  try {
37
- return spawnSync('which', ['gum'], { stdio: 'ignore' }).status === 0;
42
+ return spawnSync("which", ["gum"], { stdio: "ignore" }).status === 0;
38
43
  } catch {
39
44
  return false;
40
45
  }
41
46
  };
42
47
 
43
- const gumChoose = (options, header = '') => {
44
- const args = ['choose', ...options, '--cursor.foreground=81'];
48
+ const gumChoose = (options, header = "") => {
49
+ const args = ["choose"];
45
50
  if (header) {
46
- args.unshift(`--header=${header}`, '--header.foreground=81');
51
+ args.push(`--header=${header}`, "--header.foreground=81");
47
52
  }
48
- const res = spawnSync('gum', args, { encoding: 'utf-8', stdio: ['inherit', 'pipe', 'inherit'] });
49
- return (res.stdout || '').trim();
53
+ args.push("--cursor.foreground=81", ...options);
54
+ const res = spawnSync("gum", args, { encoding: "utf-8", stdio: ["inherit", "pipe", "inherit"] });
55
+ return (res.stdout || "").trim();
50
56
  };
51
57
 
52
- const gumInput = (promptText, placeholder = '', isPassword = false) => {
53
- const args = ['input', `--prompt=${promptText} `, `--placeholder=${placeholder}`];
54
- if (isPassword) args.push('--password');
55
- const res = spawnSync('gum', args, { encoding: 'utf-8', stdio: ['inherit', 'pipe', 'inherit'] });
56
- return (res.stdout || '').trim();
58
+ const gumInput = (promptText, placeholder = "", isPassword = false) => {
59
+ const args = ["input", `--prompt=${promptText} `, `--placeholder=${placeholder}`];
60
+ if (isPassword) args.push("--password");
61
+ const res = spawnSync("gum", args, { encoding: "utf-8", stdio: ["inherit", "pipe", "inherit"] });
62
+ return (res.stdout || "").trim();
57
63
  };
58
64
 
59
65
  const promptQuestion = (query) => {
@@ -69,19 +75,21 @@ const promptQuestion = (query) => {
69
75
  const getOrCreateDeviceId = () => {
70
76
  if (fs.existsSync(DEVICE_FILE)) {
71
77
  try {
72
- const id = fs.readFileSync(DEVICE_FILE, 'utf-8').trim();
78
+ const id = fs.readFileSync(DEVICE_FILE, "utf-8").trim();
73
79
  if (id) return id;
74
80
  } catch {}
75
81
  }
76
82
  const newId = `cli_${Math.random().toString(36).substring(2, 12)}_${Date.now()}`;
77
- try { fs.writeFileSync(DEVICE_FILE, newId, 'utf-8'); } catch {}
83
+ try {
84
+ fs.writeFileSync(DEVICE_FILE, newId, "utf-8");
85
+ } catch {}
78
86
  return newId;
79
87
  };
80
88
 
81
89
  const getCachedLicenseKey = () => {
82
90
  if (fs.existsSync(CONFIG_FILE)) {
83
91
  try {
84
- const data = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
92
+ const data = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
85
93
  return data.licenseKey || null;
86
94
  } catch {
87
95
  return null;
@@ -92,33 +100,45 @@ const getCachedLicenseKey = () => {
92
100
 
93
101
  const saveLicenseKey = (licenseKey) => {
94
102
  try {
95
- fs.writeFileSync(CONFIG_FILE, JSON.stringify({ licenseKey, updatedAt: new Date().toISOString() }, null, 2), 'utf-8');
103
+ fs.writeFileSync(
104
+ CONFIG_FILE,
105
+ JSON.stringify({ licenseKey, updatedAt: new Date().toISOString() }, null, 2),
106
+ "utf-8"
107
+ );
96
108
  } catch {}
97
109
  };
98
110
 
99
- const renderBanner = (title = 'Chemical X Protocol: Quantum Architecture') => {
111
+ const renderBanner = (title = "Chemical X Protocol: Quantum Architecture") => {
100
112
  if (hasGum()) {
101
- spawnSync('gum', [
102
- 'style',
103
- '--border=normal',
104
- '--margin=1',
105
- '--padding=1 2',
106
- '--border-foreground=45',
107
- '--foreground=81',
108
- '--bold',
109
- ` ${title}\n Zero-Context-Rot Scaffolding & Engineering Directives`
110
- ], { stdio: 'inherit' });
113
+ spawnSync(
114
+ "gum",
115
+ [
116
+ "style",
117
+ "--border=normal",
118
+ "--margin=1",
119
+ "--padding=1 2",
120
+ "--border-foreground=45",
121
+ "--foreground=81",
122
+ "--bold",
123
+ ` ${title}\n Zero-Context-Rot Scaffolding & Engineering Directives`
124
+ ],
125
+ { stdio: "inherit" }
126
+ );
111
127
  } else {
112
- process.stdout.write('\n\x1b[38;2;98;201;255m=====================================================\x1b[0m\n');
128
+ process.stdout.write(
129
+ "\n\x1b[38;2;98;201;255m=====================================================\x1b[0m\n"
130
+ );
113
131
  process.stdout.write(`\x1b[1m\x1b[38;2;98;201;255m ${title}\x1b[0m\n`);
114
- process.stdout.write(' Zero-Context-Rot Scaffolding & Engineering Directives\n');
115
- process.stdout.write('\x1b[38;2;98;201;255m=====================================================\x1b[0m\n\n');
132
+ process.stdout.write(" Zero-Context-Rot Scaffolding & Engineering Directives\n");
133
+ process.stdout.write(
134
+ "\x1b[38;2;98;201;255m=====================================================\x1b[0m\n\n"
135
+ );
116
136
  }
117
137
  };
118
138
 
119
139
  const obtainLicenseKey = async () => {
120
140
  let cached = getCachedLicenseKey();
121
- const cliFlagIdx = rawArgs.indexOf('--license');
141
+ const cliFlagIdx = rawArgs.indexOf("--license");
122
142
  if (cliFlagIdx !== -1 && rawArgs[cliFlagIdx + 1]) {
123
143
  cached = rawArgs[cliFlagIdx + 1].trim();
124
144
  }
@@ -130,77 +150,96 @@ const obtainLicenseKey = async () => {
130
150
  const useGum = hasGum();
131
151
 
132
152
  if (useGum) {
133
- const choice = gumChoose([
134
- '1. Buy Standard Edition ($49) -> Launch Checkout',
135
- '2. Buy Master Bundle ($99) -> Launch Checkout',
136
- '3. Enter License Key (CX-XXXX-XXXX-XXXX)',
137
- '4. Run Free Public Audit (npx chemx audit)',
138
- '5. Exit'
139
- ], 'Chemical X Scaffolding Requires a Paid License:');
140
-
141
- if (choice.startsWith('1.')) {
142
- process.stdout.write(`\x1b[36mOpening checkout in default browser:\x1b[0m ${URL_STANDARD}\n`);
153
+ const choice = gumChoose(
154
+ [
155
+ "1. Visit chemicalx.xophz.com to learn more",
156
+ "2. Buy eBook w/ AGENTS.md Rule Book ($27) -> Launch Checkout",
157
+ "3. Buy Master Bundle ($47) -> Launch Checkout",
158
+ "4. Enter License Key (CX-XXXX-XXXX-XXXX)",
159
+ "5. Run Free Public Audit (npx chemx audit)",
160
+ "6. Exit"
161
+ ],
162
+ "Chemical X Scaffolding Requires a Paid License:"
163
+ );
164
+
165
+ if (choice.startsWith("1.")) {
166
+ process.stdout.write(`\x1b[36mOpening Chemical X Portal in default browser:\x1b[0m ${URL_LEARN}\n`);
167
+ openBrowser(URL_LEARN);
168
+ process.stdout.write("\nOnce completed, paste your Sponsor / VIP License Key below.\n");
169
+ return gumInput("License Key (CX-XXXX-XXXX-XXXX):", "CX-XXXX-XXXX-XXXX");
170
+ }
171
+
172
+ if (choice.startsWith("2.")) {
173
+ process.stdout.write(`\x1b[36mOpening Standard Vault checkout in default browser:\x1b[0m ${URL_STANDARD}\n`);
143
174
  openBrowser(URL_STANDARD);
144
- process.stdout.write('\nOnce completed, paste your Sponsor / VIP License Key below.\n');
145
- return gumInput('License Key (CX-XXXX-XXXX-XXXX):', 'CX-XXXX-XXXX-XXXX');
175
+ process.stdout.write("\nOnce completed, paste your Sponsor / VIP License Key below.\n");
176
+ return gumInput("License Key (CX-XXXX-XXXX-XXXX):", "CX-XXXX-XXXX-XXXX");
146
177
  }
147
178
 
148
- if (choice.startsWith('2.')) {
149
- process.stdout.write(`\x1b[36mOpening checkout in default browser:\x1b[0m ${URL_MASTER}\n`);
179
+ if (choice.startsWith("3.")) {
180
+ process.stdout.write(`\x1b[36mOpening Master Bundle checkout in default browser:\x1b[0m ${URL_MASTER}\n`);
150
181
  openBrowser(URL_MASTER);
151
- process.stdout.write('\nOnce completed, paste your Sponsor / VIP License Key below.\n');
152
- return gumInput('License Key (CX-XXXX-XXXX-XXXX):', 'CX-XXXX-XXXX-XXXX');
182
+ process.stdout.write("\nOnce completed, paste your Sponsor / VIP License Key below.\n");
183
+ return gumInput("License Key (CX-XXXX-XXXX-XXXX):", "CX-XXXX-XXXX-XXXX");
153
184
  }
154
185
 
155
- if (choice.startsWith('3.')) {
156
- return gumInput('License Key (CX-XXXX-XXXX-XXXX):', 'CX-XXXX-XXXX-XXXX');
186
+ if (choice.startsWith("4.")) {
187
+ return gumInput("License Key (CX-XXXX-XXXX-XXXX):", "CX-XXXX-XXXX-XXXX");
157
188
  }
158
189
 
159
- if (choice.startsWith('4.')) {
190
+ if (choice.startsWith("5.")) {
160
191
  await runAudit(null, true);
161
192
  }
162
193
 
163
- if (choice.startsWith('5.') || !choice) {
194
+ if (choice.startsWith("6.") || !choice) {
164
195
  process.exit(0);
165
196
  }
166
197
 
167
- return gumInput('License Key (CX-XXXX-XXXX-XXXX):', 'CX-XXXX-XXXX-XXXX');
198
+ return gumInput("License Key (CX-XXXX-XXXX-XXXX):", "CX-XXXX-XXXX-XXXX");
168
199
  }
169
200
 
170
- process.stdout.write('\x1b[1mChemical X Scaffolding Requires a Paid License:\x1b[0m\n');
171
- process.stdout.write(' [1] Buy Standard Edition ($49) - Opens browser\n');
172
- process.stdout.write(' [2] Buy Master Bundle ($99) - Opens browser\n');
173
- process.stdout.write(' [3] Enter License Key\n');
174
- process.stdout.write(' [4] Run Free Public Audit (npx chemx audit)\n');
175
- process.stdout.write(' [5] Exit\n\n');
176
-
177
- const selection = await promptQuestion('Select option [1-5]: ');
201
+ process.stdout.write("\x1b[1mChemical X Scaffolding Requires a Paid License:\x1b[0m\n");
202
+ process.stdout.write(" [1] Visit chemicalx.xophz.com to learn more\n");
203
+ process.stdout.write(" [2] Buy eBook w/ AGENTS.md Rule Book ($27) - Opens browser\n");
204
+ process.stdout.write(" [3] Buy Master Bundle ($47) - Opens browser\n");
205
+ process.stdout.write(" [4] Enter License Key\n");
206
+ process.stdout.write(" [5] Run Free Public Audit (npx chemx audit)\n");
207
+ process.stdout.write(" [6] Exit\n\n");
208
+
209
+ const selection = await promptQuestion("Select option [1-6] (default: 1): ");
210
+ const effectiveChoice = selection.trim() || "1";
211
+
212
+ if (effectiveChoice === "1") {
213
+ process.stdout.write(`Opening: ${URL_LEARN}\n`);
214
+ openBrowser(URL_LEARN);
215
+ return promptQuestion("Enter License Key after review (or press Enter to exit): ");
216
+ }
178
217
 
179
- if (selection === '1') {
218
+ if (effectiveChoice === "2") {
180
219
  process.stdout.write(`Opening: ${URL_STANDARD}\n`);
181
220
  openBrowser(URL_STANDARD);
182
- return promptQuestion('Enter License Key after purchase: ');
221
+ return promptQuestion("Enter License Key after purchase: ");
183
222
  }
184
223
 
185
- if (selection === '2') {
224
+ if (effectiveChoice === "3") {
186
225
  process.stdout.write(`Opening: ${URL_MASTER}\n`);
187
226
  openBrowser(URL_MASTER);
188
- return promptQuestion('Enter License Key after purchase: ');
227
+ return promptQuestion("Enter License Key after purchase: ");
189
228
  }
190
229
 
191
- if (selection === '3') {
192
- return promptQuestion('Enter License Key (CX-XXXX-XXXX-XXXX): ');
230
+ if (effectiveChoice === "4") {
231
+ return promptQuestion("Enter License Key (CX-XXXX-XXXX-XXXX): ");
193
232
  }
194
233
 
195
- if (selection === '4') {
234
+ if (effectiveChoice === "5") {
196
235
  await runAudit(null, true);
197
236
  }
198
237
 
199
- if (selection === '5') {
238
+ if (effectiveChoice === "6") {
200
239
  process.exit(0);
201
240
  }
202
241
 
203
- return promptQuestion('Enter Chemical X Sponsor License Key (CX-XXXX-XXXX-XXXX): ');
242
+ return promptQuestion("Enter Chemical X Sponsor License Key (CX-XXXX-XXXX-XXXX): ");
204
243
  };
205
244
 
206
245
  const fetchStarterKitFiles = async (licenseKey) => {
@@ -211,51 +250,61 @@ const fetchStarterKitFiles = async (licenseKey) => {
211
250
 
212
251
  try {
213
252
  const res = await fetch(`${API_BASE}/api/starter-kit/download`, {
214
- method: 'POST',
215
- headers: { 'Content-Type': 'application/json' },
253
+ method: "POST",
254
+ headers: { "Content-Type": "application/json" },
216
255
  body: JSON.stringify({ licenseKey: normalizedKey, deviceId })
217
256
  });
218
257
 
219
258
  const responseData = await res.json();
220
259
 
221
260
  if (!res.ok || !responseData.valid) {
222
- process.stderr.write(`\x1b[31m✕ License Verification Failed: ${responseData.error || 'Invalid key.'}\x1b[0m\n`);
261
+ process.stderr.write(
262
+ `\x1b[31m✕ License Verification Failed: ${responseData.error || "Invalid key."}\x1b[0m\n`
263
+ );
223
264
  process.stderr.write(`Purchase key at: ${URL_STANDARD}\n\n`);
224
265
  process.exit(1);
225
266
  }
226
267
 
227
268
  saveLicenseKey(normalizedKey);
228
- process.stdout.write(`\x1b[32m✔ Verified License for @${responseData.githubUser || 'sponsor'}\x1b[0m\n\n`);
269
+ process.stdout.write(
270
+ `\x1b[32m✔ Verified License for @${responseData.githubUser || "sponsor"}\x1b[0m\n\n`
271
+ );
229
272
  return responseData.files || {};
230
273
  } catch (err) {
231
- process.stderr.write(`\x1b[31m✕ Network Error: Failed to reach edge server (${err.message}).\x1b[0m\n`);
274
+ process.stderr.write(
275
+ `\x1b[31m✕ Network Error: Failed to reach edge server (${err.message}).\x1b[0m\n`
276
+ );
232
277
  process.exit(1);
233
278
  }
234
279
  };
235
280
 
236
281
  const runScaffold = async (projectName) => {
237
- renderBanner('Chemical X: Quantum Scaffolder (npm create chemx)');
282
+ renderBanner("Chemical X: Quantum Scaffolder (npm create chemx)");
238
283
 
239
284
  const licenseKey = await obtainLicenseKey();
240
285
  if (!licenseKey) {
241
- process.stderr.write('\x1b[31m✕ Valid license key is required to scaffold blueprints.\x1b[0m\n');
286
+ process.stderr.write(
287
+ "\x1b[31m✕ Valid license key is required to scaffold blueprints.\x1b[0m\n"
288
+ );
242
289
  process.exit(1);
243
290
  }
244
291
 
245
292
  let targetName = projectName;
246
293
  if (!targetName) {
247
294
  if (hasGum()) {
248
- targetName = gumInput('Project directory name:', 'my-quantum-app');
295
+ targetName = gumInput("Project directory name:", "my-quantum-app");
249
296
  } else {
250
- targetName = await promptQuestion('Project directory name [my-quantum-app]: ');
297
+ targetName = await promptQuestion("Project directory name [my-quantum-app]: ");
251
298
  }
252
299
  }
253
300
 
254
- const finalDirName = targetName.trim() || 'my-quantum-app';
301
+ const finalDirName = targetName.trim() || "my-quantum-app";
255
302
  const targetDir = path.resolve(process.cwd(), finalDirName);
256
303
 
257
304
  if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
258
- process.stderr.write(`\x1b[31m✕ Error: Directory '${finalDirName}' already exists and is not empty.\x1b[0m\n`);
305
+ process.stderr.write(
306
+ `\x1b[31m✕ Error: Directory '${finalDirName}' already exists and is not empty.\x1b[0m\n`
307
+ );
259
308
  process.exit(1);
260
309
  }
261
310
 
@@ -270,32 +319,34 @@ const runScaffold = async (projectName) => {
270
319
  if (!fs.existsSync(dirName)) {
271
320
  fs.mkdirSync(dirName, { recursive: true });
272
321
  }
273
- fs.writeFileSync(fullPath, content, 'utf-8');
322
+ fs.writeFileSync(fullPath, content, "utf-8");
274
323
  process.stdout.write(` \x1b[32m✔\x1b[0m ${relPath}\n`);
275
324
  }
276
325
 
277
- const cursorRulesPath = path.join(targetDir, '.cursorrules');
326
+ const cursorRulesPath = path.join(targetDir, ".cursorrules");
278
327
  if (!fs.existsSync(cursorRulesPath)) {
279
328
  const rules = `# Chemical X Quantum Architecture Directives\nStrictly follow AGENTS.md rules. Never exceed 500 lines per file. All molecule capsules must stay under 100 lines.\n`;
280
- fs.writeFileSync(cursorRulesPath, rules, 'utf-8');
329
+ fs.writeFileSync(cursorRulesPath, rules, "utf-8");
281
330
  process.stdout.write(` \x1b[32m✔\x1b[0m .cursorrules\n`);
282
331
  }
283
332
 
284
- process.stdout.write(`\n\x1b[1m\x1b[32m✔ Quantum project created successfully at ${finalDirName}!\x1b[0m\n\n`);
285
- process.stdout.write('Next Steps:\n');
333
+ process.stdout.write(
334
+ `\n\x1b[1m\x1b[32m✔ Quantum project created successfully at ${finalDirName}!\x1b[0m\n\n`
335
+ );
336
+ process.stdout.write("Next Steps:\n");
286
337
  process.stdout.write(` 1. cd ${finalDirName}\n`);
287
- process.stdout.write(' 2. Review AGENTS.md for line budgets and architecture standards\n');
288
- process.stdout.write(' 3. Run npx chemx generate m-<feature> to create capsules\n');
289
- process.stdout.write(' 4. Run npx chemx audit to scan for line budget compliance\n\n');
338
+ process.stdout.write(" 2. Review AGENTS.md for line budgets and architecture standards\n");
339
+ process.stdout.write(" 3. Run npx chemx generate m-<feature> to create capsules\n");
340
+ process.stdout.write(" 4. Run npx chemx audit to scan for line budget compliance\n\n");
290
341
  };
291
342
 
292
- const runInit = async (targetSubDir = 'src/chemical-x') => {
293
- renderBanner('Chemical X: In-Repo Capsule Drop-in');
343
+ const runInit = async (targetSubDir = "src/chemical-x") => {
344
+ renderBanner("Chemical X: In-Repo Capsule Drop-in");
294
345
 
295
346
  const targetDir = path.resolve(process.cwd(), targetSubDir);
296
347
  const licenseKey = await obtainLicenseKey();
297
348
  if (!licenseKey) {
298
- process.stderr.write('\x1b[31m✕ Valid license key is required.\x1b[0m\n');
349
+ process.stderr.write("\x1b[31m✕ Valid license key is required.\x1b[0m\n");
299
350
  process.exit(1);
300
351
  }
301
352
 
@@ -310,16 +361,18 @@ const runInit = async (targetSubDir = 'src/chemical-x') => {
310
361
  if (!fs.existsSync(dirName)) {
311
362
  fs.mkdirSync(dirName, { recursive: true });
312
363
  }
313
- fs.writeFileSync(fullPath, content, 'utf-8');
364
+ fs.writeFileSync(fullPath, content, "utf-8");
314
365
  process.stdout.write(` \x1b[32m✔\x1b[0m ${relPath}\n`);
315
366
  count++;
316
367
  }
317
368
 
318
- process.stdout.write(`\n\x1b[1m\x1b[32m✔ Successfully installed ${count} Chemical X assets into ${targetSubDir}!\x1b[0m\n\n`);
369
+ process.stdout.write(
370
+ `\n\x1b[1m\x1b[32m✔ Successfully installed ${count} Chemical X assets into ${targetSubDir}!\x1b[0m\n\n`
371
+ );
319
372
  };
320
373
 
321
374
  const runGenerateCapsule = (capsuleName) => {
322
- const normalizedName = capsuleName.startsWith('m-') ? capsuleName : `m-${capsuleName}`;
375
+ const normalizedName = capsuleName.startsWith("m-") ? capsuleName : `m-${capsuleName}`;
323
376
  const targetDir = path.resolve(process.cwd(), normalizedName);
324
377
 
325
378
  if (fs.existsSync(targetDir)) {
@@ -330,9 +383,9 @@ const runGenerateCapsule = (capsuleName) => {
330
383
  fs.mkdirSync(targetDir, { recursive: true });
331
384
 
332
385
  const pascalName = normalizedName
333
- .split('-')
386
+ .split("-")
334
387
  .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
335
- .join('');
388
+ .join("");
336
389
 
337
390
  const componentCode = `import React from 'react';
338
391
  import type { ${pascalName}Props } from './types';
@@ -357,37 +410,46 @@ export default ${pascalName};
357
410
  export type { ${pascalName}Props } from './types';
358
411
  `;
359
412
 
360
- fs.writeFileSync(path.join(targetDir, `${normalizedName}.tsx`), componentCode, 'utf-8');
361
- fs.writeFileSync(path.join(targetDir, 'types.d.ts'), typesCode, 'utf-8');
362
- fs.writeFileSync(path.join(targetDir, 'index.ts'), indexCode, 'utf-8');
413
+ fs.writeFileSync(path.join(targetDir, `${normalizedName}.tsx`), componentCode, "utf-8");
414
+ fs.writeFileSync(path.join(targetDir, "types.d.ts"), typesCode, "utf-8");
415
+ fs.writeFileSync(path.join(targetDir, "index.ts"), indexCode, "utf-8");
363
416
 
364
- process.stdout.write(`\x1b[32m✔ Successfully generated crystalline capsule:\x1b[0m ${normalizedName}/\n`);
417
+ process.stdout.write(
418
+ `\x1b[32m✔ Successfully generated crystalline capsule:\x1b[0m ${normalizedName}/\n`
419
+ );
365
420
  process.stdout.write(` - ${normalizedName}/${normalizedName}.tsx (< 50 lines)\n`);
366
421
  process.stdout.write(` - ${normalizedName}/types.d.ts\n`);
367
422
  process.stdout.write(` - ${normalizedName}/index.ts\n\n`);
368
423
  };
369
424
 
370
425
  export const runAudit = async (customDir = null, isCli = false) => {
371
- const isJson = rawArgs.includes('--json');
372
- const dirFlag = rawArgs.find((arg) => arg.startsWith('--dir='));
373
- const targetDir = customDir || (dirFlag ? dirFlag.split('=')[1] : (fs.existsSync('src') ? 'src' : '.'));
426
+ const isJson = rawArgs.includes("--json");
427
+ const dirFlag = rawArgs.find((arg) => arg.startsWith("--dir="));
428
+ const targetDir =
429
+ customDir || (dirFlag ? dirFlag.split("=")[1] : fs.existsSync("src") ? "src" : ".");
374
430
 
375
431
  const report = executeAstAudit(targetDir);
376
432
 
377
433
  if (isJson) {
378
- process.stdout.write(JSON.stringify(report, null, 2) + '\n');
434
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
379
435
  if (isCli) process.exit(report.violations.length > 0 ? 1 : 0);
380
436
  return report;
381
437
  }
382
438
 
383
- process.stdout.write('\n\x1b[38;2;98;201;255m[Chemical X Context Hazard Audit]\x1b[0m Scanning codebase for AST architectural hazards...\n');
439
+ process.stdout.write(
440
+ "\n\x1b[38;2;98;201;255m[Chemical X Context Hazard Audit]\x1b[0m Scanning codebase for AST architectural hazards...\n"
441
+ );
384
442
  process.stdout.write(`Target Directory: ${targetDir}\n`);
385
443
  process.stdout.write(`Scanned ${report.scannedFiles} source files.\n\n`);
386
444
 
387
445
  if (report.violations.length === 0) {
388
- process.stdout.write('\x1b[1m\x1b[32m✔ 100% Quantum Compliant: Zero context hazard violations detected across all line budgets, hooks, and AST rules.\x1b[0m\n\n');
446
+ process.stdout.write(
447
+ "\x1b[1m\x1b[32m✔ 100% Quantum Compliant: Zero context hazard violations detected across all line budgets, hooks, and AST rules.\x1b[0m\n\n"
448
+ );
389
449
  } else {
390
- process.stdout.write(`\x1b[31m✕ FAILED: ${report.totalViolations} context hazard violations detected:\x1b[0m\n\n`);
450
+ process.stdout.write(
451
+ `\x1b[31m✕ FAILED: ${report.totalViolations} context hazard violations detected:\x1b[0m\n\n`
452
+ );
391
453
  for (const v of report.violations) {
392
454
  process.stdout.write(` \x1b[31m[${v.rule}]\x1b[0m \x1b[33m${v.filePath}:${v.line}\x1b[0m\n`);
393
455
  process.stdout.write(` Hazard: ${v.hazard}\n`);
@@ -398,56 +460,95 @@ export const runAudit = async (customDir = null, isCli = false) => {
398
460
  if (isCli) {
399
461
  while (true) {
400
462
  if (hasGum()) {
401
- spawnSync('gum', [
402
- 'style',
403
- '--border=rounded',
404
- '--border-foreground=81',
405
- '--padding=0 1',
406
- '--bold',
407
- 'Eliminate AI Context Rot with Chemical X Architecture'
408
- ], { stdio: 'inherit' });
409
-
410
- const choice = gumChoose([
411
- '1. Buy Standard Edition ($49) -> Launch Checkout',
412
- '2. Buy Master Bundle ($99) -> Launch Checkout',
413
- '3. Enter License Key to Scaffold (Paid License Holders)',
414
- '4. Exit'
415
- ], 'Select a CTA action:');
416
-
417
- if (choice.startsWith('1.')) {
418
- process.stdout.write(`\n\x1b[36mOpening Standard Edition checkout in browser:\x1b[0m ${URL_STANDARD}\n\n`);
463
+ spawnSync(
464
+ "gum",
465
+ [
466
+ "style",
467
+ "--border=rounded",
468
+ "--border-foreground=81",
469
+ "--padding=0 1",
470
+ "--bold",
471
+ "Chemical X: The Secret Sauce to Vibe Coding\nStop letting AI agents scour 2,000-line monoliths and hallucinate.\n25+ Years XP | Codified by Principal Systems Architect Xopher Pollard\nTarget File Budget: Max 500 lines/file (<100 lines/molecule) | 85% Token Burn Cut"
472
+ ],
473
+ { stdio: "inherit" }
474
+ );
475
+
476
+ const choice = gumChoose(
477
+ [
478
+ "1. Visit chemicalx.xophz.com to learn more",
479
+ "2. Buy eBook w/ AGENTS.md Rule Book ($27) -> Launch Checkout",
480
+ "3. Buy Master Bundle ($47) -> Launch Checkout",
481
+ "4. Enter License Key to Scaffold (Paid License Holders)",
482
+ "5. Exit"
483
+ ],
484
+ "Unlock the Awesome Secret Sauce of Chemical X:"
485
+ );
486
+
487
+ if (choice.startsWith("1.")) {
488
+ process.stdout.write(
489
+ `\n\x1b[36mOpening Chemical X Portal in browser:\x1b[0m ${URL_LEARN}\n\n`
490
+ );
491
+ openBrowser(URL_LEARN);
492
+ continue;
493
+ }
494
+ if (choice.startsWith("2.")) {
495
+ process.stdout.write(
496
+ `\n\x1b[36mOpening Standard Vault checkout (eBook + AGENTS.md):\x1b[0m ${URL_STANDARD}\n\n`
497
+ );
419
498
  openBrowser(URL_STANDARD);
420
499
  continue;
421
500
  }
422
- if (choice.startsWith('2.')) {
423
- process.stdout.write(`\n\x1b[36mOpening Master Bundle checkout in browser:\x1b[0m ${URL_MASTER}\n\n`);
501
+ if (choice.startsWith("3.")) {
502
+ process.stdout.write(
503
+ `\n\x1b[36mOpening Master Bundle checkout (Repo + Hooks + Prompts):\x1b[0m ${URL_MASTER}\n\n`
504
+ );
424
505
  openBrowser(URL_MASTER);
425
506
  continue;
426
507
  }
427
- if (choice.startsWith('3.')) {
508
+ if (choice.startsWith("4.")) {
428
509
  await runScaffold();
429
510
  break;
430
511
  }
431
512
  break;
432
513
  } else {
433
- process.stdout.write('\x1b[1m\x1b[38;2;98;201;255mEliminate AI Context Rot with Chemical X Architecture:\x1b[0m\n');
434
- process.stdout.write(` [1] Buy Standard Edition ($49) - ${URL_STANDARD}\n`);
435
- process.stdout.write(` [2] Buy Master Bundle ($99) - ${URL_MASTER}\n`);
436
- process.stdout.write(' [3] Enter License Key to Scaffold (Paid License Holders)\n');
437
- process.stdout.write(' [4] Exit\n\n');
438
-
439
- const selection = await promptQuestion('Select option [1-4]: ');
440
- if (selection === '1') {
514
+ process.stdout.write(
515
+ "\n\x1b[1m\x1b[38;2;98;201;255mChemical X: The Secret Sauce to Vibe Coding\x1b[0m\n"
516
+ );
517
+ process.stdout.write(
518
+ "Stop letting AI agents scour 2,000-line monoliths and hallucinate breaking changes.\n" +
519
+ "25+ Years XP | Codified by Principal Systems Architect Xopher Pollard\n" +
520
+ "Target File Budget: Max 500 lines/file (<100 lines per molecule capsule).\n\n"
521
+ );
522
+ process.stdout.write(` [1] Visit chemicalx.xophz.com to learn more\n`);
523
+ process.stdout.write(
524
+ ` [2] Buy eBook w/ AGENTS.md Rule Book ($27) - ${URL_STANDARD}\n` +
525
+ ` Includes: Kindle/Print PDF eBook, 7 Quantum Chapters, Universal AGENTS.md & .cursorrules\n`
526
+ );
527
+ process.stdout.write(
528
+ ` [3] Buy Master Bundle ($47) - ${URL_MASTER}\n` +
529
+ ` Includes: Private Starter-Kit Repo, Pre-Commit Line Budget Hooks, 10x Prompts, VIP Discord\n`
530
+ );
531
+ process.stdout.write(" [4] Enter License Key to Scaffold (Paid License Holders)\n");
532
+ process.stdout.write(" [5] Exit\n\n");
533
+
534
+ const selection = await promptQuestion("Select option [1-5] (default: 1): ");
535
+ const effectiveSelection = selection.trim() || "1";
536
+ if (effectiveSelection === "1") {
537
+ process.stdout.write(`\nOpening: ${URL_LEARN}\n\n`);
538
+ openBrowser(URL_LEARN);
539
+ continue;
540
+ }
541
+ if (effectiveSelection === "2") {
441
542
  process.stdout.write(`\nOpening: ${URL_STANDARD}\n\n`);
442
543
  openBrowser(URL_STANDARD);
443
544
  continue;
444
545
  }
445
- if (selection === '2') {
546
+ if (effectiveSelection === "3") {
446
547
  process.stdout.write(`\nOpening: ${URL_MASTER}\n\n`);
447
548
  openBrowser(URL_MASTER);
448
549
  continue;
449
550
  }
450
- if (selection === '3') {
551
+ if (effectiveSelection === "4") {
451
552
  await runScaffold();
452
553
  break;
453
554
  }
@@ -463,50 +564,60 @@ export { auditFile };
463
564
 
464
565
  const printHelp = () => {
465
566
  renderBanner();
466
- process.stdout.write('\x1b[1mAvailable Commands:\x1b[0m\n');
467
- process.stdout.write(' \x1b[36mnpm create chemx [dir]\x1b[0m [PAID] Scaffold complete Quantum Architecture project\n');
468
- process.stdout.write(' \x1b[36mnpx @chemx/starter-kit init [dir]\x1b[0m [PAID] Drop blueprints & hooks into existing project\n');
469
- process.stdout.write(' \x1b[36mnpx chemx generate <m-name>\x1b[0m Generate isolated molecule capsule (< 100 lines)\n');
470
- process.stdout.write(' \x1b[36mnpx chemx audit [--json] [--dir=src]\x1b[0m[FREE] Scan codebase for AST architectural hazards\n\n');
567
+ process.stdout.write("\x1b[1mAvailable Commands:\x1b[0m\n");
568
+ process.stdout.write(
569
+ " \x1b[36mnpm create chemx [dir]\x1b[0m [PAID] Scaffold complete Quantum Architecture project\n"
570
+ );
571
+ process.stdout.write(
572
+ " \x1b[36mnpx @chemx/starter-kit init [dir]\x1b[0m [PAID] Drop blueprints & hooks into existing project\n"
573
+ );
574
+ process.stdout.write(
575
+ " \x1b[36mnpx chemx generate <m-name>\x1b[0m Generate isolated molecule capsule (< 100 lines)\n"
576
+ );
577
+ process.stdout.write(
578
+ " \x1b[36mnpx chemx audit [--json] [--dir=src]\x1b[0m[FREE] Scan codebase for AST architectural hazards\n\n"
579
+ );
471
580
  };
472
581
 
473
582
  const main = async () => {
474
583
  const firstArg = rawArgs[0];
475
584
 
476
585
  if (isCreateInvoked) {
477
- const dirArg = firstArg === 'create' ? rawArgs[1] : firstArg;
586
+ const dirArg = firstArg === "create" ? rawArgs[1] : firstArg;
478
587
  await runScaffold(dirArg);
479
588
  return;
480
589
  }
481
590
 
482
591
  switch (firstArg) {
483
- case 'audit':
592
+ case "audit":
484
593
  await runAudit(null, true);
485
594
  break;
486
- case 'init':
487
- await runInit(rawArgs[1] || 'src/chemical-x');
595
+ case "init":
596
+ await runInit(rawArgs[1] || "src/chemical-x");
488
597
  break;
489
- case 'create':
598
+ case "create":
490
599
  await runScaffold(rawArgs[1]);
491
600
  break;
492
- case 'generate':
493
- case 'capsule':
494
- case 'add':
601
+ case "generate":
602
+ case "capsule":
603
+ case "add":
495
604
  if (!rawArgs[1]) {
496
- process.stderr.write('Usage: npx chemx generate <capsule-name>\nExample: npx chemx generate m-user-avatar\n');
605
+ process.stderr.write(
606
+ "Usage: npx chemx generate <capsule-name>\nExample: npx chemx generate m-user-avatar\n"
607
+ );
497
608
  process.exit(1);
498
609
  }
499
610
  runGenerateCapsule(rawArgs[1]);
500
611
  break;
501
- case 'help':
502
- case '--help':
503
- case '-h':
612
+ case "help":
613
+ case "--help":
614
+ case "-h":
504
615
  printHelp();
505
616
  break;
506
617
  default:
507
- if (firstArg && firstArg.startsWith('m-')) {
618
+ if (firstArg && firstArg.startsWith("m-")) {
508
619
  runGenerateCapsule(firstArg);
509
- } else if (firstArg && !firstArg.startsWith('-')) {
620
+ } else if (firstArg && !firstArg.startsWith("-")) {
510
621
  await runScaffold(firstArg);
511
622
  } else {
512
623
  printHelp();
@@ -519,4 +630,3 @@ main().catch((err) => {
519
630
  process.stderr.write(`\x1b[31m✕ Unexpected Error: ${err.message}\x1b[0m\n`);
520
631
  process.exit(1);
521
632
  });
522
-
package/docs/CHANGELOG.md CHANGED
@@ -37,11 +37,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
37
37
  - Unlocked `npx chemx audit` command as 100% free, unauthenticated, and ungated public utility with conversion CTAs.
38
38
  - Added dual project scaffolder (`npm create chemx` / `create-chemx`) and in-repo capsule drop-in (`init`).
39
39
  - Gated `runScaffold` (`npm create chemx`) with upfront license validation prior to project directory name prompt.
40
- - Integrated interactive Gum CTA action buttons at the conclusion of public audit for instant checkout launch ($49 Standard / $99 Master) and key-gated scaffolding for license holders.
40
+ - Integrated interactive Gum CTA action buttons at the conclusion of public audit for default portal browsing (`chemicalx.xophz.com`), instant checkout launch ($27 eBook w/ AGENTS.md / $47 Master Bundle), and key-gated scaffolding for license holders.
41
41
 
42
42
  ### Fixed
43
43
  - Removed embedded offline blueprint fallbacks and preview bypass keys from CLI executable (`cli/index.js`).
44
44
  - Restricted npm package distribution via `files` whitelist and `.npmignore` to prevent leaking private blueprints and hooks in public tarballs.
45
45
  - Added explicit `--tag` support and automatic default fallback for prerelease/CalVer versions in multi-target publisher (`scripts/publish-both.mjs`).
46
+ - Removed unscoped `chem-x` target from publisher script due to npm registry similarity protection with `chemx`.
47
+ - Excluded 3rd-party `vendor` and `build` directories, as well as minified bundles (`*.min.*`), from the AST context hazard audit to eliminate false positives on bundled external libraries.
48
+ - Fixed argument ordering in `gumChoose` to pass `--header` and styling flags to the `choose` subcommand rather than prepending to the parent binary.
46
49
 
47
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chemx/starter-kit",
3
- "version": "26.9.9-700",
3
+ "version": "26.9.9-786",
4
4
  "description": "Chemical X Protocol: Private drop-in architecture starter kit and capsule generator",
5
5
  "type": "module",
6
6
  "bin": {