codymaster 4.5.1 → 4.5.2
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 +2 -1
- package/scripts/gate-0-secrets.js +63 -0
- package/scripts/gate-1-syntax.js +53 -0
- package/scripts/gate-5-dist-verify.js +55 -0
- package/scripts/gate-6-smoke-test.js +30 -0
- package/scripts/index-codebase.sh +552 -0
- package/scripts/mcp-bridge.js +284 -0
- package/scripts/postinstall.js +301 -0
- package/scripts/security-fixer.js +143 -0
- package/scripts/security-scan.js +55 -0
- package/scripts/test-gemini.js +13 -0
- package/scripts/todo-bridge.js +112 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codymaster",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.2",
|
|
4
4
|
"description": "68+ Skills. Ship 10x faster. AI-powered coding skill kit for Claude, Cursor, Gemini & more.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"type": "commonjs",
|
|
47
47
|
"files": [
|
|
48
48
|
"dist/",
|
|
49
|
+
"scripts/",
|
|
49
50
|
"skills/",
|
|
50
51
|
"adapters/",
|
|
51
52
|
"commands/",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 0: Secret Hygiene
|
|
4
|
+
* Fastest gate (< 0.5s). Checks for leaked secrets before anything else runs.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
let failed = false;
|
|
10
|
+
|
|
11
|
+
// 1. Check wrangler config files for hardcoded secret values
|
|
12
|
+
const wranglerFiles = ['wrangler.toml', 'wrangler.jsonc', 'wrangler.json'];
|
|
13
|
+
const dangerous = [
|
|
14
|
+
'SERVICE_KEY', 'ANON_KEY', 'DB_PASSWORD', 'SECRET_KEY', 'PRIVATE_KEY', 'API_SECRET',
|
|
15
|
+
'GCP_SERVICE_ACCOUNT', 'AZURE_CONNECTION_STRING', 'HEROKU_API_KEY', 'POSTMAN_API_KEY'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (const wf of wranglerFiles) {
|
|
19
|
+
if (!fs.existsSync(wf)) continue;
|
|
20
|
+
const src = fs.readFileSync(wf, 'utf-8');
|
|
21
|
+
for (const key of dangerous) {
|
|
22
|
+
const valuePattern = new RegExp(key + '\\s*[=:]\\s*["\'][a-zA-Z0-9/+=]{20,}', 'g');
|
|
23
|
+
if (valuePattern.test(src)) {
|
|
24
|
+
console.error('❌ DANGEROUS: ' + wf + ' contains a ' + key + ' VALUE');
|
|
25
|
+
console.error(' Fix: wrangler secret put ' + key + ' (then remove from ' + wf + ')');
|
|
26
|
+
failed = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 2. Check .gitignore has required patterns
|
|
32
|
+
if (fs.existsSync('.gitignore')) {
|
|
33
|
+
const gi = fs.readFileSync('.gitignore', 'utf-8');
|
|
34
|
+
const required = ['.env', '.dev.vars'];
|
|
35
|
+
const missing = required.filter(r => !gi.includes(r));
|
|
36
|
+
if (missing.length > 0) {
|
|
37
|
+
console.error('❌ .gitignore missing: ' + missing.join(', '));
|
|
38
|
+
failed = true;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
console.error('❌ No .gitignore found!');
|
|
42
|
+
failed = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 3. Check .env / .dev.vars files aren't tracked by git
|
|
46
|
+
try {
|
|
47
|
+
const tracked = execSync('git ls-files', { encoding: 'utf-8' });
|
|
48
|
+
const badFiles = ['.env', '.dev.vars', '.env.local', '.env.production'];
|
|
49
|
+
const trackedBad = badFiles.filter(f => tracked.split('\n').includes(f));
|
|
50
|
+
if (trackedBad.length > 0) {
|
|
51
|
+
console.error('❌ CRITICAL: Secret files tracked by git: ' + trackedBad.join(', '));
|
|
52
|
+
console.error(' Fix: git rm --cached ' + trackedBad.join(' '));
|
|
53
|
+
failed = true;
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
// Not a git repo — skip
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (failed) {
|
|
60
|
+
console.error('\n🛡️ Gate 0 FAILED. Fix issues above before deploying.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
console.log('✅ Gate 0 passed: secret hygiene verified');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 1: Syntax Validation
|
|
4
|
+
* Fast-fail (< 2s). Catches syntax errors before the slower test suite.
|
|
5
|
+
* - Parses all JS files in public/js/ with acorn
|
|
6
|
+
* - Runs tsc --noEmit for TypeScript in src/
|
|
7
|
+
*/
|
|
8
|
+
const { parse } = require('acorn');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
let failed = false;
|
|
14
|
+
|
|
15
|
+
// 1. Parse all JS files in public/js/
|
|
16
|
+
const jsDir = 'public/js';
|
|
17
|
+
if (fs.existsSync(jsDir)) {
|
|
18
|
+
const jsFiles = fs.readdirSync(jsDir).filter(f => f.endsWith('.js'));
|
|
19
|
+
for (const file of jsFiles) {
|
|
20
|
+
const filePath = path.join(jsDir, file);
|
|
21
|
+
const code = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
try {
|
|
23
|
+
parse(code, { ecmaVersion: 2022, sourceType: 'script' });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error(`❌ Syntax error in ${filePath}:`);
|
|
26
|
+
console.error(` Line ${err.loc?.line}, Column ${err.loc?.column}: ${err.message}`);
|
|
27
|
+
failed = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!failed) {
|
|
31
|
+
console.log(`✅ ${jsFiles.length} JS files parsed successfully`);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
console.log('⚠ No public/js/ directory found, skipping JS syntax check');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. TypeScript compilation check
|
|
38
|
+
if (fs.existsSync('tsconfig.json')) {
|
|
39
|
+
try {
|
|
40
|
+
execSync('npx tsc --noEmit', { encoding: 'utf-8', stdio: 'pipe' });
|
|
41
|
+
console.log('✅ TypeScript compilation check passed');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('❌ TypeScript compilation errors:');
|
|
44
|
+
console.error(err.stdout || err.stderr || err.message);
|
|
45
|
+
failed = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (failed) {
|
|
50
|
+
console.error('\n🔴 Gate 1 FAILED. Fix syntax errors before proceeding.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
console.log('✅ Gate 1 passed: syntax validation complete');
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 5: Dist Asset Verification
|
|
4
|
+
* Verifies critical files exist in public/ after build:html + docs:build.
|
|
5
|
+
* Build can "succeed" but produce an incomplete output directory.
|
|
6
|
+
*/
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const publicDir = 'public';
|
|
11
|
+
// Critical HTML pages
|
|
12
|
+
const requiredHtml = [
|
|
13
|
+
'dashboard/index.html',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// Critical JS files
|
|
17
|
+
const requiredJs = [
|
|
18
|
+
'dashboard/app.js',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Critical CSS files
|
|
22
|
+
const requiredCss = [
|
|
23
|
+
'dashboard/style.css',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// Build required file list
|
|
27
|
+
const required = [];
|
|
28
|
+
|
|
29
|
+
// HTML pages
|
|
30
|
+
for (const html of requiredHtml) {
|
|
31
|
+
required.push(path.join(publicDir, html));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// JS files
|
|
35
|
+
for (const js of requiredJs) {
|
|
36
|
+
required.push(path.join(publicDir, js));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// CSS files
|
|
40
|
+
for (const css of requiredCss) {
|
|
41
|
+
required.push(path.join(publicDir, css));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// Check all required files
|
|
46
|
+
const missing = required.filter(f => !fs.existsSync(f));
|
|
47
|
+
|
|
48
|
+
if (missing.length > 0) {
|
|
49
|
+
console.error('❌ Missing critical files:');
|
|
50
|
+
missing.forEach(f => console.error(' ' + f));
|
|
51
|
+
console.error(`\n🔴 Gate 5 FAILED. ${missing.length} file(s) missing from build output.`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log(`✅ Gate 5 passed: all ${required.length} critical files present`);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Gate 6: Post-Deploy Smoke Test
|
|
4
|
+
* Verifies the deployed site returns HTTP 200.
|
|
5
|
+
* Usage: node scripts/gate-6-smoke-test.js [optional-url]
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DEPLOY_URL = process.argv[2] || process.env.DEPLOY_URL || 'https://cody.todyle.com';
|
|
9
|
+
|
|
10
|
+
async function smokeTest() {
|
|
11
|
+
console.log(`🔍 Smoke testing: ${DEPLOY_URL}`);
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetch(DEPLOY_URL);
|
|
15
|
+
if (res.status === 200) {
|
|
16
|
+
console.log(`✅ Gate 6 passed: HTTP ${res.status} from ${DEPLOY_URL}`);
|
|
17
|
+
} else {
|
|
18
|
+
console.error(`❌ Gate 6 FAILED: HTTP ${res.status} from ${DEPLOY_URL}`);
|
|
19
|
+
console.error(' ⚠ Consider immediate rollback.');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error(`❌ Gate 6 FAILED: Could not reach ${DEPLOY_URL}`);
|
|
24
|
+
console.error(` Error: ${err.message}`);
|
|
25
|
+
console.error(' ⚠ Consider immediate rollback.');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
smokeTest();
|