diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5ffe431..335fed4 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -17,7 +17,8 @@ "Bash(grep -n \"templateSlug\\\\|postTemplateSlug\" /Users/gb/Projects/bDS/src/main/engine/*.ts)", "Bash(npm test -- tests/renderer/i18nLocaleCompleteness.test.ts)", "WebFetch(domain:ricmac.org)", - "WebFetch(domain:docs.mistral.ai)" + "WebFetch(domain:docs.mistral.ai)", + "Bash(npm uninstall dropbox date-fns @testing-library/user-event @types/dagre electron-store memfs)" ] } } diff --git a/knip.json b/knip.json new file mode 100644 index 0000000..4078d69 --- /dev/null +++ b/knip.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://unpkg.com/knip@5/schema.json", + "entry": [ + "src/main/main.ts", + "src/main/preload.ts", + "src/cli/bds-mcp.ts", + "src/main/engine/generation.worker.ts", + "src/main/engine/pythonMacro.worker.ts", + "src/main/engine/blogmarkPython.worker.ts" + ], + "project": [ + "src/**/*.{ts,tsx}" + ], + "ignoreDependencies": [ + "@ai-sdk/provider", + "@electron/notarize", + "@floating-ui/dom", + "@milkdown/plugin-block", + "@milkdown/plugin-clipboard", + "@milkdown/plugin-cursor", + "@milkdown/plugin-history", + "@milkdown/plugin-indent", + "@milkdown/plugin-listener", + "@milkdown/plugin-trailing", + "@milkdown/theme-nord", + "d3-cloud", + "highlight.js", + "lightbox2", + "marked", + "mdast", + "unified", + "unist-util-visit", + "vanilla-calendar-pro" + ], + "vitest": { + "config": ["vitest.config.ts"], + "entry": [ + "tests/**/*.test.{ts,tsx}", + "src/**/*.test.{ts,tsx}", + "tests/setup.ts" + ] + }, + "eslint": { + "config": ["eslint.config.mjs"] + }, + "vite": { + "config": ["vite.config.ts", "vite.config.cli.ts"] + }, + "drizzle": { + "config": ["drizzle.config.ts"] + }, + "paths": { + "@/*": ["src/renderer/*"] + } +} diff --git a/package-lock.json b/package-lock.json index 5db0e35..8f1d944 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,9 +36,7 @@ "ai": "^6.0.105", "chokidar": "^5.0.0", "d3-cloud": "^1.2.8", - "date-fns": "^4.1.0", "drizzle-orm": "^0.45.1", - "dropbox": "^10.34.0", "fast-xml-parser": "^5.3.8", "gray-matter": "^4.0.3", "lightbox2": "^2.11.5", @@ -68,9 +66,7 @@ "@electron/notarize": "^3.1.0", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/chokidar": "^1.7.5", - "@types/dagre": "^0.7.54", "@types/node": "^25.2.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", @@ -85,11 +81,9 @@ "drizzle-kit": "^0.31.9", "electron": "^40.4.0", "electron-builder": "^26.7.0", - "electron-store": "^11.0.2", "eslint": "^9.39.3", "eslint-plugin-i18next": "^6.1.3", "jsdom": "^28.0.0", - "memfs": "^4.6.0", "png-to-ico": "^3.0.1", "tsx": "^4.6.0", "typescript": "^5.3.0", @@ -3489,436 +3483,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/buffers": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", - "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/codegen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", - "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-core": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.56.10.tgz", - "integrity": "sha512-PyAEA/3cnHhsGcdY+AmIU+ZPqTuZkDhCXQ2wkXypdLitSpd6d5Ivxhnq4wa2ETRWFVJGabYynBWxIijOswSmOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.56.10", - "@jsonjoy.com/fs-node-utils": "4.56.10", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-fsa": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.56.10.tgz", - "integrity": "sha512-/FVK63ysNzTPOnCCcPoPHt77TOmachdMS422txM4KhxddLdbW1fIbFMYH0AM0ow/YchCyS5gqEjKLNyv71j/5Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-core": "4.56.10", - "@jsonjoy.com/fs-node-builtins": "4.56.10", - "@jsonjoy.com/fs-node-utils": "4.56.10", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.56.10.tgz", - "integrity": "sha512-7R4Gv3tkUdW3dXfXiOkqxkElxKNVdd8BDOWC0/dbERd0pXpPY+s2s1Mino+aTvkGrFPiY+mmVxA7zhskm4Ue4Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-core": "4.56.10", - "@jsonjoy.com/fs-node-builtins": "4.56.10", - "@jsonjoy.com/fs-node-utils": "4.56.10", - "@jsonjoy.com/fs-print": "4.56.10", - "@jsonjoy.com/fs-snapshot": "4.56.10", - "glob-to-regex.js": "^1.0.0", - "thingies": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-builtins": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.56.10.tgz", - "integrity": "sha512-uUnKz8R0YJyKq5jXpZtkGV9U0pJDt8hmYcLRrPjROheIfjMXsz82kXMgAA/qNg0wrZ1Kv+hrg7azqEZx6XZCVw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-to-fsa": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.56.10.tgz", - "integrity": "sha512-oH+O6Y4lhn9NyG6aEoFwIBNKZeYy66toP5LJcDOMBgL99BKQMUf/zWJspdRhMdn/3hbzQsZ8EHHsuekbFLGUWw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-fsa": "4.56.10", - "@jsonjoy.com/fs-node-builtins": "4.56.10", - "@jsonjoy.com/fs-node-utils": "4.56.10" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-node-utils": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.56.10.tgz", - "integrity": "sha512-8EuPBgVI2aDPwFdaNQeNpHsyqPi3rr+85tMNG/lHvQLiVjzoZsvxA//Xd8aB567LUhy4QS03ptT+unkD/DIsNg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.56.10" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-print": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.56.10.tgz", - "integrity": "sha512-JW4fp5mAYepzFsSGrQ48ep8FXxpg4niFWHdF78wDrFGof7F3tKDJln72QFDEn/27M1yHd4v7sKHHVPh78aWcEw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-node-utils": "4.56.10", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.56.10.tgz", - "integrity": "sha512-DkR6l5fj7+qj0+fVKm/OOXMGfDFCGXLfyHkORH3DF8hxkpDgIHbhf/DwncBMs2igu/ST7OEkexn1gIqoU6Y+9g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/buffers": "^17.65.0", - "@jsonjoy.com/fs-node-utils": "4.56.10", - "@jsonjoy.com/json-pack": "^17.65.0", - "@jsonjoy.com/util": "^17.65.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", - "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", - "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", - "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/base64": "17.67.0", - "@jsonjoy.com/buffers": "17.67.0", - "@jsonjoy.com/codegen": "17.67.0", - "@jsonjoy.com/json-pointer": "17.67.0", - "@jsonjoy.com/util": "17.67.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", - "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/util": "17.67.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { - "version": "17.67.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", - "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/buffers": "17.67.0", - "@jsonjoy.com/codegen": "17.67.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", - "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/base64": "^1.1.2", - "@jsonjoy.com/buffers": "^1.2.0", - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/json-pointer": "^1.0.2", - "@jsonjoy.com/util": "^1.9.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pointer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", - "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/util": "^1.9.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", - "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/buffers": "^1.0.0", - "@jsonjoy.com/codegen": "^1.0.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -5619,20 +5183,6 @@ } } }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -5720,13 +5270,6 @@ "@types/node": "*" } }, - "node_modules/@types/dagre": { - "version": "0.7.54", - "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.54.tgz", - "integrity": "sha512-QjcRY+adGbYvBFS7cwv5txhVIwX1XXIUswWl+kSQTbI6NjgZydrZkEKX/etzVd7i+bCsCb40Z/xlBY5eoFuvWQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -5851,17 +5394,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/@types/node-fetch": { - "version": "2.6.13", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", - "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.4" - } - }, "node_modules/@types/plist": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", @@ -7103,6 +6635,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, "license": "MIT" }, "node_modules/at-least-node": { @@ -7115,17 +6648,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atomically": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", - "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "stubborn-fs": "^2.0.0", - "when-exit": "^2.1.4" - } - }, "node_modules/axios": { "version": "1.13.5", "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", @@ -7861,6 +7383,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -7921,80 +7444,6 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/conf": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/conf/-/conf-15.1.0.tgz", - "integrity": "sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "atomically": "^2.0.3", - "debounce-fn": "^6.0.0", - "dot-prop": "^10.0.0", - "env-paths": "^3.0.0", - "json-schema-typed": "^8.0.1", - "semver": "^7.7.2", - "uint8array-extras": "^1.5.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/conf/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/conf/node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/conf/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/conf/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/content-disposition": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", @@ -8281,32 +7730,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/debounce-fn": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-6.0.0.tgz", - "integrity": "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -8441,6 +7864,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -8638,22 +8062,6 @@ "@types/trusted-types": "^2.0.7" } }, - "node_modules/dot-prop": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-10.1.0.tgz", - "integrity": "sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^5.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -8824,63 +8232,6 @@ } } }, - "node_modules/dropbox": { - "version": "10.34.0", - "resolved": "https://registry.npmjs.org/dropbox/-/dropbox-10.34.0.tgz", - "integrity": "sha512-5jb5/XzU0fSnq36/hEpwT5/QIep7MgqKuxghEG44xCu7HruOAjPdOb3x0geXv5O/hd0nHpQpWO+r5MjYTpMvJg==", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.1" - }, - "engines": { - "node": ">=0.10.3" - }, - "peerDependencies": { - "@types/node-fetch": "^2.5.7" - } - }, - "node_modules/dropbox/node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/dropbox/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/dropbox/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/dropbox/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -9075,23 +8426,6 @@ "node": ">= 10.0.0" } }, - "node_modules/electron-store": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-11.0.2.tgz", - "integrity": "sha512-4VkNRdN+BImL2KcCi41WvAYbh6zLX5AUTi4so68yPqiItjbgTjqpEnGAqasgnG+lB6GuAyUltKwVopp6Uv+gwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "conf": "^15.0.2", - "type-fest": "^5.0.1" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", @@ -9242,6 +8576,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10041,6 +9376,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -10263,23 +9599,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regex.js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", - "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -10492,6 +9811,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -10662,16 +9982,6 @@ "node": ">= 14" } }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.18" - } - }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -11800,36 +11110,6 @@ "node": ">= 0.8" } }, - "node_modules/memfs": { - "version": "4.56.10", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.56.10.tgz", - "integrity": "sha512-eLvzyrwqLHnLYalJP7YZ3wBe79MXktMdfQbvMrVD80K+NhrIukCVBvgP30zTJYEEDh9hZ/ep9z0KOdD7FSHo7w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/fs-core": "4.56.10", - "@jsonjoy.com/fs-fsa": "4.56.10", - "@jsonjoy.com/fs-node": "4.56.10", - "@jsonjoy.com/fs-node-builtins": "4.56.10", - "@jsonjoy.com/fs-node-to-fsa": "4.56.10", - "@jsonjoy.com/fs-node-utils": "4.56.10", - "@jsonjoy.com/fs-print": "4.56.10", - "@jsonjoy.com/fs-snapshot": "4.56.10", - "@jsonjoy.com/json-pack": "^1.11.0", - "@jsonjoy.com/util": "^1.9.0", - "glob-to-regex.js": "^1.0.1", - "thingies": "^2.5.0", - "tree-dump": "^1.0.3", - "tslib": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -12447,6 +11727,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12456,6 +11737,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -12464,19 +11746,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -15213,23 +14482,6 @@ ], "license": "MIT" }, - "node_modules/stubborn-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", - "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "stubborn-utils": "^1.0.1" - } - }, - "node_modules/stubborn-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", - "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", - "dev": true, - "license": "MIT" - }, "node_modules/style-mod": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", @@ -15272,19 +14524,6 @@ "dev": true, "license": "MIT" }, - "node_modules/tagged-tag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", - "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tar": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", @@ -15373,23 +14612,6 @@ "node": ">= 10.0.0" } }, - "node_modules/thingies": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", - "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "^2" - } - }, "node_modules/tiny-async-pool": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", @@ -15552,23 +14774,6 @@ "node": ">=20.0.0" } }, - "node_modules/tree-dump": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", - "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -16152,22 +15357,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.4.tgz", - "integrity": "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "dependencies": { - "tagged-tag": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -16222,19 +15411,6 @@ "node": ">=14.17" } }, - "node_modules/uint8array-extras": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", - "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/undici": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.21.0.tgz", @@ -17302,13 +16478,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/when-exit": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", - "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", - "dev": true, - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 0eb23bd..caef10f 100644 --- a/package.json +++ b/package.json @@ -41,9 +41,7 @@ "@electron/notarize": "^3.1.0", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/chokidar": "^1.7.5", - "@types/dagre": "^0.7.54", "@types/node": "^25.2.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", @@ -58,11 +56,9 @@ "drizzle-kit": "^0.31.9", "electron": "^40.4.0", "electron-builder": "^26.7.0", - "electron-store": "^11.0.2", "eslint": "^9.39.3", "eslint-plugin-i18next": "^6.1.3", "jsdom": "^28.0.0", - "memfs": "^4.6.0", "png-to-ico": "^3.0.1", "tsx": "^4.6.0", "typescript": "^5.3.0", @@ -98,9 +94,7 @@ "ai": "^6.0.105", "chokidar": "^5.0.0", "d3-cloud": "^1.2.8", - "date-fns": "^4.1.0", "drizzle-orm": "^0.45.1", - "dropbox": "^10.34.0", "fast-xml-parser": "^5.3.8", "gray-matter": "^4.0.3", "lightbox2": "^2.11.5", @@ -136,6 +130,10 @@ "appId": "com.bds.blogging-desktop-server", "productName": "Blogging Desktop Server", "asar": true, + "asarUnpack": [ + "node_modules/onnxruntime-node/**", + "node_modules/usearch/**" + ], "afterSign": "scripts/notarize.mjs", "directories": { "output": "release" diff --git a/src/main/config/macroConfig.ts b/src/main/config/macroConfig.ts index fcdbea7..557b95a 100644 --- a/src/main/config/macroConfig.ts +++ b/src/main/config/macroConfig.ts @@ -23,7 +23,7 @@ export interface MacroConfig { * Registry of known macro configurations. * Add new macros here to enable validation during import analysis. */ -export const macroConfigs: MacroConfig[] = [ +const macroConfigs: MacroConfig[] = [ { name: 'youtube', description: 'Embeds a YouTube video player', @@ -105,43 +105,3 @@ export function getMacroConfigMap(): Map { return map; } -/** - * Validate macro parameters against known configurations. - * - * @param macroName - The macro name - * @param params - The macro parameters - * @returns Error message if invalid, undefined if valid or macro is unknown - */ -export function validateMacroParams( - macroName: string, - params: Record -): { valid: boolean; error?: string; known: boolean } { - const config = getMacroConfigMap().get(macroName.toLowerCase()); - - if (!config) { - return { valid: false, known: false }; - } - - // Check required parameters - if (config.requiredParams) { - for (const param of config.requiredParams) { - if (!params[param]) { - return { - valid: false, - known: true, - error: `Missing required parameter: ${param}` - }; - } - } - } - - // Run custom validation if provided - if (config.validate) { - const error = config.validate(params); - if (error) { - return { valid: false, known: true, error }; - } - } - - return { valid: true, known: true }; -} diff --git a/src/main/engine/BlogGenerationOutputService.ts b/src/main/engine/BlogGenerationOutputService.ts index 12314b1..0c6a6e9 100644 --- a/src/main/engine/BlogGenerationOutputService.ts +++ b/src/main/engine/BlogGenerationOutputService.ts @@ -43,11 +43,11 @@ export function urlPathToHtmlIndexPath(htmlDir: string, urlPath: string): string return path.join(htmlDir, normalizedPath.slice(1), 'index.html'); } -export function computeContentHash(content: string): string { +function computeContentHash(content: string): string { return crypto.createHash('sha256').update(content).digest('hex'); } -export function computeBufferHash(content: Buffer): string { +function computeBufferHash(content: Buffer): string { return crypto.createHash('sha256').update(content).digest('hex'); } diff --git a/src/main/engine/EmbeddingEngine.ts b/src/main/engine/EmbeddingEngine.ts index c8b01dd..9dfe17a 100644 --- a/src/main/engine/EmbeddingEngine.ts +++ b/src/main/engine/EmbeddingEngine.ts @@ -46,6 +46,8 @@ export interface DuplicatePair { export interface EmbeddingEngineDeps { /** Return the path to the USearch index file for a project */ getIndexPath: (projectId: string) => string; + /** Writable directory for caching downloaded models (must be outside app.asar) */ + modelCacheDir: string; /** Create the embedding pipeline (dependency-injected for tests) */ createPipeline?: () => Promise; } @@ -104,8 +106,9 @@ export class EmbeddingEngine extends EventEmitter { // Dynamic import to avoid loading heavy ONNX runtime at startup const { pipeline, env } = await import('@huggingface/transformers'); - // Configure cache for Electron -- use ~/.cache/huggingface + // Configure cache for Electron -- point to writable userData dir (not app.asar) env.useFSCache = true; + env.cacheDir = this.deps.modelCacheDir; const extractor = await pipeline('feature-extraction', this.MODEL_ID, { dtype: 'fp32', diff --git a/src/main/engine/MetaEngine.ts b/src/main/engine/MetaEngine.ts index ee04d77..05b9a6a 100644 --- a/src/main/engine/MetaEngine.ts +++ b/src/main/engine/MetaEngine.ts @@ -144,19 +144,9 @@ function normalizeProjectMetadata(metadata: ProjectMetadata): ProjectMetadata { /** * Default categories for new projects (from VISION.md) */ -export const DEFAULT_CATEGORIES = ['article', 'picture', 'aside', 'page']; +const DEFAULT_CATEGORIES = ['article', 'picture', 'aside', 'page']; -export function getDefaultCategorySettings(): Record { - const defaults = getDefaultCategoryMetadata(); - return Object.fromEntries( - Object.entries(defaults).map(([category, value]) => [ - category, - { renderInLists: value.renderInLists, showTitle: value.showTitle }, - ]), - ); -} - -export function getDefaultCategoryMetadata(): Record { +function getDefaultCategoryMetadata(): Record { return { article: { renderInLists: true, showTitle: true, title: 'article' }, picture: { renderInLists: true, showTitle: true, title: 'picture' }, diff --git a/src/main/engine/PageRenderer.ts b/src/main/engine/PageRenderer.ts index a22558e..b494faf 100644 --- a/src/main/engine/PageRenderer.ts +++ b/src/main/engine/PageRenderer.ts @@ -244,7 +244,7 @@ export interface TagUsageEntry { export type TagCloudOrientationMode = 'horizontal' | 'mixed-hv' | 'mixed-diagonal'; -export function normalizeTagCloudOrientation(value: string | undefined): TagCloudOrientationMode { +function normalizeTagCloudOrientation(value: string | undefined): TagCloudOrientationMode { const normalized = (value || '').trim().toLowerCase(); if (normalized === 'mixed_hv' || normalized === 'mixed-hv' || normalized === 'hv' || normalized === 'horizontal_vertical') { @@ -376,7 +376,7 @@ export function resolvePageTitle(metadata: { description?: string; name?: string return 'Blog Preview'; } -export function escapeHtml(value: string): string { +function escapeHtml(value: string): string { return value .replace(/&/g, '&') .replace(/ { +function parseMacroParams(paramString: string | undefined): Record { if (!paramString) return {}; const params: Record = {}; @@ -399,7 +399,7 @@ export function parseMacroParams(paramString: string | undefined): Record, ): Array<{ year: number; month: number; media: MediaData[] }> { @@ -580,7 +580,7 @@ export function buildPhotoArchiveBuckets( return orderedBuckets; } -export function renderGalleryMacro( +function renderGalleryMacro( params: Record, postId: string, mediaItems: MediaData[], @@ -621,7 +621,7 @@ export function renderGalleryMacro( }); } -export function renderPhotoArchiveMacro( +function renderPhotoArchiveMacro( params: Record, mediaItems: MediaData[], renderLanguage: string, @@ -678,7 +678,7 @@ export function renderPhotoArchiveMacro( }); } -export function renderTagCloudMacro(params: Record, tagUsage: TagUsageEntry[], renderLanguage: string): string { +function renderTagCloudMacro(params: Record, tagUsage: TagUsageEntry[], renderLanguage: string): string { const language = resolveRenderLanguageFromProjectPreferences(renderLanguage); const widthParam = parseIntegerParam(params.width); const heightParam = parseIntegerParam(params.height); @@ -727,14 +727,14 @@ export function renderTagCloudMacro(params: Record, tagUsage: Ta }); } -export function isExternalOrSpecialUrl(value: string): boolean { +function isExternalOrSpecialUrl(value: string): boolean { const normalized = value.trim(); if (!normalized) return false; if (normalized.startsWith('#') || normalized.startsWith('//')) return true; return /^[a-z][a-z0-9+.-]*:/i.test(normalized); } -export function splitPathSuffix(value: string): { pathPart: string; suffix: string } { +function splitPathSuffix(value: string): { pathPart: string; suffix: string } { const match = value.match(/^([^?#]*)([?#].*)?$/); return { pathPart: match?.[1] ?? value, @@ -802,7 +802,7 @@ export function normalizePreviewHref(rawHref: string, rewriteContext: HtmlRewrit return rawHref; } -export function normalizePreviewSrc(rawSrc: string, rewriteContext: HtmlRewriteContext): string { +function normalizePreviewSrc(rawSrc: string, rewriteContext: HtmlRewriteContext): string { if (!rawSrc || isExternalOrSpecialUrl(rawSrc)) { return rawSrc; } @@ -891,7 +891,7 @@ export function isBuiltInMacro(name: string): boolean { return JS_BUILTIN_MACROS.has(normalizeMacroName(name)); } -export function serializePostDataForMacro(post: PostData): Record { +function serializePostDataForMacro(post: PostData): Record { return { id: post.id, projectId: post.projectId, @@ -1019,21 +1019,21 @@ export function buildCanonicalPostPath(post: PostData): string { return `/${year}/${month}/${day}/${post.slug}`; } -export function formatArchiveDate(date: Date): string { +function formatArchiveDate(date: Date): string { const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = String(date.getFullYear()); return `${day}.${month}.${year}`; } -export function getArchiveDateKey(date: Date): string { +function getArchiveDateKey(date: Date): string { const year = String(date.getFullYear()); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } -export function toDateParts(date: Date): { day: number; month: number; year: number } { +function toDateParts(date: Date): { day: number; month: number; year: number } { return { day: date.getDate(), month: date.getMonth() + 1, @@ -1041,7 +1041,7 @@ export function toDateParts(date: Date): { day: number; month: number; year: num }; } -export function buildPaginationHref(basePathname: string, page: number): string { +function buildPaginationHref(basePathname: string, page: number): string { const base = basePathname === '/' ? '' : basePathname; if (page <= 1) { return basePathname === '/' ? '/' : `${basePathname}/`; @@ -1072,7 +1072,7 @@ export function mapToRecord(map: Map): Record { return Object.fromEntries(map.entries()); } -export function recordToMap(record: unknown): Map { +function recordToMap(record: unknown): Map { if (!record || typeof record !== 'object') { return new Map(); } diff --git a/src/main/engine/ai/providers.ts b/src/main/engine/ai/providers.ts index 006d3f0..9e54f0f 100644 --- a/src/main/engine/ai/providers.ts +++ b/src/main/engine/ai/providers.ts @@ -24,9 +24,9 @@ import type { ChatModel } from '../../shared/electronApi'; // Constants // --------------------------------------------------------------------------- -export const ZEN_BASE_URL = 'https://opencode.ai/zen/v1'; -export const ZEN_MODELS_URL = 'https://opencode.ai/zen/v1/models'; -export const MISTRAL_MODELS_URL = 'https://api.mistral.ai/v1/models'; +const ZEN_BASE_URL = 'https://opencode.ai/zen/v1'; +const ZEN_MODELS_URL = 'https://opencode.ai/zen/v1/models'; +const MISTRAL_MODELS_URL = 'https://api.mistral.ai/v1/models'; export const OLLAMA_BASE_URL = 'http://localhost:11434/v1'; export const OLLAMA_TAGS_URL = 'http://localhost:11434/api/tags'; export const LMSTUDIO_BASE_URL = 'http://localhost:1234/v1'; diff --git a/src/main/engine/index.ts b/src/main/engine/index.ts deleted file mode 100644 index 685e810..0000000 --- a/src/main/engine/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -export { TaskManager, taskManager, type Task, type TaskProgress, type TaskStatus } from './TaskManager'; -export { PostEngine, type PostData, type PostFilter, type SearchResult, type PaginatedResult, type PaginationOptions } from './PostEngine'; -export { MediaEngine, type MediaData } from './MediaEngine'; -export { PostMediaEngine, type PostMediaLinkData } from './PostMediaEngine'; -export { ProjectEngine, type ProjectData } from './ProjectEngine'; -export { MetaEngine, type ProjectMetadata, DEFAULT_CATEGORIES } from './MetaEngine'; -export { - TagEngine, - type TagData, - type TagWithCount, - type CreateTagInput, - type UpdateTagInput, - type DeleteTagResult, - type MergeTagsResult, - type RenameTagResult, - type SyncTagsResult, -} from './TagEngine'; -export { - stemText, - stemWord, - stemQuery, - prepareForFTS, - getSupportedLanguages, - isoToStemmerLanguage, - type SupportedLanguage, -} from './stemmer'; -export { - ChatEngine, - type ChatConversationData, - type ChatMessageData, - type CreateConversationInput, -} from './ChatEngine'; -export { - WxrParser, - type WxrData, - type WxrPost, - type WxrMedia, - type WxrSiteInfo, - type WxrCategory, - type WxrTag, -} from './WxrParser'; -export { - ImportAnalysisEngine, - type ImportAnalysisReport, - type AnalyzedPost, - type AnalyzedMedia, - type AnalyzedCategory, - type AnalyzedTag, - type PostAnalysisStatus, - type MediaAnalysisStatus, - type ImportConflictResolution, -} from './ImportAnalysisEngine'; -export { - ImportDefinitionEngine, - type ImportDefinitionData, -} from './ImportDefinitionEngine'; -export { - readPostFile, - type PostFileData, -} from './postFileUtils'; -export { - MetadataDiffEngine, - type PostMetadataDiff, - type DiffGroup, - type DiffField, - type ScanResult, - type TableStats, -} from './MetadataDiffEngine'; -export { - GitEngine, - type GitAvailability, - type RepoState, - type GitStatusDto, - type GitDiffDto, - type GitDiffContentDto, - type GitHistoryEntry, - type GitStatusFile, - type GitStatusCounts, - type GitInitResult, -} from './GitEngine'; -export { - BlogGenerationEngine, - resolvePublicBaseUrl, - type BlogGenerationOptions, - type BlogGenerationResult, -} from './BlogGenerationEngine'; -export { - MenuEngine, - type MenuItemData, - type MenuDocument, - type MenuItemKind, -} from './MenuEngine'; -export { - ScriptEngine, - type ScriptData, - type ScriptKind, - type CreateScriptInput, - type UpdateScriptInput, -} from './ScriptEngine'; -export { - PublishEngine, - type PublishCredentials, - type DirectoryUploadResult, -} from './PublishEngine'; diff --git a/src/main/ipc/blogHandlers.ts b/src/main/ipc/blogHandlers.ts index e9d90ee..49415a4 100644 --- a/src/main/ipc/blogHandlers.ts +++ b/src/main/ipc/blogHandlers.ts @@ -245,14 +245,15 @@ export function registerBlogHandlers(safeHandle: SafeHandle, bundle: EngineBundl const seenMediaLang = new Set(); for (let i = 0; i < publishedPosts.length; i++) { const post = publishedPosts[i]; - const postLang = post.language || mainLang; const links = await bundle.postMediaEngine.getLinkedMediaForPost(post.id); for (const link of links) { + const mediaItem = await bundle.mediaEngine.getMedia(link.mediaId); + const mediaLang = mediaItem?.language || mainLang; const mediaTranslations = await bundle.mediaEngine.getMediaTranslations(link.mediaId); const existingLangs = new Set(mediaTranslations.map((t) => t.language)); for (const lang of blogLanguages) { const key = `${link.mediaId}:${lang}`; - if (lang !== postLang && !existingLangs.has(lang) && !seenMediaLang.has(key)) { + if (lang !== mediaLang && !existingLangs.has(lang) && !seenMediaLang.has(key)) { seenMediaLang.add(key); mediaItems.push({ mediaId: link.mediaId, targetLang: lang }); } diff --git a/src/main/ipc/index.ts b/src/main/ipc/index.ts index a30d6d4..5d0c86f 100644 --- a/src/main/ipc/index.ts +++ b/src/main/ipc/index.ts @@ -1,2 +1,2 @@ -export { registerIpcHandlers, registerEventForwarding, startEmbeddingIndexTask, startDuplicateSearchTask, startRebuildEmbeddingIndexTask } from './handlers'; +export { registerIpcHandlers, registerEventForwarding, startEmbeddingIndexTask, startRebuildEmbeddingIndexTask } from './handlers'; export { registerChatHandlers, initializeChatHandlers, cleanupChatHandlers } from './chatHandlers'; diff --git a/src/main/main.ts b/src/main/main.ts index 3f0707b..77336aa 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -943,6 +943,7 @@ app.whenReady().then(async () => { const embeddingEngine = new EmbeddingEngine({ getIndexPath: (projectId: string) => path.join(userData, 'projects', projectId, 'embeddings.usearch'), + modelCacheDir: path.join(userData, 'model-cache'), }); const appApiAdapter = new AppApiAdapter(projectEngine); const publishApiAdapter = new PublishApiAdapter(projectEngine, publishEngine, taskManager); diff --git a/src/main/shared/picoThemes.ts b/src/main/shared/picoThemes.ts index 3b5b6ac..5e56ad6 100644 --- a/src/main/shared/picoThemes.ts +++ b/src/main/shared/picoThemes.ts @@ -23,7 +23,7 @@ export const PICO_THEME_NAMES = [ export type PicoThemeName = (typeof PICO_THEME_NAMES)[number]; export type PicoThemeMode = 'auto' | 'light' | 'dark'; -export function isPicoThemeName(value: unknown): value is PicoThemeName { +function isPicoThemeName(value: unknown): value is PicoThemeName { return typeof value === 'string' && (PICO_THEME_NAMES as readonly string[]).includes(value); } @@ -38,7 +38,7 @@ export function sanitizePicoThemeMode(value: unknown): PicoThemeMode | undefined return undefined; } -export function getPicoStylesheetAssetName(theme: PicoThemeName | undefined): string { +function getPicoStylesheetAssetName(theme: PicoThemeName | undefined): string { if (!theme) { return 'pico.min.css'; } diff --git a/src/main/shared/pythonApiContractV1.ts b/src/main/shared/pythonApiContractV1.ts index 3e539a5..97df09d 100644 --- a/src/main/shared/pythonApiContractV1.ts +++ b/src/main/shared/pythonApiContractV1.ts @@ -517,7 +517,3 @@ export function listPythonApiMethodNames(): string[] { export function getPythonApiMethodContract(methodName: string): PythonApiMethodContractV1 | undefined { return BDS_PYTHON_API_CONTRACT_V1.methods.find((entry) => entry.method === methodName); } - -export function getPythonApiDataStructureContracts(): PythonApiDataStructureContractV1[] { - return BDS_PYTHON_API_CONTRACT_V1.dataStructures; -} diff --git a/src/renderer/a2ui/components/A2UIMindmap.tsx b/src/renderer/a2ui/components/A2UIMindmap.tsx index 00acca9..20f7061 100644 --- a/src/renderer/a2ui/components/A2UIMindmap.tsx +++ b/src/renderer/a2ui/components/A2UIMindmap.tsx @@ -50,8 +50,8 @@ function getNodeColor(depth: number): string { /* ── Constants ──────────────────────────────────────────────── */ -export const FONT_SIZE = 13; -export const CHAR_WIDTH = 7.8; +const FONT_SIZE = 13; +const CHAR_WIDTH = 7.8; export const LINE_HEIGHT = 18; const NODE_PADDING_X = 14; const NODE_PADDING_Y = 8; diff --git a/src/renderer/a2ui/components/index.ts b/src/renderer/a2ui/components/index.ts deleted file mode 100644 index ff10c96..0000000 --- a/src/renderer/a2ui/components/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { A2UIText } from './A2UIText'; -export { A2UIButton } from './A2UIButton'; -export { A2UICard } from './A2UICard'; -export { A2UIChart } from './A2UIChart'; -export { A2UITable } from './A2UITable'; -export { A2UIForm } from './A2UIForm'; -export { A2UITextField } from './A2UITextField'; -export { A2UICheckBox } from './A2UICheckBox'; -export { A2UIDateTimeInput } from './A2UIDateTimeInput'; -export { A2UIChoicePicker } from './A2UIChoicePicker'; -export { A2UIImage } from './A2UIImage'; -export { A2UITabs } from './A2UITabs'; -export { A2UIMetric } from './A2UIMetric'; -export { A2UIList } from './A2UIList'; -export { A2UIRow } from './A2UIRow'; -export { A2UIColumn } from './A2UIColumn'; -export { A2UIDivider } from './A2UIDivider'; diff --git a/src/renderer/components/AssistantSidebar/AssistantSidebar.tsx b/src/renderer/components/AssistantSidebar/AssistantSidebar.tsx index 5e706b3..264376b 100644 --- a/src/renderer/components/AssistantSidebar/AssistantSidebar.tsx +++ b/src/renderer/components/AssistantSidebar/AssistantSidebar.tsx @@ -302,5 +302,3 @@ export const AssistantSidebar: React.FC = () => { ); }; - -export default AssistantSidebar; diff --git a/src/renderer/components/Lightbox/Lightbox.tsx b/src/renderer/components/Lightbox/Lightbox.tsx index 2737405..9239356 100644 --- a/src/renderer/components/Lightbox/Lightbox.tsx +++ b/src/renderer/components/Lightbox/Lightbox.tsx @@ -171,62 +171,3 @@ export function useMarkdownImages(content: string): LightboxImage[] { }, [content]); } -// Component to render images with lightbox support -interface ImageGalleryProps { - images: LightboxImage[]; -} - -export const ImageGallery: React.FC = ({ images }) => { - const [lightboxOpen, setLightboxOpen] = useState(false); - const [selectedIndex, setSelectedIndex] = useState(0); - - if (images.length === 0) { - return null; - } - - const openLightbox = (index: number) => { - setSelectedIndex(index); - setLightboxOpen(true); - }; - - if (images.length === 1) { - return ( - <> -
openLightbox(0)}> - {images[0].alt - {images[0].caption &&

{images[0].caption}

} -
- setLightboxOpen(false)} - /> - - ); - } - - return ( - <> -
- {images.map((image, index) => ( -
openLightbox(index)} - > - {image.alt -
- ))} -
- setLightboxOpen(false)} - /> - - ); -}; - -export default Lightbox; diff --git a/src/renderer/components/Lightbox/index.ts b/src/renderer/components/Lightbox/index.ts index cbb86a9..497ad2a 100644 --- a/src/renderer/components/Lightbox/index.ts +++ b/src/renderer/components/Lightbox/index.ts @@ -1 +1 @@ -export { Lightbox, ImageGallery, useMarkdownImages } from './Lightbox'; +export { Lightbox, useMarkdownImages } from './Lightbox'; diff --git a/src/renderer/components/LinkedMediaPanel/LinkedMediaPanel.tsx b/src/renderer/components/LinkedMediaPanel/LinkedMediaPanel.tsx index caa22d1..86978ec 100644 --- a/src/renderer/components/LinkedMediaPanel/LinkedMediaPanel.tsx +++ b/src/renderer/components/LinkedMediaPanel/LinkedMediaPanel.tsx @@ -345,5 +345,3 @@ export const LinkedMediaPanel: React.FC = ({ ); }; - -export default LinkedMediaPanel; diff --git a/src/renderer/components/LinkedMediaPanel/index.ts b/src/renderer/components/LinkedMediaPanel/index.ts index 57ec9c9..31ea8c2 100644 --- a/src/renderer/components/LinkedMediaPanel/index.ts +++ b/src/renderer/components/LinkedMediaPanel/index.ts @@ -1,2 +1 @@ export { LinkedMediaPanel } from './LinkedMediaPanel'; -export { default } from './LinkedMediaPanel'; diff --git a/src/renderer/components/MilkdownEditor/MilkdownEditor.tsx b/src/renderer/components/MilkdownEditor/MilkdownEditor.tsx index 49e3356..847fbe3 100644 --- a/src/renderer/components/MilkdownEditor/MilkdownEditor.tsx +++ b/src/renderer/components/MilkdownEditor/MilkdownEditor.tsx @@ -391,5 +391,3 @@ const MilkdownProviderInner: React.FC = ({ ); }; - -export default MilkdownEditor; diff --git a/src/renderer/components/PostLinks/PostLinks.tsx b/src/renderer/components/PostLinks/PostLinks.tsx index 82add03..d0c8b09 100644 --- a/src/renderer/components/PostLinks/PostLinks.tsx +++ b/src/renderer/components/PostLinks/PostLinks.tsx @@ -116,5 +116,3 @@ export const PostLinks: React.FC = ({ postId, onPostClick, updat ); }; - -export default PostLinks; diff --git a/src/renderer/components/PostLinks/index.ts b/src/renderer/components/PostLinks/index.ts index f9dd49e..19b1cfa 100644 --- a/src/renderer/components/PostLinks/index.ts +++ b/src/renderer/components/PostLinks/index.ts @@ -1,2 +1 @@ export { PostLinks } from './PostLinks'; -export { default } from './PostLinks'; diff --git a/src/renderer/components/PostSearchModal/PostSearchModal.css b/src/renderer/components/PostSearchModal/PostSearchModal.css deleted file mode 100644 index fadfbbb..0000000 --- a/src/renderer/components/PostSearchModal/PostSearchModal.css +++ /dev/null @@ -1,130 +0,0 @@ -.post-search-modal-backdrop { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.6); - display: flex; - align-items: center; - justify-content: center; - z-index: 10000; -} - -.post-search-modal { - background: var(--color-bg-secondary, #1e1e1e); - border: 1px solid var(--color-border, #3c3c3c); - border-radius: 8px; - width: 600px; - max-height: 500px; - display: flex; - flex-direction: column; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); -} - -.post-search-header { - border-bottom: 1px solid var(--color-border, #3c3c3c); -} - -.post-search-input { - width: 100%; - padding: 16px 20px; - font-size: 16px; - background: transparent; - border: none; - color: var(--color-text, #ccc); - outline: none; - font-family: inherit; -} - -.post-search-input::placeholder { - color: var(--color-text-muted, #888); -} - -.post-search-results { - flex: 1; - overflow-y: auto; - padding: 8px; - min-height: 200px; -} - -.post-search-loading, -.post-search-empty { - display: flex; - align-items: center; - justify-content: center; - padding: 40px 20px; - color: var(--color-text-muted, #888); - font-size: 14px; - text-align: center; -} - -.post-search-result-item { - padding: 12px 16px; - border-radius: 4px; - cursor: pointer; - margin-bottom: 4px; - transition: background-color 0.15s ease; -} - -.post-search-result-item:hover, -.post-search-result-item.selected { - background: var(--color-bg-tertiary, #2a2a2a); -} - -.post-search-result-item.selected { - border-left: 3px solid var(--color-primary, #0e639c); - padding-left: 13px; -} - -.post-search-result-title { - font-size: 14px; - font-weight: 600; - color: var(--color-text, #fff); - margin-bottom: 4px; -} - -.post-search-result-excerpt { - font-size: 12px; - color: var(--color-text-muted, #888); - line-height: 1.4; - margin-bottom: 4px; -} - -.post-search-result-slug { - font-size: 11px; - color: var(--color-text-muted, #666); - font-family: 'Cascadia Code', 'Consolas', 'Courier New', monospace; -} - -.post-search-footer { - border-top: 1px solid var(--color-border, #3c3c3c); - padding: 8px 16px; - display: flex; - justify-content: center; -} - -.post-search-hint { - font-size: 11px; - color: var(--color-text-muted, #888); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* Scrollbar styling */ -.post-search-results::-webkit-scrollbar { - width: 8px; -} - -.post-search-results::-webkit-scrollbar-track { - background: var(--color-bg-secondary, #1e1e1e); -} - -.post-search-results::-webkit-scrollbar-thumb { - background: var(--color-border, #3c3c3c); - border-radius: 4px; -} - -.post-search-results::-webkit-scrollbar-thumb:hover { - background: var(--color-text-muted, #555); -} diff --git a/src/renderer/components/PostSearchModal/PostSearchModal.tsx b/src/renderer/components/PostSearchModal/PostSearchModal.tsx deleted file mode 100644 index d9db0a1..0000000 --- a/src/renderer/components/PostSearchModal/PostSearchModal.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { useI18n } from '../../i18n'; -import './PostSearchModal.css'; - -interface SearchResult { - id: string; - title: string; - slug: string; - excerpt?: string; -} - -interface PostSearchModalProps { - onSelect: (post: SearchResult) => void; - onClose: () => void; - initialQuery?: string; -} - -export const PostSearchModal: React.FC = ({ - onSelect, - onClose, - initialQuery = '' -}) => { - const { t } = useI18n(); - const [query, setQuery] = useState(initialQuery); - const [results, setResults] = useState([]); - const [selectedIndex, setSelectedIndex] = useState(0); - const [isSearching, setIsSearching] = useState(false); - const inputRef = useRef(null); - - // Focus search input on mount - useEffect(() => { - inputRef.current?.focus(); - }, []); - - // Debounced search effect - useEffect(() => { - if (query.length < 2) { - setResults([]); - setSelectedIndex(0); - return; - } - - const timeoutId = setTimeout(async () => { - setIsSearching(true); - try { - const searchResults = await window.electronAPI.posts.search(query); - setResults(searchResults || []); - setSelectedIndex(0); - } catch (error) { - console.error('Search failed:', error); - setResults([]); - } finally { - setIsSearching(false); - } - }, 300); - - return () => clearTimeout(timeoutId); - }, [query]); - - // Keyboard navigation handler - const handleKeyDown = useCallback((e: React.KeyboardEvent) => { - switch (e.key) { - case 'Escape': - e.preventDefault(); - onClose(); - break; - case 'ArrowDown': - e.preventDefault(); - setSelectedIndex(prev => Math.min(prev + 1, results.length - 1)); - break; - case 'ArrowUp': - e.preventDefault(); - setSelectedIndex(prev => Math.max(prev - 1, 0)); - break; - case 'Enter': - e.preventDefault(); - if (results[selectedIndex]) { - onSelect(results[selectedIndex]); - } - break; - } - }, [results, selectedIndex, onClose, onSelect]); - - // Backdrop click handler - const handleBackdropClick = useCallback((e: React.MouseEvent) => { - if (e.target === e.currentTarget) { - onClose(); - } - }, [onClose]); - - // Result click handler - const handleResultClick = useCallback((post: SearchResult) => { - onSelect(post); - }, [onSelect]); - - // Scroll selected item into view - useEffect(() => { - const selectedElement = document.querySelector('.post-search-result-item.selected'); - if (selectedElement) { - selectedElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); - } - }, [selectedIndex]); - - return ( -
-
-
- setQuery(e.target.value)} - autoComplete="off" - /> -
- -
- {isSearching && ( -
- {t('postSearch.searching')} -
- )} - - {!isSearching && query.length < 2 && ( -
- {t('postSearch.typeMore')} -
- )} - - {!isSearching && query.length >= 2 && results.length === 0 && ( -
- {t('postSearch.noResults', { query })} -
- )} - - {!isSearching && results.length > 0 && results.map((post, index) => ( -
handleResultClick(post)} - onMouseEnter={() => setSelectedIndex(index)} - > -
{post.title}
- {post.excerpt && ( -
- {post.excerpt.length > 120 - ? post.excerpt.substring(0, 120) + '...' - : post.excerpt} -
- )} -
/posts/{post.slug}
-
- ))} -
- -
- - {t('postSearch.hint')} - -
-
-
- ); -}; diff --git a/src/renderer/components/PostSearchModal/index.ts b/src/renderer/components/PostSearchModal/index.ts deleted file mode 100644 index 90b48b3..0000000 --- a/src/renderer/components/PostSearchModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { PostSearchModal } from './PostSearchModal'; diff --git a/src/renderer/components/ProjectSelector/ProjectSelector.tsx b/src/renderer/components/ProjectSelector/ProjectSelector.tsx index 8b0f748..9ad6f9a 100644 --- a/src/renderer/components/ProjectSelector/ProjectSelector.tsx +++ b/src/renderer/components/ProjectSelector/ProjectSelector.tsx @@ -387,5 +387,3 @@ export const ProjectSelector: React.FC = () => { ); }; - -export default ProjectSelector; diff --git a/src/renderer/components/ProjectSelector/index.ts b/src/renderer/components/ProjectSelector/index.ts index a1c3b7d..2417124 100644 --- a/src/renderer/components/ProjectSelector/index.ts +++ b/src/renderer/components/ProjectSelector/index.ts @@ -1,2 +1 @@ export { ProjectSelector } from './ProjectSelector'; -export { default } from './ProjectSelector'; diff --git a/src/renderer/components/ResizablePanel/ResizablePanel.tsx b/src/renderer/components/ResizablePanel/ResizablePanel.tsx index a9d8ad1..8257a7c 100644 --- a/src/renderer/components/ResizablePanel/ResizablePanel.tsx +++ b/src/renderer/components/ResizablePanel/ResizablePanel.tsx @@ -119,5 +119,3 @@ export const ResizablePanel: React.FC = ({ ); }; - -export default ResizablePanel; diff --git a/src/renderer/components/SettingsView/SettingsView.tsx b/src/renderer/components/SettingsView/SettingsView.tsx index bc732fa..96d8874 100644 --- a/src/renderer/components/SettingsView/SettingsView.tsx +++ b/src/renderer/components/SettingsView/SettingsView.tsx @@ -2246,5 +2246,3 @@ export const SettingsView: React.FC = () => { ); }; - -export default SettingsView; diff --git a/src/renderer/components/SettingsView/index.ts b/src/renderer/components/SettingsView/index.ts index 6b25c6e..686c3d8 100644 --- a/src/renderer/components/SettingsView/index.ts +++ b/src/renderer/components/SettingsView/index.ts @@ -1,2 +1 @@ -export { SettingsView, scrollToSettingsSection } from './SettingsView'; -export type { SettingsCategory } from './SettingsView'; +export { SettingsView } from './SettingsView'; diff --git a/src/renderer/components/StyleView/StyleView.tsx b/src/renderer/components/StyleView/StyleView.tsx index 6d570fd..e945809 100644 --- a/src/renderer/components/StyleView/StyleView.tsx +++ b/src/renderer/components/StyleView/StyleView.tsx @@ -136,5 +136,3 @@ export const StyleView: React.FC = () => { ); }; - -export default StyleView; diff --git a/src/renderer/components/StyleView/index.ts b/src/renderer/components/StyleView/index.ts deleted file mode 100644 index 554804a..0000000 --- a/src/renderer/components/StyleView/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { StyleView } from './StyleView'; diff --git a/src/renderer/components/TabBar/TabBar.tsx b/src/renderer/components/TabBar/TabBar.tsx index 4fc709f..4829427 100644 --- a/src/renderer/components/TabBar/TabBar.tsx +++ b/src/renderer/components/TabBar/TabBar.tsx @@ -839,5 +839,3 @@ export const TabBar: React.FC = () => { ); }; - -export default TabBar; diff --git a/src/renderer/components/TaskPopup/TaskPopup.tsx b/src/renderer/components/TaskPopup/TaskPopup.tsx index ce67199..8dc41b0 100644 --- a/src/renderer/components/TaskPopup/TaskPopup.tsx +++ b/src/renderer/components/TaskPopup/TaskPopup.tsx @@ -221,5 +221,3 @@ export const TaskPopup: React.FC = () => { ); }; - -export default TaskPopup; diff --git a/src/renderer/components/TaskPopup/index.ts b/src/renderer/components/TaskPopup/index.ts deleted file mode 100644 index ceee7d9..0000000 --- a/src/renderer/components/TaskPopup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { TaskPopup } from './TaskPopup'; diff --git a/src/renderer/components/Toast/Toast.tsx b/src/renderer/components/Toast/Toast.tsx index 13d82d8..08b4cbd 100644 --- a/src/renderer/components/Toast/Toast.tsx +++ b/src/renderer/components/Toast/Toast.tsx @@ -2,11 +2,8 @@ import React from 'react'; import { Toaster, toast } from 'react-hot-toast'; import './Toast.css'; -// Re-export toast for use throughout the app -export { toast }; - // Toast types -export type ToastType = 'success' | 'error' | 'loading' | 'info'; +type ToastType = 'success' | 'error' | 'loading' | 'info'; // Custom toast functions export const showToast = { @@ -84,5 +81,3 @@ export const ToastContainer: React.FC = () => { /> ); }; - -export default ToastContainer; diff --git a/src/renderer/components/Toast/index.ts b/src/renderer/components/Toast/index.ts index ae4c8ee..206fb7b 100644 --- a/src/renderer/components/Toast/index.ts +++ b/src/renderer/components/Toast/index.ts @@ -1 +1 @@ -export { ToastContainer, toast, showToast, type ToastType } from './Toast'; +export { ToastContainer, showToast } from './Toast'; diff --git a/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx b/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx index e86815a..dc44bc5 100644 --- a/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx +++ b/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx @@ -505,6 +505,4 @@ export const WindowTitleBar: React.FC = () => { )} ); -}; - -export default WindowTitleBar; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/renderer/components/index.ts b/src/renderer/components/index.ts index 1fc5f2d..0aa7ec6 100644 --- a/src/renderer/components/index.ts +++ b/src/renderer/components/index.ts @@ -4,26 +4,7 @@ export { Editor } from './Editor'; export { StatusBar } from './StatusBar'; export { Panel } from './Panel'; export { TabBar } from './TabBar'; -export { ToastContainer, toast, showToast, type ToastType } from './Toast'; -export { ProjectSelector } from './ProjectSelector'; -export { MilkdownEditor } from './MilkdownEditor'; -export { Lightbox, ImageGallery, useMarkdownImages } from './Lightbox'; -export { TaskPopup } from './TaskPopup'; +export { ToastContainer, showToast } from './Toast'; export { ResizablePanel } from './ResizablePanel'; -export { SettingsView } from './SettingsView'; -export { StyleView } from './StyleView'; -export { TagsView, scrollToTagsSection, type TagsCategory } from './TagsView'; -export { TagInput } from './TagInput'; -export { PostLinks } from './PostLinks'; -export { LinkedMediaPanel } from './LinkedMediaPanel'; -export { ErrorModal, type ErrorDetails } from './ErrorModal'; -export { ConfirmDeleteModal, type ConfirmDeleteDetails, type DeleteReference } from './ConfirmDeleteModal'; -export { AISuggestionsModal, type AISuggestions, type CurrentValues } from './AISuggestionsModal/AISuggestionsModal'; -export { ChatPanel } from './ChatPanel'; -export { ImportAnalysisView } from './ImportAnalysisView'; -export { InsertModal } from './InsertModal'; export { WindowTitleBar } from './WindowTitleBar'; -export { DocumentationView } from './DocumentationView/DocumentationView'; -export { SiteValidationView } from './SiteValidationView'; -export { ScriptsView } from './ScriptsView/ScriptsView'; export { AssistantSidebar } from './AssistantSidebar'; diff --git a/src/renderer/i18n/index.tsx b/src/renderer/i18n/index.tsx index fd52a30..bf23b75 100644 --- a/src/renderer/i18n/index.tsx +++ b/src/renderer/i18n/index.tsx @@ -9,7 +9,7 @@ export type UiLanguage = 'en' | 'de' | 'fr' | 'it' | 'es'; export const UI_LANGUAGE_STORAGE_KEY = 'bds-ui-language'; -export const SUPPORTED_UI_LANGUAGES: UiLanguage[] = ['en', 'de', 'fr', 'it', 'es']; +const SUPPORTED_UI_LANGUAGES: UiLanguage[] = ['en', 'de', 'fr', 'it', 'es']; type TranslationTable = Record; diff --git a/src/renderer/macros/definitions/gallery.ts b/src/renderer/macros/definitions/gallery.ts index b0648ed..75adda4 100644 --- a/src/renderer/macros/definitions/gallery.ts +++ b/src/renderer/macros/definitions/gallery.ts @@ -74,5 +74,3 @@ const galleryMacro: MacroDefinition = { // Self-register registerMacro(galleryMacro); - -export default galleryMacro; diff --git a/src/renderer/macros/definitions/photo_archive.ts b/src/renderer/macros/definitions/photo_archive.ts index 8e9d3dc..7d4d978 100644 --- a/src/renderer/macros/definitions/photo_archive.ts +++ b/src/renderer/macros/definitions/photo_archive.ts @@ -34,7 +34,7 @@ function getMonthName(month: number): string { return MONTH_NAMES[month - 1] || 'Unknown'; } -const photoArchiveMacro: MacroDefinition = { +export const photoArchiveMacro: MacroDefinition = { name: 'photo_archive', description: 'Creates a photo archive gallery organized by year and month', @@ -125,5 +125,3 @@ const photoArchiveMacro: MacroDefinition = { // Self-register registerMacro(photoArchiveMacro); -export default photoArchiveMacro; -export { getMonthName, MONTH_NAMES }; diff --git a/src/renderer/macros/definitions/vimeo.ts b/src/renderer/macros/definitions/vimeo.ts index 6b580cd..18dd9d8 100644 --- a/src/renderer/macros/definitions/vimeo.ts +++ b/src/renderer/macros/definitions/vimeo.ts @@ -72,5 +72,3 @@ const vimeoMacro: MacroDefinition = { // Self-register registerMacro(vimeoMacro); - -export default vimeoMacro; diff --git a/src/renderer/macros/definitions/youtube.ts b/src/renderer/macros/definitions/youtube.ts index 68896e6..40900b6 100644 --- a/src/renderer/macros/definitions/youtube.ts +++ b/src/renderer/macros/definitions/youtube.ts @@ -85,5 +85,3 @@ const youtubeMacro: MacroDefinition = { // Self-register registerMacro(youtubeMacro); - -export default youtubeMacro; diff --git a/src/renderer/macros/index.ts b/src/renderer/macros/index.ts index 0f26827..c1b2dce 100644 --- a/src/renderer/macros/index.ts +++ b/src/renderer/macros/index.ts @@ -1,13 +1,13 @@ /** * Macros Module - * + * * Provides a simple extension system for rendering custom content blocks * in markdown using [[macro param="value"]] syntax. - * + * * Usage: * 1. Import this module to register all macros * 2. Use the registry functions to render macros - * + * * Adding new macros: * 1. Create a file in ./definitions/ (e.g., myMacro.ts) * 2. Implement MacroDefinition interface @@ -18,31 +18,8 @@ // Import all macro definitions so they register import './definitions'; -// Re-export types -export type { - MacroDefinition, - MacroParams, - MacroRenderContext, - ParsedMacro, - PythonMacroInfo, - PythonMacroResolver, - PythonMacroRendererFn, -} from './types'; - -// Re-export registry functions +// Re-export registry functions used by app export { - registerMacro, - getMacro, - hasMacro, - getMacroNames, - getAllMacros, - clearMacros, - parseParams, - parseMacros, - renderMacro, - renderAllMacros, - getEditorPreview, - setPythonMacroResolver, refreshPythonMacroSlugs, } from './registry'; diff --git a/src/renderer/navigation/assistantPanelSpec.ts b/src/renderer/navigation/assistantPanelSpec.ts deleted file mode 100644 index cf82fa9..0000000 --- a/src/renderer/navigation/assistantPanelSpec.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { z } from 'zod'; - -const textElementSchema = z.object({ - type: z.literal('text'), - text: z.string().min(1), -}); - -const metricElementSchema = z.object({ - type: z.literal('metric'), - label: z.string().min(1), - value: z.string().min(1), -}); - -const listElementSchema = z.object({ - type: z.literal('list'), - title: z.string().optional(), - items: z.array(z.string().min(1)).min(1), -}); - -const tableElementSchema = z.object({ - type: z.literal('table'), - columns: z.array(z.string().min(1)).min(1), - rows: z.array(z.array(z.string())).min(1), -}); - -const actionElementSchema = z.object({ - type: z.literal('action'), - label: z.string().min(1), - action: z.string().min(1), - payload: z.record(z.string(), z.unknown()).optional(), -}); - -const segmentSchema = z.object({ - label: z.string().min(1), - value: z.number(), -}); - -const chartElementSchema = z.object({ - type: z.literal('chart'), - chartType: z.enum(['bar', 'stacked-bar', 'line', 'area', 'pie', 'donut', 'heatmap']), - title: z.string().min(1).optional(), - series: z.array( - z.object({ - label: z.string().min(1), - value: z.number(), - segments: z.array(segmentSchema).optional(), - }), - ).min(1), -}); - -const inputTypeSchema = z.enum(['text', 'textarea', 'select', 'checkbox', 'date', 'number']); - -const inputOptionSchema = z.object({ - label: z.string().min(1), - value: z.string(), -}); - -const inputElementSchema = z.object({ - type: z.literal('input'), - key: z.string().min(1), - label: z.string().min(1), - inputType: inputTypeSchema, - placeholder: z.string().optional(), - defaultValue: z.union([z.string(), z.number(), z.boolean()]).optional(), - options: z.array(inputOptionSchema).optional(), - action: z.string().min(1).optional(), - submitLabel: z.string().min(1).optional(), - payload: z.record(z.string(), z.unknown()).optional(), -}); - -const datePickerElementSchema = z.object({ - type: z.literal('datePicker'), - key: z.string().min(1), - label: z.string().min(1), - defaultValue: z.string().optional(), - min: z.string().optional(), - max: z.string().optional(), - action: z.string().min(1).optional(), - submitLabel: z.string().min(1).optional(), - payload: z.record(z.string(), z.unknown()).optional(), -}); - -const formFieldSchema = z.object({ - key: z.string().min(1), - label: z.string().min(1), - inputType: inputTypeSchema, - placeholder: z.string().optional(), - defaultValue: z.union([z.string(), z.number(), z.boolean()]).optional(), - options: z.array(inputOptionSchema).optional(), - required: z.boolean().optional(), -}); - -const formElementSchema = z.object({ - type: z.literal('form'), - formId: z.string().min(1), - title: z.string().optional(), - submitLabel: z.string().min(1), - action: z.string().min(1), - payload: z.record(z.string(), z.unknown()).optional(), - fields: z.array(formFieldSchema).min(1), -}); - -const cardActionSchema = z.object({ - label: z.string().min(1), - action: z.string().min(1), - payload: z.record(z.string(), z.unknown()).optional(), -}); - -const cardElementSchema = z.object({ - type: z.literal('card'), - title: z.string().min(1), - body: z.string().min(1), - subtitle: z.string().optional(), - actions: z.array(cardActionSchema).optional(), -}); - -const imageElementSchema = z.object({ - type: z.literal('image'), - src: z.string().min(1), - alt: z.string().optional(), - caption: z.string().optional(), - action: z.string().min(1).optional(), - payload: z.record(z.string(), z.unknown()).optional(), -}); - -let assistantPanelElementSchemaRef: z.ZodTypeAny; - -const tabsElementSchema: z.ZodTypeAny = z.lazy(() => z.object({ - type: z.literal('tabs'), - widgetId: z.string().min(1).optional(), - defaultTabId: z.string().min(1).optional(), - tabs: z.array( - z.object({ - id: z.string().min(1), - label: z.string().min(1), - elements: z.array(assistantPanelElementSchemaRef).min(1), - }), - ).min(1), -})); - -assistantPanelElementSchemaRef = z.union([ - textElementSchema, - metricElementSchema, - listElementSchema, - tableElementSchema, - actionElementSchema, - chartElementSchema, - inputElementSchema, - formElementSchema, - datePickerElementSchema, - cardElementSchema, - imageElementSchema, - tabsElementSchema, -]); - -export const assistantPanelElementSchema = assistantPanelElementSchemaRef; - -export const assistantPanelSpecSchema = z.object({ - specVersion: z.literal('1'), - elements: z.array(assistantPanelElementSchema).min(1), -}); - -export type AssistantPanelElement = z.infer; -export type AssistantPanelSpec = z.infer; diff --git a/src/renderer/navigation/tabPolicy.ts b/src/renderer/navigation/tabPolicy.ts index 3bb7e19..d013282 100644 --- a/src/renderer/navigation/tabPolicy.ts +++ b/src/renderer/navigation/tabPolicy.ts @@ -133,11 +133,11 @@ export function openTemplateTab( openTab(getTemplateTabSpec(templateId, intent)); } -export function getGitDiffFileTabId(filePath: string): string { +function getGitDiffFileTabId(filePath: string): string { return `git-diff:${filePath}`; } -export function getGitDiffCommitTabId(commitHash: string): string { +function getGitDiffCommitTabId(commitHash: string): string { return `git-diff:commit:${commitHash}`; } diff --git a/src/renderer/plugins/imageResolverPlugin.ts b/src/renderer/plugins/imageResolverPlugin.ts index c70f5a6..ab35a43 100644 --- a/src/renderer/plugins/imageResolverPlugin.ts +++ b/src/renderer/plugins/imageResolverPlugin.ts @@ -147,5 +147,3 @@ export const imageResolverPlugin = $prose(() => { }, }); }); - -export default imageResolverPlugin; diff --git a/src/renderer/plugins/macroPlugin.ts b/src/renderer/plugins/macroPlugin.ts index c3309fb..e8f84d6 100644 --- a/src/renderer/plugins/macroPlugin.ts +++ b/src/renderer/plugins/macroPlugin.ts @@ -84,12 +84,12 @@ const remarkMacroParser: Plugin<[], Root> = () => { /** * Remark plugin registration for Milkdown */ -export const remarkMacro = $remark('remarkMacro', () => remarkMacroParser); +const remarkMacro = $remark('remarkMacro', () => remarkMacroParser); /** * ProseMirror node schema for macros */ -export const macroNode = $node('macro', () => ({ +const macroNode = $node('macro', () => ({ group: 'inline', inline: true, atom: true, // Treated as a single unit, not editable as text @@ -154,7 +154,7 @@ export const macroNode = $node('macro', () => ({ * Input rule to convert typed [[macro...]] to macro node * Triggers when user types ]] to close a macro */ -export const macroInputRule = $inputRule(() => { +const macroInputRule = $inputRule(() => { // Match [[macroName param="value"]] when user types the closing ]] return new InputRule( /\[\[(\w+)(?:\s+([^\]]+))?\]\]$/, @@ -185,5 +185,3 @@ export const macroPlugin = [ macroNode, macroInputRule, ].flat(); - -export default macroPlugin; diff --git a/src/renderer/python/pythonApiContractV1.ts b/src/renderer/python/pythonApiContractV1.ts index e74374c..ff53b8e 100644 --- a/src/renderer/python/pythonApiContractV1.ts +++ b/src/renderer/python/pythonApiContractV1.ts @@ -3,7 +3,6 @@ export { BDS_PYTHON_API_CONTRACT_V1, listPythonApiMethodNames, getPythonApiMethodContract, - getPythonApiDataStructureContracts, } from '../../main/shared/pythonApiContractV1'; export type { diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index 0cf9296..8297d59 100644 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -1,7 +1,6 @@ -export { AutoSaveManager, type AutoSaveConfig } from './autoSave'; +export { AutoSaveManager } from './autoSave'; export { getContrastColor } from './color'; -export { unescapeMacroSyntax } from './markdownEscape'; -export { groupPostsByStatus, type GroupedPosts, type PostStatus } from './postGrouping'; +export { groupPostsByStatus } from './postGrouping'; export { loadTabsForProject, saveTabsForProject } from './tabPersistence'; -export { buildTagColorMap, loadTagColorMap } from './tagColors'; +export { loadTagColorMap } from './tagColors'; export { BDS_EVENT_SCRIPTS_CHANGED, BDS_EVENT_TEMPLATES_CHANGED, addWindowEventListener, dispatchWindowEvent, type BdsWindowEventName } from './windowEvents'; diff --git a/tests/engine/EmbeddingEngine.test.ts b/tests/engine/EmbeddingEngine.test.ts index 6d559f5..550a522 100644 --- a/tests/engine/EmbeddingEngine.test.ts +++ b/tests/engine/EmbeddingEngine.test.ts @@ -138,6 +138,7 @@ function createMockPipeline(): EmbeddingPipeline { function makeEngine(tmpDir: string): EmbeddingEngine { return new EmbeddingEngine({ getIndexPath: (projectId: string) => path.join(tmpDir, `${projectId}.usearch`), + modelCacheDir: path.join(tmpDir, 'model-cache'), createPipeline: async () => createMockPipeline(), }); } diff --git a/tests/ipc/handlers.test.ts b/tests/ipc/handlers.test.ts index 5e43f1f..8a80c4b 100644 --- a/tests/ipc/handlers.test.ts +++ b/tests/ipc/handlers.test.ts @@ -339,8 +339,13 @@ vi.mock('fs/promises', () => ({ })); let mockOfflineMode = false; +const mockAutoTranslatePost = vi.fn().mockResolvedValue({ success: true }); +const mockAutoTranslateMediaMetadata = vi.fn().mockResolvedValue({ success: true }); + vi.mock('../../src/main/ipc/chatHandlers', () => ({ isOfflineModeActive: vi.fn(() => mockOfflineMode), + autoTranslatePost: (...args: any[]) => mockAutoTranslatePost(...args), + autoTranslateMediaMetadata: (...args: any[]) => mockAutoTranslateMediaMetadata(...args), })); // Helper to invoke a registered handler @@ -3022,6 +3027,45 @@ describe('IPC Handlers', () => { expect(result).toEqual({ taskStarted: true }); expect(onProgress).toHaveBeenCalledWith(100, 'All translations are up to date'); }); + + it('should use media canonical language, not post language, to determine target languages', async () => { + // Scenario: blog has en + de. An English media item is linked to a German post. + // The media is missing a German translation, NOT an English one. + const mockProject = createMockProject({ id: 'test-project', dataPath: '/mock/data' }); + mockProjectEngine.getActiveProject.mockResolvedValue(mockProject); + mockProjectEngine.getDataDir.mockReturnValue('/mock/data/dir'); + mockMetaEngine.getProjectMetadata.mockResolvedValue({ + mainLanguage: 'de', + blogLanguages: ['de', 'en'], + }); + + const post1 = createMockPost({ id: 'post-1', title: 'German Post', language: 'de', status: 'published' }); + // No posts missing post translations + mockPostEngine.getPostsFiltered.mockImplementation(async (filter: any) => { + if (filter.missingTranslationLanguage) return []; + return [post1]; // all published + }); + + // Post links to an English-language media item + mockPostMediaEngine.getLinkedMediaForPost.mockResolvedValue([{ mediaId: 'media-en-1', sortOrder: 0 }]); + mockMediaEngine.getMedia.mockResolvedValue(createMockMedia({ id: 'media-en-1', language: 'en' })); + mockMediaEngine.getMediaTranslations.mockResolvedValue([]); // no translations yet + + const onProgress = vi.fn(); + let taskDone: Promise | undefined; + mockTaskManager.runTask.mockImplementation((task: any) => { + taskDone = task.execute(onProgress); + return taskDone; + }); + + const result = await invokeHandler('blog:fillMissingTranslations'); + await taskDone; + + expect(result).toEqual({ taskStarted: true }); + // Should translate to German (the missing language), NOT to English (the media's own language) + expect(mockAutoTranslateMediaMetadata).toHaveBeenCalledTimes(1); + expect(mockAutoTranslateMediaMetadata).toHaveBeenCalledWith('media-en-1', 'de'); + }); }); describe('blog:applyValidation', () => { diff --git a/tests/renderer/hardcodedUiLiteralsPhase1.test.ts b/tests/renderer/hardcodedUiLiteralsPhase1.test.ts index 6f61161..1c21c9e 100644 --- a/tests/renderer/hardcodedUiLiteralsPhase1.test.ts +++ b/tests/renderer/hardcodedUiLiteralsPhase1.test.ts @@ -11,15 +11,6 @@ function read(relativePath: string): string { describe('Phase 1 i18n hardcoded literals', () => { it('does not keep known hardcoded user-facing literals in renderer components', () => { const checks: Array<{ file: string; literals: string[] }> = [ - { - file: 'src/renderer/components/PostSearchModal/PostSearchModal.tsx', - literals: [ - 'Search posts by title or content...', - 'Searching...', - 'Type at least 2 characters to search', - 'Use ↑↓ to navigate, Enter to select, Esc to close', - ], - }, { file: 'src/renderer/components/StatusBar/StatusBar.tsx', literals: ['{totalPosts} posts', '{media.length} media', 'Theme: {activeTheme}', 'aria-label="UI language"'], diff --git a/tests/renderer/macros/photo_archive.test.ts b/tests/renderer/macros/photo_archive.test.ts index 7dc1ce7..4469b01 100644 --- a/tests/renderer/macros/photo_archive.test.ts +++ b/tests/renderer/macros/photo_archive.test.ts @@ -8,7 +8,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { clearMacros, getMacro, registerMacro } from '../../../src/renderer/macros/registry'; import type { MacroParams, MacroRenderContext } from '../../../src/renderer/macros/types'; -import photoArchiveMacro from '../../../src/renderer/macros/definitions/photo_archive'; +import { photoArchiveMacro } from '../../../src/renderer/macros/definitions/photo_archive'; describe('photo_archive macro', () => { beforeEach(() => { diff --git a/vite.config.ts b/vite.config.ts index 250fb8f..e6592e9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -32,7 +32,7 @@ export default defineConfig({ return 'react-vendor'; } - if (id.includes('node_modules/zustand') || id.includes('node_modules/date-fns')) { + if (id.includes('node_modules/zustand')) { return 'app-vendor'; } },