Skip to content

Commit dec6218

Browse files
committed
feat: migrate to remote Single Source of Truth architecture and release v2.0.0
1 parent 4f1473a commit dec6218

6 files changed

Lines changed: 52 additions & 10 deletions

File tree

WORK_LOG/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 2026-07-04 (v2.0.0)
4+
- **Massive Architectural Change**: Shifted Single Source of Truth for synced problems to GitHub via `commitcode.json`. This completely solves the multi-device problem where using a second laptop would reset the README.
5+
- Automatically migrates existing local databases to the remote repository.
6+
- Re-architected `ReadmeGenerator` to be entirely stateless and driven by the remote configuration file.
7+
38
## 2026-07-03
49
- Redesigned Onboarding, Options, and Popup UIs with a modern, premium glassmorphic dark theme using Tailwind CSS.
510
- Rebranded extension from "LeetSync" to "CommitCode".

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 3,
33
"name": "CommitCode",
4-
"version": "1.1.0",
4+
"version": "2.0.0",
55
"description": "Privacy-first browser extension that automatically syncs accepted coding problem submissions from LeetCode to GitHub.",
66
"icons": {
77
"16": "logo.png",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "commitcode",
3-
"version": "1.1.0",
3+
"version": "2.0.0",
44
"description": "Privacy-first LeetCode to GitHub sync extension",
55
"type": "module",
66
"scripts": {

src/background/sync-engine.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,46 @@ export class SyncEngine {
181181
{ path: targetPath, content: fullCode }
182182
];
183183

184-
// 5. Generate README content if enabled
184+
// 5. Remote Source of Truth & README Generation
185185
if (settings.readmeEnabled) {
186-
const allProblems = await db.getAllProblems();
186+
problem.version = version;
187+
188+
let remoteMetadata: any[] = [];
189+
try {
190+
const remoteFile = await client.getFile('commitcode.json');
191+
// UTF-8 base64 decode
192+
const jsonStr = decodeURIComponent(escape(atob(remoteFile.content)));
193+
remoteMetadata = JSON.parse(jsonStr);
194+
} catch (e: any) {
195+
if (e.status !== 404) {
196+
console.warn('[CommitCode] Could not fetch commitcode.json, assuming new or missing.', e);
197+
}
198+
}
199+
200+
// Migrate local data to remote if remote is empty
201+
if (remoteMetadata.length === 0) {
202+
const localProblems = await db.getAllProblems();
203+
remoteMetadata = localProblems.map(p => {
204+
const { code: _, ...rest } = p;
205+
return rest;
206+
});
207+
}
208+
209+
// Include current problem
210+
const { code: _code, ...currentMeta } = problem;
211+
const index = remoteMetadata.findIndex(p => p.id === currentMeta.id && p.language === currentMeta.language);
212+
if (index >= 0) {
213+
remoteMetadata[index] = currentMeta;
214+
} else {
215+
remoteMetadata.push(currentMeta);
216+
}
217+
218+
// Queue commitcode.json
219+
const newJsonStr = JSON.stringify(remoteMetadata, null, 2);
220+
filesToCommit.push({ path: 'commitcode.json', content: newJsonStr });
221+
187222
const readmeGenerator = new ReadmeGenerator();
188-
const readmeContent = readmeGenerator.generate(settings, allProblems);
223+
const readmeContent = readmeGenerator.generate(settings, remoteMetadata);
189224
if (readmeContent) {
190225
filesToCommit.push({ path: 'README.md', content: readmeContent });
191226
}

src/github/readme-generator.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ProblemRecord, Settings } from '../storage/types';
1+
import { ProblemMetadata, Settings } from '../storage/types';
22

33
export class ReadmeGenerator {
44
private getExtensionByLanguage(language: string): string {
@@ -22,7 +22,7 @@ export class ReadmeGenerator {
2222
return map[language.toLowerCase()] || 'txt';
2323
}
2424

25-
private resolvePath(problem: ProblemRecord, settings: Settings): string {
25+
private resolvePath(problem: ProblemMetadata, settings: Settings): string {
2626
const paddedId = problem.id.toString().padStart(4, '0');
2727
const safeTitle = problem.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
2828
const ext = this.getExtensionByLanguage(problem.language);
@@ -41,8 +41,8 @@ export class ReadmeGenerator {
4141
case 'Language':
4242
return `${problem.language}/${filename}`;
4343
case 'Number':
44-
const paddedId = problem.id.toString().padStart(4, '0');
45-
return `${paddedId}/${filename}`;
44+
const paddedIdFolder = problem.id.toString().padStart(4, '0');
45+
return `${paddedIdFolder}/${filename}`;
4646
case 'Flat':
4747
return filename;
4848
case 'Topic':
@@ -52,7 +52,7 @@ export class ReadmeGenerator {
5252
}
5353
}
5454

55-
public generate(settings: Settings, allProblems: ProblemRecord[]): string {
55+
public generate(settings: Settings, allProblems: ProblemMetadata[]): string {
5656
if (allProblems.length === 0) return '';
5757

5858
let total = 0;

src/storage/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export interface ProblemRecord {
1313
version: number;
1414
}
1515

16+
export type ProblemMetadata = Omit<ProblemRecord, 'code'>;
17+
1618
export type FolderStructure = 'Difficulty' | 'Topic' | 'Language' | 'Number' | 'Flat';
1719

1820
export interface Settings {

0 commit comments

Comments
 (0)