-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsync-profile-readme.js
More file actions
196 lines (167 loc) · 8.02 KB
/
sync-profile-readme.js
File metadata and controls
196 lines (167 loc) · 8.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
const fs = require('fs');
const path = require('path');
// Configuration
const WEBSITE_DATA_URL = 'https://raw.githubusercontent.com/ppradyoth/ppradyoth-website/main/lib/data.ts';
const GITHUB_USERNAME = 'ppradyoth';
// Custom descriptions to override default GitHub descriptions with high-quality copy
const CUSTOM_DESCRIPTIONS = {
'ai-security-resources': 'Curated directory of state-of-the-art Adversarial AI Security tools, vulnerability scanners, safety benchmarks, guardrails, and compliance standards.',
'prompt-injection-ctf': 'Interactive AI Security Playground — Prompt Injection CTF. Craft attack prompts to break constrained AI systems. Learn prompt injection, jailbreaking, intent drift & token smuggling. Built to teach adversarial thinking hands-on.',
'llm-ops-workshop': 'End-to-end MLOps workflow demonstrating model lifecycle, monitoring, and deployment practices.',
'ML-101-Workshop': 'Source code from the ML-101 workshop hosted by IEEE Bangalore Section at IEEE CCONNECT. Built to make machine learning accessible to early-career engineers.',
'schmaltz-surveyor': 'Live sentiment analysis of public tweets. Two-phase project: classifier benchmarking across multiple ML models, then a web app for real-time Twitter sentiment analysis.',
'synaptic-wetware': '🧠 Organoid Intelligence Biocomputer Simulator — HH + Izhikevich neuron models, MEA burst detection, DishBrain Pong, Baltimore Declaration ethics monitor. Built by Antigravity (Google DeepMind).',
'akrivon-ai': 'AI Scope & Intent Enforcement Gateway. Automated adversarial red-team probing (IntentScan) and a low-latency runtime proxy (IntentEnforce) to keep LLMs secure and aligned.',
'weighted-safety-refusal': 'Severity-weighted LLM safety evaluation suite. Measures absolute refusal robustness across prompt injection, jailbreaking, data exfiltration, toxicity, and malware generation using risk-adjusted weights.'
};
// Patterns to exclude minor, test, or school lab repositories to keep the profile premium
const EXCLUDE_PATTERNS = [
/lab/i,
/test/i,
/program/i,
/session/i,
/wtproject/i,
/mp_asm/i,
/class/i,
/course/i,
/practice/i,
/linktree/i,
/bende-bot/i,
/psychmytrip/i,
/discord/i
];
const EXCLUDED_REPOS = [
'ppradyoth',
'stock-predictor-1',
'ss_lexyacc',
'Apple-Edu',
'basic-shop-catalogue-webapp',
'OperatingSystems'
];
// File Paths (defaults to parent directory for Profile README)
const readmePath = path.join(__dirname, 'README.md');
// Helper to fetch text content via native fetch
async function fetchText(url, headers = {}) {
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
}
return response.text();
}
// Helper to fetch JSON content via native fetch
async function fetchJson(url, headers = {}) {
const text = await fetchText(url, headers);
return JSON.parse(text);
}
// Helper to parse TS data using eval-slicing
function parseWebsiteData(tsContent) {
const cleanJs = tsContent
.split('export const certifications')[0]
.replace(/export const /g, 'exports.');
const moduleFn = new Function('exports', cleanJs);
const data = {};
moduleFn(data);
return data;
}
// Helper to replace text between markers
function replaceBetweenMarkers(content, startMarker, endMarker, replacement) {
const startIndex = content.indexOf(startMarker);
const endIndex = content.indexOf(endMarker);
if (startIndex === -1 || endIndex === -1) {
console.warn(`Markers not found: ${startMarker} or ${endMarker}`);
return content;
}
return (
content.substring(0, startIndex + startMarker.length) +
'\n' +
replacement +
'\n' +
content.substring(endIndex)
);
}
async function main() {
try {
console.log('Starting profile sync...');
// 1. Load career data from personal website
let tsContent;
const localWebsitePath = path.join(__dirname, '..', 'ppradyoth-website', 'lib', 'data.ts');
if (fs.existsSync(localWebsitePath)) {
console.log('Found local website data file at:', localWebsitePath);
tsContent = fs.readFileSync(localWebsitePath, 'utf8');
} else {
console.log('Local website data not found, fetching from remote repo...');
const websiteHeaders = {
'User-Agent': 'ppradyoth-sync-script',
};
const token = process.env.WEBSITE_ACCESS_TOKEN || process.env.GITHUB_TOKEN;
if (token) {
websiteHeaders['Authorization'] = `token ${token}`;
console.log('Using authorization token for website data fetch.');
}
tsContent = await fetchText(WEBSITE_DATA_URL, websiteHeaders);
}
const careerData = parseWebsiteData(tsContent);
const latestRole = careerData.experience[0];
if (!latestRole) {
throw new Error('No experience roles found in website data.');
}
console.log(`Latest role parsed: ${latestRole.role} at ${latestRole.company}`);
// 2. Fetch public repositories from GitHub API
console.log('Fetching repositories from GitHub API...');
const githubHeaders = {
'User-Agent': 'ppradyoth-sync-script',
};
if (process.env.GITHUB_TOKEN) {
githubHeaders['Authorization'] = `token ${process.env.GITHUB_TOKEN}`;
}
const reposUrl = `https://api.github.com/users/${GITHUB_USERNAME}/repos?per_page=100`;
const repos = await fetchJson(reposUrl, githubHeaders);
console.log(`Fetched ${repos.length} total repositories.`);
// 3. Read current README.md
if (!fs.existsSync(readmePath)) {
throw new Error(`README.md not found at ${readmePath}`);
}
let readmeContent = fs.readFileSync(readmePath, 'utf8');
// 4. Update Header (Capsule Render desc)
let teamName = latestRole.team || '';
if (teamName.includes('·')) {
const parts = teamName.split('·').map(p => p.trim());
teamName = parts.find(p => p.toLowerCase().includes('red team')) || parts[parts.length - 1];
}
const descString = `${latestRole.role} | ${teamName} | ${latestRole.company}`;
const encodedDesc = encodeURIComponent(descString);
const encodedName = encodeURIComponent(careerData.profile.name);
const newHeader = `<img src="https://capsule-render.vercel.app/api?type=waving&color=0:0d1117,50:8b0000,100:0e75b6&height=180§ion=header&text=${encodedName}&fontSize=48&fontColor=ffffff&animation=twinkling&fontAlignY=35&desc=${encodedDesc}&descAlignY=55&descSize=18&descFontColor=cccccc" width="100%"/>`;
readmeContent = replaceBetweenMarkers(readmeContent, '<!-- HEADER_START -->', '<!-- HEADER_END -->', newHeader);
// 5. Update What I'm Working On (Latest Role highlights)
const workLines = latestRole.highlights.map(h => `- ${h}`).join('\n');
readmeContent = replaceBetweenMarkers(readmeContent, '<!-- WORK_START -->', '<!-- WORK_END -->', workLines);
// 6. Update Open Source Section
const formattedRepos = repos
.filter(r => {
if (r.fork || r.private || EXCLUDED_REPOS.includes(r.name)) return false;
return !EXCLUDE_PATTERNS.some(pat => pat.test(r.name));
})
.sort((a, b) => {
if (b.stargazers_count !== a.stargazers_count) {
return b.stargazers_count - a.stargazers_count;
}
return new Date(b.pushed_at) - new Date(a.pushed_at);
})
.map(r => {
const starBadge = r.stargazers_count > 0 ? ` (⭐ ${r.stargazers_count})` : '';
const description = CUSTOM_DESCRIPTIONS[r.name] || r.description || 'No description provided.';
return `**[${r.name}](${r.html_url})**${starBadge} — ${description}`;
})
.join('\n\n');
const openSourceContent = formattedRepos + '\n\n*Also building something in AI security — stealth mode 🔒*';
readmeContent = replaceBetweenMarkers(readmeContent, '<!-- OPENSYNC_START -->', '<!-- OPENSYNC_END -->', openSourceContent);
// 7. Write changes back to README.md
fs.writeFileSync(readmePath, readmeContent, 'utf8');
console.log('README.md successfully updated and synchronized!');
} catch (error) {
console.error('Error during sync process:', error);
process.exit(1);
}
}
main();