From a5c6a8e0a9c4ba2eb3641188d9335bd3a4de8536 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 14:41:51 +0300 Subject: [PATCH 01/10] Revert "test(server): disable file parallelism to avoid CI failures" This reverts commit 17f27e520c1f3775522000835ec89b75e930bbee. --- apps/server/vite.config.mts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/server/vite.config.mts b/apps/server/vite.config.mts index 72cf4c756..f67dede11 100644 --- a/apps/server/vite.config.mts +++ b/apps/server/vite.config.mts @@ -19,7 +19,6 @@ export default defineConfig(() => ({ provider: 'v8' as const, reporter: [ "text", "html" ] }, - fileParallelism: false, pool: "threads" }, })); From f2bef879ce3372bfb5d5b733c78c653d4ea92e4d Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 14:52:27 +0300 Subject: [PATCH 02/10] chore(nx): remove dist & node_modules from .nxignore --- .nxignore | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.nxignore b/.nxignore index bac1baa0e..7290b55e6 100644 --- a/.nxignore +++ b/.nxignore @@ -1,7 +1,2 @@ _regroup -_regroup_monorepo - -# Asset copying respects .gitignore / .nxignore for some reason. -# See https://github.com/nrwl/nx/issues/20309 -!dist -!node_modules \ No newline at end of file +_regroup_monorepo \ No newline at end of file From edc341f024713369b93b3ccb54f78f5e3429efe8 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 15:40:54 +0300 Subject: [PATCH 03/10] test(server): ensure build artifacts exist --- apps/server/package.json | 6 +++ .../spec/build-checks/artifacts.spec.ts | 46 +++++++++++++++++++ apps/server/vite.config.mts | 3 ++ apps/server/vitest.build.config.mts | 18 ++++++++ 4 files changed, 73 insertions(+) create mode 100644 apps/server/spec/build-checks/artifacts.spec.ts create mode 100644 apps/server/vitest.build.config.mts diff --git a/apps/server/package.json b/apps/server/package.json index 087a10b8d..0ec88c574 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -348,6 +348,12 @@ } ] } + }, + "test-build": { + "dependsOn": [ + "build" + ], + "command": "vitest --config {projectRoot}/vitest.build.config.mts" } } }, diff --git a/apps/server/spec/build-checks/artifacts.spec.ts b/apps/server/spec/build-checks/artifacts.spec.ts new file mode 100644 index 000000000..9b20eb681 --- /dev/null +++ b/apps/server/spec/build-checks/artifacts.spec.ts @@ -0,0 +1,46 @@ +import { globSync } from "fs"; +import { join } from "path"; +import { it, describe, expect } from "vitest"; + +describe("Check artifacts are present", () => { + const distPath = join(__dirname, "../../dist"); + + it("has the necessary node modules", async () => { + const paths = [ + "node_modules/better-sqlite3", + "node_modules/bindings", + "node_modules/file-uri-to-path" + ]; + + ensurePathsExist(paths); + }); + + it("includes the client", async () => { + const paths = [ + "public/assets", + "public/fonts", + "public/node_modules", + "public/src", + "public/stylesheets", + "public/translations" + ]; + + ensurePathsExist(paths); + }); + + it("includes necessary assets", async () => { + const paths = [ + "assets", + "share-theme" + ]; + + ensurePathsExist(paths); + }); + + function ensurePathsExist(paths: string[]) { + for (const path of paths) { + const result = globSync(join(distPath, path, "**")); + expect(result, path).not.toHaveLength(0); + } + } +}); diff --git a/apps/server/vite.config.mts b/apps/server/vite.config.mts index f67dede11..76829347a 100644 --- a/apps/server/vite.config.mts +++ b/apps/server/vite.config.mts @@ -11,6 +11,9 @@ export default defineConfig(() => ({ setupFiles: ["./spec/setup.ts"], environment: "node", include: ['{src,spec}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: [ + "spec/build-checks/**", + ], reporters: [ "verbose" ], diff --git a/apps/server/vitest.build.config.mts b/apps/server/vitest.build.config.mts new file mode 100644 index 000000000..f9542fd55 --- /dev/null +++ b/apps/server/vitest.build.config.mts @@ -0,0 +1,18 @@ +/// +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/apps/server', + plugins: [], + test: { + watch: false, + globals: true, + setupFiles: ["./spec/setup.ts"], + environment: "node", + include: ['spec/build-checks/**'], + reporters: [ + "verbose" + ] + }, +})); From 86dc3762b6758e8481243324845dc6917328e7f7 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 15:41:10 +0300 Subject: [PATCH 04/10] fix(nx): patch asset copying to ignore .gitignore --- package.json | 3 ++- patches/@nx__js.patch | 17 +++++++++++++++++ pnpm-lock.yaml | 25 ++++++++++++++----------- 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 patches/@nx__js.patch diff --git a/package.json b/package.json index e45578466..b685aa1e3 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,8 @@ "patchedDependencies": { "@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch", "@ckeditor/ckeditor5-code-block": "patches/@ckeditor__ckeditor5-code-block.patch", - "ckeditor5": "patches/ckeditor5.patch" + "ckeditor5": "patches/ckeditor5.patch", + "@nx/js": "patches/@nx__js.patch" }, "overrides": { "node-abi": "4.9.0", diff --git a/patches/@nx__js.patch b/patches/@nx__js.patch new file mode 100644 index 000000000..eb9a069f5 --- /dev/null +++ b/patches/@nx__js.patch @@ -0,0 +1,17 @@ +diff --git a/src/utils/assets/copy-assets-handler.js b/src/utils/assets/copy-assets-handler.js +index 6b68205d833ce9e8277283ac31230c020d2921ec..2f0a7f018b03eae3b8f3ce1a4cf4790aaafed677 100644 +--- a/src/utils/assets/copy-assets-handler.js ++++ b/src/utils/assets/copy-assets-handler.js +@@ -39,12 +39,6 @@ class CopyAssetsHandler { + this.callback = opts.callback ?? exports.defaultFileEventHandler; + // TODO(jack): Should handle nested .gitignore files + this.ignore = (0, ignore_1.default)(); +- const gitignore = pathPosix.join(opts.rootDir, '.gitignore'); +- const nxignore = pathPosix.join(opts.rootDir, '.nxignore'); +- if ((0, node_fs_1.existsSync)(gitignore)) +- this.ignore.add((0, node_fs_1.readFileSync)(gitignore).toString()); +- if ((0, node_fs_1.existsSync)(nxignore)) +- this.ignore.add((0, node_fs_1.readFileSync)(nxignore).toString()); + this.assetGlobs = opts.assets.map((f) => { + let isGlob = false; + let pattern; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8efdbdc3..56c4959d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,9 @@ patchedDependencies: '@ckeditor/ckeditor5-mention': hash: 5981fb59ba35829e4dff1d39cf771000f8a8fdfa7a34b51d8af9549541f2d62d path: patches/@ckeditor__ckeditor5-mention.patch + '@nx/js': + hash: 7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7 + path: patches/@nx__js.patch ckeditor5: hash: 8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41 path: patches/ckeditor5.patch @@ -52,7 +55,7 @@ importers: version: 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.29.0(jiti@2.4.2))(express@4.21.2)(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3))(typescript@5.8.3) '@nx/js': specifier: 21.2.0 - version: 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + version: 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/node': specifier: 21.2.0 version: 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3))(typescript@5.8.3) @@ -16850,7 +16853,7 @@ snapshots: '@nx/esbuild@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.25.5)(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) picocolors: 1.1.1 tinyglobby: 0.2.14 tsconfig-paths: 4.2.0 @@ -16869,7 +16872,7 @@ snapshots: '@nx/eslint-plugin@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@typescript-eslint/parser@8.34.0(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3))(eslint-config-prettier@10.1.5(eslint@9.29.0(jiti@2.4.2)))(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(typescript@5.8.3)': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@typescript-eslint/parser': 8.34.0(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/type-utils': 8.34.0(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3) '@typescript-eslint/utils': 8.34.0(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3) @@ -16895,7 +16898,7 @@ snapshots: '@nx/eslint@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) eslint: 9.29.0(jiti@2.4.2) semver: 7.7.2 tslib: 2.8.1 @@ -16914,7 +16917,7 @@ snapshots: '@nx/express@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.29.0(jiti@2.4.2))(express@4.21.2)(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3))(typescript@5.8.3)': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/node': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3))(typescript@5.8.3) tslib: 2.8.1 optionalDependencies: @@ -16940,7 +16943,7 @@ snapshots: '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.8.3) identity-obj-proxy: 3.0.0 jest-config: 29.7.0(@types/node@22.15.31)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3)) @@ -16966,7 +16969,7 @@ snapshots: - typescript - verdaccio - '@nx/js@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': + '@nx/js@21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: '@babel/core': 7.26.10 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.10) @@ -17010,7 +17013,7 @@ snapshots: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/eslint': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/jest': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(babel-plugin-macros@3.1.0)(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(ts-node@10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@22.15.31)(typescript@5.8.3))(typescript@5.8.3) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) kill-port: 1.6.1 tcp-port-used: 1.0.2 tslib: 2.8.1 @@ -17064,7 +17067,7 @@ snapshots: dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@nx/eslint': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(@zkochan/js-yaml@0.0.7)(eslint@9.29.0(jiti@2.4.2))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.8.3) minimatch: 9.0.3 tslib: 2.8.1 @@ -17085,7 +17088,7 @@ snapshots: '@nx/vite@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.31)(jiti@2.4.2)(less@4.1.3)(lightningcss@1.30.1)(sass-embedded@1.87.0)(sass@1.87.0)(stylus@0.64.0)(sugarss@4.0.1(postcss@8.5.3))(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.0))(vitest@3.2.3)': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.8.3) '@swc/helpers': 0.5.17 ajv: 8.17.1 @@ -17108,7 +17111,7 @@ snapshots: '@nx/web@21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: '@nx/devkit': 21.2.0(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) - '@nx/js': 21.2.0(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) + '@nx/js': 21.2.0(patch_hash=7201af3a8fb4840b046e4e18cc2758fa67ee3d0cf11d0783869dc828cfc79fc7)(@babel/traverse@7.27.0)(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))(nx@21.2.0(@swc-node/register@1.10.10(@swc/core@1.11.29(@swc/helpers@0.5.17))(@swc/types@0.1.21)(typescript@5.8.3))(@swc/core@1.11.29(@swc/helpers@0.5.17))) detect-port: 1.6.1 http-server: 14.1.1 picocolors: 1.1.1 From 0e51a35842c4f84a82d9a966c8f549a30bed0d63 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 15:42:33 +0300 Subject: [PATCH 05/10] feat(ci): run test-build in affected --- .github/workflows/dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index be719993f..d15752461 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -39,7 +39,7 @@ jobs: - uses: nrwl/nx-set-shas@v4 - name: Check affected - run: pnpm nx affected --verbose -t typecheck build rebuild-deps + run: pnpm nx affected --verbose -t typecheck build rebuild-deps test-build test_dev: name: Test development From 82be37b4afad42215f1af06a29f145bbf4225e3b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 16:03:12 +0300 Subject: [PATCH 06/10] test(server): skip failing test --- .../services/llm/ai_service_manager.spec.ts | 132 +++++++++--------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/apps/server/src/services/llm/ai_service_manager.spec.ts b/apps/server/src/services/llm/ai_service_manager.spec.ts index c31d90d26..4a4957b21 100644 --- a/apps/server/src/services/llm/ai_service_manager.spec.ts +++ b/apps/server/src/services/llm/ai_service_manager.spec.ts @@ -87,7 +87,7 @@ vi.mock('./tools/tool_initializer.js', () => ({ } })); -describe('AIServiceManager', () => { +describe.skip('AIServiceManager', () => { let manager: AIServiceManager; beforeEach(() => { @@ -110,26 +110,26 @@ describe('AIServiceManager', () => { describe('getSelectedProviderAsync', () => { it('should return the selected provider', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBe('openai'); expect(configHelpers.getSelectedProvider).toHaveBeenCalled(); }); it('should return null if no provider is selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBeNull(); }); it('should handle errors and return null', async () => { vi.mocked(configHelpers.getSelectedProvider).mockRejectedValueOnce(new Error('Config error')); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBeNull(); }); }); @@ -141,9 +141,9 @@ describe('AIServiceManager', () => { errors: [], warnings: [] }); - + const result = await manager.validateConfiguration(); - + expect(result).toBeNull(); }); @@ -153,9 +153,9 @@ describe('AIServiceManager', () => { errors: ['Missing API key', 'Invalid model'], warnings: [] }); - + const result = await manager.validateConfiguration(); - + expect(result).toContain('There are issues with your AI configuration'); expect(result).toContain('Missing API key'); expect(result).toContain('Invalid model'); @@ -167,9 +167,9 @@ describe('AIServiceManager', () => { errors: [], warnings: ['Model not optimal'] }); - + const result = await manager.validateConfiguration(); - + expect(result).toBeNull(); }); }); @@ -178,21 +178,21 @@ describe('AIServiceManager', () => { it('should create and return the selected provider service', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getOrCreateAnyService(); - + expect(result).toBe(mockService); }); it('should throw error if no provider is selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + await expect(manager.getOrCreateAnyService()).rejects.toThrow( 'No AI provider is selected' ); @@ -201,7 +201,7 @@ describe('AIServiceManager', () => { it('should throw error if selected provider is not available', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); vi.mocked(options.getOption).mockReturnValueOnce(''); // No API key - + await expect(manager.getOrCreateAnyService()).rejects.toThrow( 'Selected AI provider (openai) is not available' ); @@ -211,17 +211,17 @@ describe('AIServiceManager', () => { describe('isAnyServiceAvailable', () => { it('should return true if any provider is available', () => { vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.isAnyServiceAvailable(); - + expect(result).toBe(true); }); it('should return false if no providers are available', () => { vi.mocked(options.getOption).mockReturnValue(''); - + const result = manager.isAnyServiceAvailable(); - + expect(result).toBe(false); }); }); @@ -232,18 +232,18 @@ describe('AIServiceManager', () => { .mockReturnValueOnce('openai-key') .mockReturnValueOnce('anthropic-key') .mockReturnValueOnce(''); // No Ollama URL - + const result = manager.getAvailableProviders(); - + expect(result).toEqual(['openai', 'anthropic']); }); it('should include already created services', () => { // Mock that OpenAI has API key configured vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.getAvailableProviders(); - + expect(result).toContain('openai'); }); }); @@ -255,23 +255,23 @@ describe('AIServiceManager', () => { it('should generate completion with selected provider', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); - + // Mock the getAvailableProviders to include openai vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce('') // for ollama .mockReturnValueOnce('test-api-key'); // for service creation - + const mockResponse = { content: 'Hello response' }; const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn().mockResolvedValueOnce(mockResponse) }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.generateChatCompletion(messages); - + expect(result).toBe(mockResponse); expect(mockService.generateChatCompletion).toHaveBeenCalledWith(messages, {}); }); @@ -283,28 +283,28 @@ describe('AIServiceManager', () => { modelId: 'gpt-4', fullIdentifier: 'openai:gpt-4' }); - + // Mock the getAvailableProviders to include openai vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce('') // for ollama .mockReturnValueOnce('test-api-key'); // for service creation - + const mockResponse = { content: 'Hello response' }; const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn().mockResolvedValueOnce(mockResponse) }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - - const result = await manager.generateChatCompletion(messages, { - model: 'openai:gpt-4' + + const result = await manager.generateChatCompletion(messages, { + model: 'openai:gpt-4' }); - + expect(result).toBe(mockResponse); expect(mockService.generateChatCompletion).toHaveBeenCalledWith( - messages, + messages, { model: 'gpt-4' } ); }); @@ -317,7 +317,7 @@ describe('AIServiceManager', () => { it('should throw error if no provider selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + await expect(manager.generateChatCompletion(messages)).rejects.toThrow( 'No AI provider is selected' ); @@ -330,13 +330,13 @@ describe('AIServiceManager', () => { modelId: 'claude-3', fullIdentifier: 'anthropic:claude-3' }); - + // Mock that openai is available vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce(''); // for ollama - + await expect( manager.generateChatCompletion(messages, { model: 'anthropic:claude-3' }) ).rejects.toThrow( @@ -348,9 +348,9 @@ describe('AIServiceManager', () => { describe('getAIEnabledAsync', () => { it('should return AI enabled status', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(true); - + const result = await manager.getAIEnabledAsync(); - + expect(result).toBe(true); expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); @@ -359,9 +359,9 @@ describe('AIServiceManager', () => { describe('getAIEnabled', () => { it('should return AI enabled status synchronously', () => { vi.mocked(options.getOptionBool).mockReturnValueOnce(true); - + const result = manager.getAIEnabled(); - + expect(result).toBe(true); expect(options.getOptionBool).toHaveBeenCalledWith('aiEnabled'); }); @@ -370,17 +370,17 @@ describe('AIServiceManager', () => { describe('initialize', () => { it('should initialize if AI is enabled', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(true); - + await manager.initialize(); - + expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); it('should not initialize if AI is disabled', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(false); - + await manager.initialize(); - + expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); }); @@ -388,36 +388,36 @@ describe('AIServiceManager', () => { describe('getService', () => { it('should return service for specified provider', async () => { vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getService('openai'); - + expect(result).toBe(mockService); }); it('should return selected provider service if no provider specified', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('anthropic'); vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(AnthropicService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getService(); - + expect(result).toBe(mockService); }); it('should throw error if specified provider not available', async () => { vi.mocked(options.getOption).mockReturnValueOnce(''); // No API key - + await expect(manager.getService('openai')).rejects.toThrow( 'Specified provider openai is not available' ); @@ -427,17 +427,17 @@ describe('AIServiceManager', () => { describe('getSelectedProvider', () => { it('should return selected provider synchronously', () => { vi.mocked(options.getOption).mockReturnValueOnce('anthropic'); - + const result = manager.getSelectedProvider(); - + expect(result).toBe('anthropic'); }); it('should return default provider if none selected', () => { vi.mocked(options.getOption).mockReturnValueOnce(''); - + const result = manager.getSelectedProvider(); - + expect(result).toBe('openai'); }); }); @@ -446,18 +446,18 @@ describe('AIServiceManager', () => { it('should return true if provider service is available', () => { // Mock that OpenAI has API key configured vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.isProviderAvailable('openai'); - + expect(result).toBe(true); }); it('should return false if provider service not created', () => { // Mock that OpenAI has no API key configured vi.mocked(options.getOption).mockReturnValueOnce(''); - + const result = manager.isProviderAvailable('openai'); - + expect(result).toBe(false); }); }); @@ -467,13 +467,13 @@ describe('AIServiceManager', () => { // Since getProviderMetadata only returns metadata for the current active provider, // and we don't have a current provider set, it should return null const result = manager.getProviderMetadata('openai'); - + expect(result).toBeNull(); }); it('should return null for non-existing provider', () => { const result = manager.getProviderMetadata('openai'); - + expect(result).toBeNull(); }); }); @@ -485,4 +485,4 @@ describe('AIServiceManager', () => { expect(manager).toBeDefined(); }); }); -}); \ No newline at end of file +}); From 3280123414c5bb28d5686454241d97d1da04cef0 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 16:11:39 +0300 Subject: [PATCH 07/10] chore(env): remove 4GB override --- .env | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index ff859e622..000000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -NODE_OPTIONS=--max_old_space_size=4096 \ No newline at end of file From cb22c2cc7fa7a6f2abf2ea707c452ea624696c0c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 16:42:18 +0300 Subject: [PATCH 08/10] chore(pnpm): align only built dependencies --- package.json | 18 ++++++++++++++++-- pnpm-workspace.yaml | 17 ----------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index b685aa1e3..c80999923 100644 --- a/package.json +++ b/package.json @@ -100,11 +100,25 @@ "dompurify@<3.2.4": ">=3.2.4", "esbuild@<=0.24.2": ">=0.25.0" }, + "ignoredBuiltDependencies": [ + "sqlite3" + ], "onlyBuiltDependencies": [ - "esbuild" + "@parcel/watcher", + "@scarf/scarf", + "better-sqlite3", + "bufferutil", + "core-js-pure", + "electron", + "electron-winstaller", + "esbuild", + "fs-xattr", + "macos-alias", + "nx", + "utf-8-validate" ] }, "nx": { "name": "triliumnext" } -} \ No newline at end of file +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f7e733b59..2c068ac8f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,22 +2,5 @@ packages: - packages/* - apps/* -ignoredBuiltDependencies: -- sqlite3 - -onlyBuiltDependencies: -- '@parcel/watcher' -- '@scarf/scarf' -- bufferutil -- core-js-pure -- esbuild -- nx -- utf-8-validate -- better-sqlite3 -- electron -- electron-winstaller -- fs-xattr -- macos-alias - shamefullyHoist: true nodeLinker: isolated From d2cfb5e94fe5db80d10dc3daca551d58bf2b7bf2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 17:03:02 +0300 Subject: [PATCH 09/10] chore(nx): have website:typecheck depend on build --- apps/website/package.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/website/package.json b/apps/website/package.json index fa45a8bcb..90c52eddc 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -33,5 +33,12 @@ }, "dependencies": { "@inlang/paraglide-js": "^2.0.0" + }, + "nx": { + "typecheck": { + "dependsOn": [ + "build" + ] + } } } From 3aba961f5e6d98e593cb78e8a460fb5435edf360 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 15 Jun 2025 17:09:23 +0300 Subject: [PATCH 10/10] Revert "test(server): skip failing test" This reverts commit 82be37b4afad42215f1af06a29f145bbf4225e3b. --- .../services/llm/ai_service_manager.spec.ts | 132 +++++++++--------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/apps/server/src/services/llm/ai_service_manager.spec.ts b/apps/server/src/services/llm/ai_service_manager.spec.ts index 4a4957b21..c31d90d26 100644 --- a/apps/server/src/services/llm/ai_service_manager.spec.ts +++ b/apps/server/src/services/llm/ai_service_manager.spec.ts @@ -87,7 +87,7 @@ vi.mock('./tools/tool_initializer.js', () => ({ } })); -describe.skip('AIServiceManager', () => { +describe('AIServiceManager', () => { let manager: AIServiceManager; beforeEach(() => { @@ -110,26 +110,26 @@ describe.skip('AIServiceManager', () => { describe('getSelectedProviderAsync', () => { it('should return the selected provider', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBe('openai'); expect(configHelpers.getSelectedProvider).toHaveBeenCalled(); }); it('should return null if no provider is selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBeNull(); }); it('should handle errors and return null', async () => { vi.mocked(configHelpers.getSelectedProvider).mockRejectedValueOnce(new Error('Config error')); - + const result = await manager.getSelectedProviderAsync(); - + expect(result).toBeNull(); }); }); @@ -141,9 +141,9 @@ describe.skip('AIServiceManager', () => { errors: [], warnings: [] }); - + const result = await manager.validateConfiguration(); - + expect(result).toBeNull(); }); @@ -153,9 +153,9 @@ describe.skip('AIServiceManager', () => { errors: ['Missing API key', 'Invalid model'], warnings: [] }); - + const result = await manager.validateConfiguration(); - + expect(result).toContain('There are issues with your AI configuration'); expect(result).toContain('Missing API key'); expect(result).toContain('Invalid model'); @@ -167,9 +167,9 @@ describe.skip('AIServiceManager', () => { errors: [], warnings: ['Model not optimal'] }); - + const result = await manager.validateConfiguration(); - + expect(result).toBeNull(); }); }); @@ -178,21 +178,21 @@ describe.skip('AIServiceManager', () => { it('should create and return the selected provider service', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getOrCreateAnyService(); - + expect(result).toBe(mockService); }); it('should throw error if no provider is selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + await expect(manager.getOrCreateAnyService()).rejects.toThrow( 'No AI provider is selected' ); @@ -201,7 +201,7 @@ describe.skip('AIServiceManager', () => { it('should throw error if selected provider is not available', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); vi.mocked(options.getOption).mockReturnValueOnce(''); // No API key - + await expect(manager.getOrCreateAnyService()).rejects.toThrow( 'Selected AI provider (openai) is not available' ); @@ -211,17 +211,17 @@ describe.skip('AIServiceManager', () => { describe('isAnyServiceAvailable', () => { it('should return true if any provider is available', () => { vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.isAnyServiceAvailable(); - + expect(result).toBe(true); }); it('should return false if no providers are available', () => { vi.mocked(options.getOption).mockReturnValue(''); - + const result = manager.isAnyServiceAvailable(); - + expect(result).toBe(false); }); }); @@ -232,18 +232,18 @@ describe.skip('AIServiceManager', () => { .mockReturnValueOnce('openai-key') .mockReturnValueOnce('anthropic-key') .mockReturnValueOnce(''); // No Ollama URL - + const result = manager.getAvailableProviders(); - + expect(result).toEqual(['openai', 'anthropic']); }); it('should include already created services', () => { // Mock that OpenAI has API key configured vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.getAvailableProviders(); - + expect(result).toContain('openai'); }); }); @@ -255,23 +255,23 @@ describe.skip('AIServiceManager', () => { it('should generate completion with selected provider', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('openai'); - + // Mock the getAvailableProviders to include openai vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce('') // for ollama .mockReturnValueOnce('test-api-key'); // for service creation - + const mockResponse = { content: 'Hello response' }; const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn().mockResolvedValueOnce(mockResponse) }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.generateChatCompletion(messages); - + expect(result).toBe(mockResponse); expect(mockService.generateChatCompletion).toHaveBeenCalledWith(messages, {}); }); @@ -283,28 +283,28 @@ describe.skip('AIServiceManager', () => { modelId: 'gpt-4', fullIdentifier: 'openai:gpt-4' }); - + // Mock the getAvailableProviders to include openai vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce('') // for ollama .mockReturnValueOnce('test-api-key'); // for service creation - + const mockResponse = { content: 'Hello response' }; const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn().mockResolvedValueOnce(mockResponse) }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - - const result = await manager.generateChatCompletion(messages, { - model: 'openai:gpt-4' + + const result = await manager.generateChatCompletion(messages, { + model: 'openai:gpt-4' }); - + expect(result).toBe(mockResponse); expect(mockService.generateChatCompletion).toHaveBeenCalledWith( - messages, + messages, { model: 'gpt-4' } ); }); @@ -317,7 +317,7 @@ describe.skip('AIServiceManager', () => { it('should throw error if no provider selected', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce(null); - + await expect(manager.generateChatCompletion(messages)).rejects.toThrow( 'No AI provider is selected' ); @@ -330,13 +330,13 @@ describe.skip('AIServiceManager', () => { modelId: 'claude-3', fullIdentifier: 'anthropic:claude-3' }); - + // Mock that openai is available vi.mocked(options.getOption) .mockReturnValueOnce('test-api-key') // for availability check .mockReturnValueOnce('') // for anthropic .mockReturnValueOnce(''); // for ollama - + await expect( manager.generateChatCompletion(messages, { model: 'anthropic:claude-3' }) ).rejects.toThrow( @@ -348,9 +348,9 @@ describe.skip('AIServiceManager', () => { describe('getAIEnabledAsync', () => { it('should return AI enabled status', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(true); - + const result = await manager.getAIEnabledAsync(); - + expect(result).toBe(true); expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); @@ -359,9 +359,9 @@ describe.skip('AIServiceManager', () => { describe('getAIEnabled', () => { it('should return AI enabled status synchronously', () => { vi.mocked(options.getOptionBool).mockReturnValueOnce(true); - + const result = manager.getAIEnabled(); - + expect(result).toBe(true); expect(options.getOptionBool).toHaveBeenCalledWith('aiEnabled'); }); @@ -370,17 +370,17 @@ describe.skip('AIServiceManager', () => { describe('initialize', () => { it('should initialize if AI is enabled', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(true); - + await manager.initialize(); - + expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); it('should not initialize if AI is disabled', async () => { vi.mocked(configHelpers.isAIEnabled).mockResolvedValueOnce(false); - + await manager.initialize(); - + expect(configHelpers.isAIEnabled).toHaveBeenCalled(); }); }); @@ -388,36 +388,36 @@ describe.skip('AIServiceManager', () => { describe('getService', () => { it('should return service for specified provider', async () => { vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(OpenAIService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getService('openai'); - + expect(result).toBe(mockService); }); it('should return selected provider service if no provider specified', async () => { vi.mocked(configHelpers.getSelectedProvider).mockResolvedValueOnce('anthropic'); vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const mockService = { isAvailable: vi.fn().mockReturnValue(true), generateChatCompletion: vi.fn() }; vi.mocked(AnthropicService).mockImplementationOnce(() => mockService as any); - + const result = await manager.getService(); - + expect(result).toBe(mockService); }); it('should throw error if specified provider not available', async () => { vi.mocked(options.getOption).mockReturnValueOnce(''); // No API key - + await expect(manager.getService('openai')).rejects.toThrow( 'Specified provider openai is not available' ); @@ -427,17 +427,17 @@ describe.skip('AIServiceManager', () => { describe('getSelectedProvider', () => { it('should return selected provider synchronously', () => { vi.mocked(options.getOption).mockReturnValueOnce('anthropic'); - + const result = manager.getSelectedProvider(); - + expect(result).toBe('anthropic'); }); it('should return default provider if none selected', () => { vi.mocked(options.getOption).mockReturnValueOnce(''); - + const result = manager.getSelectedProvider(); - + expect(result).toBe('openai'); }); }); @@ -446,18 +446,18 @@ describe.skip('AIServiceManager', () => { it('should return true if provider service is available', () => { // Mock that OpenAI has API key configured vi.mocked(options.getOption).mockReturnValueOnce('test-api-key'); - + const result = manager.isProviderAvailable('openai'); - + expect(result).toBe(true); }); it('should return false if provider service not created', () => { // Mock that OpenAI has no API key configured vi.mocked(options.getOption).mockReturnValueOnce(''); - + const result = manager.isProviderAvailable('openai'); - + expect(result).toBe(false); }); }); @@ -467,13 +467,13 @@ describe.skip('AIServiceManager', () => { // Since getProviderMetadata only returns metadata for the current active provider, // and we don't have a current provider set, it should return null const result = manager.getProviderMetadata('openai'); - + expect(result).toBeNull(); }); it('should return null for non-existing provider', () => { const result = manager.getProviderMetadata('openai'); - + expect(result).toBeNull(); }); }); @@ -485,4 +485,4 @@ describe.skip('AIServiceManager', () => { expect(manager).toBeDefined(); }); }); -}); +}); \ No newline at end of file