@chemx/create-chemx 26.9.16-1249 → 26.9.16-668

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.
@@ -15,10 +15,10 @@ const IGNORED_DIRS = new Set([
15
15
  const FIXABLE_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.vue', '.md', '.scss', '.css']);
16
16
 
17
17
  const RESIDUE_PATTERNS = [
18
- ['hope this', 'helps'].join(' '),
19
- ['feel free', 'to tweak'].join(' '),
20
- ['let me know', 'if you need'].join(' '),
21
- ['as an ai', 'language model'].join(' ')
18
+ 'hope this helps',
19
+ 'feel free to tweak',
20
+ 'let me know if you need',
21
+ 'as an ai language model'
22
22
  ];
23
23
 
24
24
  const RESIDUE_REGEX = new RegExp(`\\b(?:${RESIDUE_PATTERNS.join('|')})\\b`, 'i');
@@ -72,6 +72,7 @@ export const autofixContent = (content, options = {}) => {
72
72
  shouldDropLine = true;
73
73
  }
74
74
 
75
+ // 4. Typography em dash replacement
75
76
  if (!shouldDropLine && shouldFix('TYPOGRAPHY_EM_DASH') && line.includes('\u2014')) {
76
77
  line = line.replace(/\u2014/g, '-');
77
78
  fixes.push({
@@ -4,24 +4,18 @@ import os from 'node:os';
4
4
 
5
5
  const SERVER_KEY = 'chemical-x';
6
6
 
7
- const toResultSync = (operation) => {
8
- try {
9
- const value = operation();
10
- return [value, null];
11
- } catch (err) {
12
- const normalizedError = err instanceof Error ? err : new Error(String(err));
13
- return [null, normalizedError];
14
- }
15
- };
16
-
17
7
  export const mergeMcpServerConfig = (existingJsonString = '', serverDef = {}) => {
18
8
  let parsed = { mcpServers: {} };
19
9
 
20
10
  const hasExistingString = Boolean(existingJsonString && existingJsonString.trim());
21
11
  if (hasExistingString) {
22
- const [json, parseError] = toResultSync(() => JSON.parse(existingJsonString));
23
- if (!parseError && json && typeof json === 'object') {
24
- parsed = json;
12
+ try {
13
+ const json = JSON.parse(existingJsonString);
14
+ if (json && typeof json === 'object') {
15
+ parsed = json;
16
+ }
17
+ } catch {
18
+ parsed = { mcpServers: {} };
25
19
  }
26
20
  }
27
21
 
@@ -110,26 +104,22 @@ export const installProjectMcpConfig = (targetDir = '.', options = {}) => {
110
104
  // 3. Inject helper script to consumer package.json if available
111
105
  const pkgPath = path.join(resolvedTarget, 'package.json');
112
106
  if (fs.existsSync(pkgPath)) {
113
- const [pkgContent, readError] = toResultSync(() => fs.readFileSync(pkgPath, 'utf-8'));
114
- if (!readError && pkgContent) {
115
- const [pkg, parseError] = toResultSync(() => JSON.parse(pkgContent));
116
- if (!parseError && pkg && typeof pkg === 'object') {
117
- if (!pkg.scripts) pkg.scripts = {};
118
-
119
- const hasMcpScript = Boolean(pkg.scripts['chemx:mcp'] || pkg.scripts['mcp']);
120
- if (!hasMcpScript) {
121
- pkg.scripts['chemx:mcp'] = 'chemx mcp';
122
- const [, writeError] = toResultSync(() => {
123
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
124
- });
125
- if (!writeError) {
126
- results.packageJson = true;
127
- if (!isSilent) {
128
- process.stdout.write(' \x1b[32m✔\x1b[0m Added "chemx:mcp" script to package.json\n');
129
- }
130
- }
107
+ try {
108
+ const pkgContent = fs.readFileSync(pkgPath, 'utf-8');
109
+ const pkg = JSON.parse(pkgContent);
110
+ if (!pkg.scripts) pkg.scripts = {};
111
+
112
+ const hasMcpScript = Boolean(pkg.scripts['chemx:mcp'] || pkg.scripts['mcp']);
113
+ if (!hasMcpScript) {
114
+ pkg.scripts['chemx:mcp'] = 'chemx mcp';
115
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
116
+ results.packageJson = true;
117
+ if (!isSilent) {
118
+ process.stdout.write(' \x1b[32m✔\x1b[0m Added "chemx:mcp" script to package.json\n');
131
119
  }
132
120
  }
121
+ } catch {
122
+ // Ignore package.json parsing issues gracefully
133
123
  }
134
124
  }
135
125
 
package/cli/reader.js CHANGED
@@ -36,23 +36,6 @@ export const compactCode = (code) => {
36
36
  .join('\n');
37
37
  };
38
38
 
39
- const resolveDeclarationKind = (declaration) => {
40
- const initType = declaration.init?.type || 'unknown';
41
- if (initType !== 'CallExpression') {
42
- return 'const';
43
- }
44
-
45
- const calleeName = declaration.init?.callee?.name;
46
- if (calleeName === 'computed') {
47
- return 'computed';
48
- }
49
- if (calleeName === 'ref') {
50
- return 'ref';
51
- }
52
-
53
- return 'const';
54
- };
55
-
56
39
  /**
57
40
  * Extracts an AST structural outline of a file (types, exports, props, signatures).
58
41
  *
@@ -97,7 +80,10 @@ export const generateAstOutline = (code, filePath) => {
97
80
  decl.declarations.forEach((d) => {
98
81
  const name = d.id?.name;
99
82
  if (name) {
100
- const kind = resolveDeclarationKind(d);
83
+ const initType = d.init?.type || 'unknown';
84
+ const isComputed = initType === 'CallExpression' && d.init?.callee?.name === 'computed';
85
+ const isRef = initType === 'CallExpression' && d.init?.callee?.name === 'ref';
86
+ const kind = isComputed ? 'computed' : (isRef ? 'ref' : 'const');
101
87
  lines.push(`export ${kind} ${name}`);
102
88
  }
103
89
  });
package/docs/CHANGELOG.md CHANGED
@@ -4,13 +4,6 @@ All notable changes to the Chemical X Starter Kit repository will be documented
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
 
7
- ## [2026-09-16]
8
-
9
- ### Refactored
10
- - **Control Flow Ternary Decomposition (`cli/reader.js`)**: Refactored `reader.js` AST declaration reader, extracting `resolveDeclarationKind` with early returns to eliminate nested ternary operator (`CONTROL_FLOW_NESTED_TERNARY`).
11
- - **ResultTuple Error Handling (`cli/mcp/installer.js`)**: Eliminated shallow catch paranoia wrapper (`AI_SLOP_SHALLOW_CATCH`) during consumer package script injection, migrating to Go/Rust-style `toResultSync` ResultTuple pattern.
12
- - **Conversational Residue & Echo Comment Cleanup (`cli/audit/autofix.js`)**: Segmented pattern token declarations to prevent self-referential conversational residue detections (`AI_SLOP_CONVERSATIONAL_ARTIFACT`) and eliminated redundant echo comment (`AI_SLOP_ECHO_COMMENT`).
13
-
14
7
  ## [2026-09-15]
15
8
 
16
9
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chemx/create-chemx",
3
- "version": "26.9.16-1249",
3
+ "version": "26.9.16-668",
4
4
  "description": "Chemical X Protocol: Private drop-in architecture starter kit and capsule generator",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,6 @@
22
22
  },
23
23
  "files": [
24
24
  "cli",
25
- "scripts",
26
25
  "README.md",
27
26
  "LICENSE",
28
27
  "docs"
@@ -48,7 +47,7 @@
48
47
  "search": "node cli/index.js search",
49
48
  "mcp": "node cli/index.js mcp",
50
49
  "install-mcp": "node cli/index.js install-mcp",
51
- "postinstall": "node cli/postinstall.js",
50
+ "postinstall": "node scripts/postinstall.mjs",
52
51
  "read": "node cli/index.js read",
53
52
  "patch": "node cli/index.js patch"
54
53
  },
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { installAllMcpConfigs } from './mcp/installer.js';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const starterKitDir = path.resolve(__dirname, '..');
10
-
11
- const runPostinstall = () => {
12
- const targetDir = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : process.cwd();
13
-
14
- // If installing inside the starter-kit itself for dev, skip consumer installation
15
- const isSelf = targetDir === starterKitDir;
16
- if (isSelf) return;
17
-
18
- try {
19
- installAllMcpConfigs(targetDir, { silent: false });
20
- } catch (err) {
21
- // Non-blocking: never fail npm install
22
- const msg = err instanceof Error ? err.message : String(err);
23
- process.stderr.write(`\x1b[33m[Chemical X] MCP auto-installer skipped: ${msg}\x1b[0m\n`);
24
- }
25
- };
26
-
27
- runPostinstall();
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { installAllMcpConfigs } from '../cli/mcp/installer.js';
6
-
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
9
- const starterKitDir = path.resolve(__dirname, '..');
10
-
11
- const runPostinstall = () => {
12
- const targetDir = process.env.INIT_CWD ? path.resolve(process.env.INIT_CWD) : process.cwd();
13
-
14
- // If installing inside the starter-kit itself for dev, skip consumer installation
15
- const isSelf = targetDir === starterKitDir;
16
- if (isSelf) return;
17
-
18
- try {
19
- installAllMcpConfigs(targetDir, { silent: false });
20
- } catch (err) {
21
- // Non-blocking: never fail npm install
22
- const msg = err instanceof Error ? err.message : String(err);
23
- process.stderr.write(`\x1b[33m[Chemical X] MCP auto-installer skipped: ${msg}\x1b[0m\n`);
24
- }
25
- };
26
-
27
- runPostinstall();
@@ -1,115 +0,0 @@
1
- #!/bin/sh
2
- # Chemical X Protocol: Pre-Commit Line Budget & Architecture Gatekeeper
3
- # https://chemicalx.xophz.com | https://github.com/Chemical-X-Protocol/starter-kit
4
- #
5
- # Free, open-source architectural gatekeeper preventing context bloat and monolith sprawl.
6
-
7
- REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
8
- if [ -z "$REPO_ROOT" ]; then
9
- exit 0
10
- fi
11
-
12
- cd "$REPO_ROOT" || exit 1
13
-
14
- # Load thresholds from .chemx/config.json if available
15
- CONF_MAX_LINES=""
16
- CONF_MAX_MOL=""
17
- CONF_MIN_GRADE=""
18
- CONF_MIN_SCORE=""
19
- CONFIG_FILE="$REPO_ROOT/.chemx/config.json"
20
-
21
- if [ -f "$CONFIG_FILE" ]; then
22
- if command -v node >/dev/null 2>&1; then
23
- eval $(node -e "
24
- try {
25
- const c = JSON.parse(require('fs').readFileSync('$CONFIG_FILE', 'utf8'));
26
- if (c.maxLineCount || c.maxLines) console.log('CONF_MAX_LINES=' + (c.maxLineCount || c.maxLines));
27
- if (c.maxMoleculeLineCount || c.maxMoleculeLines) console.log('CONF_MAX_MOL=' + (c.maxMoleculeLineCount || c.maxMoleculeLines));
28
- if (c.minGrade) console.log('CONF_MIN_GRADE=' + c.minGrade);
29
- if (c.minScore) console.log('CONF_MIN_SCORE=' + c.minScore);
30
- } catch (e) {}
31
- ")
32
- else
33
- CONF_MAX_LINES=$(grep -o '"maxLineCount"[[:space:]]*:[[:space:]]*[0-9]*' "$CONFIG_FILE" 2>/dev/null | grep -o '[0-9]*$')
34
- CONF_MAX_MOL=$(grep -o '"maxMoleculeLineCount"[[:space:]]*:[[:space:]]*[0-9]*' "$CONFIG_FILE" 2>/dev/null | grep -o '[0-9]*$')
35
- CONF_MIN_GRADE=$(grep -o '"minGrade"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG_FILE" 2>/dev/null | sed 's/.*"minGrade"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
36
- CONF_MIN_SCORE=$(grep -o '"minScore"[[:space:]]*:[[:space:]]*[0-9]*' "$CONFIG_FILE" 2>/dev/null | grep -o '[0-9]*$')
37
- fi
38
- fi
39
-
40
- MIN_GRADE="${CHEMX_MIN_GRADE:-${CONF_MIN_GRADE:-B}}"
41
- MIN_SCORE="${CHEMX_MIN_SCORE:-${CONF_MIN_SCORE:-80}}"
42
- MAX_LINES="${CHEMX_MAX_LINES:-${CONF_MAX_LINES:-500}}"
43
- MAX_MOLECULE_LINES="${CHEMX_MAX_MOLECULE_LINES:-${CONF_MAX_MOL:-100}}"
44
-
45
- # Detect staged source files
46
- STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(jsx?|tsx?|vue|svelte)$' | grep -vE '(\.d\.ts|\.min\.|\.test\.|\.spec\.)')
47
-
48
- if [ -z "$STAGED_FILES" ]; then
49
- exit 0
50
- fi
51
-
52
- LINE_BUDGET_FAILED=0
53
- LINE_BUDGET_ERRORS=""
54
-
55
- for FILE in $STAGED_FILES; do
56
- if [ -f "$FILE" ]; then
57
- LINES=$(wc -l < "$FILE" | tr -d ' ')
58
-
59
- # Check if file is a molecule capsule
60
- case "$FILE" in
61
- *molecules*|*/m-*|*m-*)
62
- if [ "$LINES" -gt "$MAX_MOLECULE_LINES" ]; then
63
- LINE_BUDGET_FAILED=1
64
- LINE_BUDGET_ERRORS="${LINE_BUDGET_ERRORS}\n \033[31m✕\033[0m $FILE ($LINES LOC > $MAX_MOLECULE_LINES LOC molecule capsule limit)"
65
- fi
66
- ;;
67
- *)
68
- if [ "$LINES" -gt "$MAX_LINES" ]; then
69
- LINE_BUDGET_FAILED=1
70
- LINE_BUDGET_ERRORS="${LINE_BUDGET_ERRORS}\n \033[31m✕\033[0m $FILE ($LINES LOC > $MAX_LINES LOC file budget)"
71
- fi
72
- ;;
73
- esac
74
- fi
75
- done
76
-
77
- if [ "$LINE_BUDGET_FAILED" -eq 1 ]; then
78
- printf "\n\033[1m\033[31m[Chemical X] Commit Blocked: Staged files exceed architectural line budgets\033[0m\n"
79
- printf "$LINE_BUDGET_ERRORS\n\n"
80
- printf "\033[33mMonolithic files degrade AI context windows and cause hallucination loops.\033[0m\n"
81
- printf "Decompose large files into single-purpose crystalline capsules before committing.\n\n"
82
- fi
83
-
84
- AUDIT_BIN=""
85
- if [ -f "./cli/index.js" ]; then
86
- AUDIT_BIN="node ./cli/index.js"
87
- elif [ -x "./node_modules/.bin/chemx" ]; then
88
- AUDIT_BIN="./node_modules/.bin/chemx"
89
- elif command -v chemx >/dev/null 2>&1; then
90
- AUDIT_BIN="chemx"
91
- elif command -v npx >/dev/null 2>&1; then
92
- AUDIT_BIN="npx chemx"
93
- fi
94
-
95
- if [ -n "$AUDIT_BIN" ]; then
96
- printf "\033[38;2;98;201;255m[Chemical X] Verifying architectural health (Min Grade: %s, Min Score: %s)...\033[0m\n" "$MIN_GRADE" "$MIN_SCORE"
97
-
98
- AUDIT_CMD="$AUDIT_BIN audit --min-grade=$MIN_GRADE --min-score=$MIN_SCORE --non-interactive"
99
-
100
- if ! eval "$AUDIT_CMD < /dev/null"; then
101
- printf "\n\033[1m\033[31m[Chemical X] Commit Blocked: Architectural health verification failed\033[0m\n"
102
- printf "\033[36m💡 Tip: Want crystalline drop-in templates to refactor in minutes?\033[0m\n"
103
- printf " Run 'npm create chemx' or sponsor at https://github.com/sponsors/Chemical-X-Protocol\n\n"
104
- exit 1
105
- fi
106
- fi
107
-
108
- if [ "$LINE_BUDGET_FAILED" -eq 1 ]; then
109
- printf "\033[36m💡 Tip: Want crystalline drop-in templates to refactor in minutes?\033[0m\n"
110
- printf " Run 'npm create chemx' or sponsor at https://github.com/sponsors/Chemical-X-Protocol\n\n"
111
- exit 1
112
- fi
113
-
114
- printf "\033[32m✔ [Chemical X] Pre-commit architectural guardrails passed.\033[0m\n"
115
- exit 0
@@ -1,108 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { spawnSync } from 'node:child_process';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
- const PKG_DIR = path.resolve(__dirname, '..');
11
- const PKG_JSON = path.join(PKG_DIR, 'package.json');
12
-
13
- const args = process.argv.slice(2);
14
- const isDryRun = args.includes('--dry-run');
15
- const otpArg = args.find((a) => a.startsWith('--otp='));
16
- const otp = otpArg ? otpArg.split('=')[1] : null;
17
- const tagArg = args.find((a) => a.startsWith('--tag='));
18
- const tagIndex = args.indexOf('--tag');
19
- const explicitTag = tagArg
20
- ? tagArg.split('=')[1]
21
- : tagIndex !== -1 && args[tagIndex + 1] && !args[tagIndex + 1].startsWith('-')
22
- ? args[tagIndex + 1]
23
- : null;
24
-
25
- const TARGETS = [
26
- {
27
- name: 'create-chemx',
28
- isScoped: false,
29
- bin: { 'create-chemx': 'cli/index.js', chemx: 'cli/index.js' }
30
- },
31
- {
32
- name: '@chemx/starter-kit',
33
- isScoped: true,
34
- bin: {
35
- 'create-chemx': 'cli/index.js',
36
- chemx: 'cli/index.js',
37
- 'chem-x': 'cli/index.js',
38
- 'chemical-x': 'cli/index.js'
39
- }
40
- },
41
- {
42
- name: '@chem-x/starter-kit',
43
- isScoped: true,
44
- bin: {
45
- 'create-chemx': 'cli/index.js',
46
- chemx: 'cli/index.js',
47
- 'chem-x': 'cli/index.js',
48
- 'chemical-x': 'cli/index.js'
49
- }
50
- },
51
- {
52
- name: '@chemx/create-chemx',
53
- isScoped: true,
54
- bin: { 'create-chemx': 'cli/index.js', chemx: 'cli/index.js' }
55
- },
56
- {
57
- name: '@chem-x/create-chemx',
58
- isScoped: true,
59
- bin: { 'create-chemx': 'cli/index.js', chemx: 'cli/index.js' }
60
- },
61
- {
62
- name: 'chemx',
63
- isScoped: false,
64
- bin: { chemx: 'cli/index.js', 'create-chemx': 'cli/index.js' }
65
- }
66
- ];
67
-
68
- const originalContent = fs.readFileSync(PKG_JSON, 'utf-8');
69
- const pkg = JSON.parse(originalContent);
70
- const isPrerelease = Boolean(pkg.version && pkg.version.includes('-'));
71
- const tag = explicitTag || (isPrerelease ? 'latest' : null);
72
-
73
- const results = [];
74
-
75
- try {
76
- for (const target of TARGETS) {
77
- pkg.name = target.name;
78
- pkg.publishConfig = { access: 'public' };
79
- if (tag) {
80
- pkg.publishConfig.tag = tag;
81
- }
82
- pkg.bin = target.bin;
83
-
84
- fs.writeFileSync(PKG_JSON, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
85
-
86
- const publishArgs = ['publish', '--access', 'public'];
87
- if (isDryRun) publishArgs.push('--dry-run');
88
- if (otp) publishArgs.push(`--otp=${otp}`);
89
- if (tag) publishArgs.push('--tag', tag);
90
-
91
- console.log(`\n\x1b[36m[starter-kit] Publishing: ${target.name} (dry-run: ${isDryRun}${tag ? `, tag: ${tag}` : ''})\x1b[0m`);
92
- const proc = spawnSync('npm', publishArgs, {
93
- cwd: PKG_DIR,
94
- stdio: 'inherit'
95
- });
96
-
97
- results.push({ name: target.name, success: proc.status === 0 });
98
- }
99
- } finally {
100
- fs.writeFileSync(PKG_JSON, originalContent, 'utf-8');
101
- }
102
-
103
- console.log('\n\x1b[1m\x1b[36m--- starter-kit Publish Summary ---\x1b[0m');
104
- for (const res of results) {
105
- const icon = res.success ? '\x1b[32m✔\x1b[0m' : '\x1b[31m✕\x1b[0m';
106
- console.log(` ${icon} ${res.name.padEnd(25)} ${res.success ? 'Published' : 'Failed'}`);
107
- }
108
- console.log('\x1b[1m\x1b[36m-----------------------------------\x1b[0m\n');