Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d172b2a
chore: test husky pre-commit
focusedbrain Aug 27, 2025
5b8a2a1
chore: modernize husky pre-commit
focusedbrain Aug 27, 2025
127edee
ci: setup pnpm cache, defaults + prettier check
focusedbrain Aug 27, 2025
fcefc14
ci: add lint & format scripts to workspace root
focusedbrain Aug 27, 2025
08967a8
chore: add project files and lint script
focusedbrain Aug 27, 2025
4b709bc
chore(ci): trigger pipeline
focusedbrain Aug 27, 2025
ff33596
fix(desktop): remove unused import createRequire
focusedbrain Aug 28, 2025
bcf1154
chore(eslint): add ESLint v9 flat-config and remove old eslintrc
focusedbrain Aug 28, 2025
4456b92
chore(desktop): sync package.json with workspace and update lockfile
focusedbrain Aug 28, 2025
44eb30e
style: format code with prettier
focusedbrain Aug 28, 2025
be9adda
test: check pre-commit
focusedbrain Aug 28, 2025
a4f18ff
chore: add tests, vitest config, .gitignore, and CI workflow
focusedbrain Aug 28, 2025
7c084f3
chore: unify .gitignore at repo root
focusedbrain Aug 28, 2025
32f4011
ci: simplify node setup (no cache, minimal working version)
focusedbrain Aug 28, 2025
bf5ad40
ci: disable frozen-lockfile for now
focusedbrain Aug 28, 2025
302b1a1
ci: minimal install (no frozen lockfile) + trigger on all branches
focusedbrain Aug 28, 2025
45595ec
ci: fix pnpm run ordering (place --if-present before run)
focusedbrain Aug 28, 2025
6a340d0
ci: trigger
focusedbrain Aug 28, 2025
a574247
ci: remove old ci.yml; use tests.yml only
focusedbrain Aug 28, 2025
a292667
ci: trigger
focusedbrain Aug 28, 2025
ab6491e
ci: minimal workflow; disable frozen lockfile explicitly
focusedbrain Aug 28, 2025
e9e8852
ci: trigger
focusedbrain Aug 28, 2025
710ae9d
chore: refresh pnpm-lock.yaml
focusedbrain Aug 28, 2025
47cfffd
ci: update tests workflow; chore: adjust desktop package json
focusedbrain Aug 28, 2025
5d6af4d
ci: trigger
focusedbrain Aug 28, 2025
3c43f84
ci: add/fix minimal tests workflow (powershell)
focusedbrain Aug 28, 2025
4599333
ci: trigger
focusedbrain Aug 28, 2025
357a829
ci: add OSV vulnerability scan job
focusedbrain Aug 28, 2025
8e16fa3
ci: fix OSV action tag to @v2
focusedbrain Aug 28, 2025
b4f6417
ci: use OSV reusable workflow with exact tag v2.2.2
focusedbrain Aug 28, 2025
e273009
ci: add OSV scan via CLI (no reusable workflow)
focusedbrain Aug 28, 2025
7af9183
ci: fix yaml and add OSV scan job
focusedbrain Aug 28, 2025
fbc1b62
ci: add concurrency and timeouts (safe)
focusedbrain Aug 28, 2025
d3f80d9
ci: move concurrency to top-level and add timeouts
focusedbrain Aug 28, 2025
d8404e5
ci: allow manual run (workflow_dispatch)
focusedbrain Aug 28, 2025
26a377c
ci: fix workflow_dispatch placement and clean OSV step
focusedbrain Aug 28, 2025
798e79b
ci: enable pnpm cache using code/pnpm-lock.yaml
focusedbrain Aug 28, 2025
1476ef9
ci: full workflow (tests + osv + trivy), cache, concurrency, dispatch
focusedbrain Aug 28, 2025
ee59973
chore: add .cursorignore for AI tools
focusedbrain Aug 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.env
.env.*
secrets/**
dumps/**
uploads/**
**/*.log
node_modules/**
dist/**
.vite/**
coverage/**
22 changes: 0 additions & 22 deletions .github/workflows/ci.yml

This file was deleted.

45 changes: 45 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI - Workspace Tests

on:
push:
branches:
- '**'
pull_request:
branches:
- '**'

jobs:
test_all:
runs-on: ubuntu-latest
defaults:
run:
working-directory: code
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Ensure no frozen lockfile
run: pnpm config set frozen-lockfile false
- name: Install dependencies (no scripts)
run: pnpm install --ignore-scripts --no-frozen-lockfile
- name: Show workspace packages
run: pnpm -r list --depth -1
- name: Run tests in all packages (if present)
run: pnpm -r --workspace-concurrency=1 --if-present run test:ci

osv_scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install OSV-Scanner
run: |
curl -sSfL https://raw.githubusercontent.com/google/osv-scanner/main/scripts/install.sh | sh -s -- -b /usr/local/bin
- name: Run OSV scan (lockfile only)
run: |
osv-scanner --lockfile=./code/pnpm-lock.yaml || true
29 changes: 29 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Node / pnpm
node_modules/
.pnpm-debug.log
pnpm-debug.log*

# Vite / Build Artefakte
dist/
.vite/
*.local

# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.log

# Test coverage
coverage/

# Editor
.vscode/
.idea/
.DS_Store
Thumbs.db

# Environment files
.env
.env.*
!.env.example
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

pnpm -C code lint-staged
1 change: 1 addition & 0 deletions code/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pnpm test
5 changes: 5 additions & 0 deletions code/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
**/node_modules/**
**/dist/**
**/build/**
**/dist-electron/**
**/.vite/**
1 change: 1 addition & 0 deletions code/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "singleQuote": true, "semi": true, "printWidth": 100 }
15 changes: 15 additions & 0 deletions code/apps/desktop/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
};
24 changes: 24 additions & 0 deletions code/apps/desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
30 changes: 30 additions & 0 deletions code/apps/desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
};
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
45 changes: 45 additions & 0 deletions code/apps/desktop/dist-electron/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { app, BrowserWindow } from "electron";
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import path from "node:path";
createRequire(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
process.env.APP_ROOT = path.join(__dirname, "..");
const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"];
const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron");
const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist");
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, "public") : RENDERER_DIST;
let win;
function createWindow() {
win = new BrowserWindow({
icon: path.join(process.env.VITE_PUBLIC, "electron-vite.svg"),
webPreferences: {
preload: path.join(__dirname, "preload.mjs")
}
});
win.webContents.on("did-finish-load", () => {
win == null ? void 0 : win.webContents.send("main-process-message", (/* @__PURE__ */ new Date()).toLocaleString());
});
if (VITE_DEV_SERVER_URL) {
win.loadURL(VITE_DEV_SERVER_URL);
} else {
win.loadFile(path.join(RENDERER_DIST, "index.html"));
}
}
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
win = null;
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app.whenReady().then(createWindow);
export {
MAIN_DIST,
RENDERER_DIST,
VITE_DEV_SERVER_URL
};
22 changes: 22 additions & 0 deletions code/apps/desktop/dist-electron/preload.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use strict";
const electron = require("electron");
electron.contextBridge.exposeInMainWorld("ipcRenderer", {
on(...args) {
const [channel, listener] = args;
return electron.ipcRenderer.on(channel, (event, ...args2) => listener(event, ...args2));
},
off(...args) {
const [channel, ...omit] = args;
return electron.ipcRenderer.off(channel, ...omit);
},
send(...args) {
const [channel, ...omit] = args;
return electron.ipcRenderer.send(channel, ...omit);
},
invoke(...args) {
const [channel, ...omit] = args;
return electron.ipcRenderer.invoke(channel, ...omit);
}
// You can expose other APTs you need here.
// ...
});
34 changes: 34 additions & 0 deletions code/apps/desktop/electron-builder.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// @see - https://www.electron.build/configuration/configuration
{
$schema: 'https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json',
appId: 'YourAppID',
asar: true,
productName: 'YourAppName',
directories: {
output: 'release/${version}',
},
files: ['dist', 'dist-electron'],
mac: {
target: ['dmg'],
artifactName: '${productName}-Mac-${version}-Installer.${ext}',
},
win: {
target: [
{
target: 'nsis',
arch: ['x64'],
},
],
artifactName: '${productName}-Windows-${version}-Setup.${ext}',
},
nsis: {
oneClick: false,
perMachine: false,
allowToChangeInstallationDirectory: true,
deleteAppDataOnUninstall: false,
},
linux: {
target: ['AppImage'],
artifactName: '${productName}-Linux-${version}.${ext}',
},
}
27 changes: 27 additions & 0 deletions code/apps/desktop/electron/electron-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/// <reference types="vite-plugin-electron/electron-env" />

declare namespace NodeJS {
interface ProcessEnv {
/**
* The built directory structure
*
* ```tree
* ├─┬─┬ dist
* │ │ └── index.html
* │ │
* │ ├─┬ dist-electron
* │ │ ├── main.js
* │ │ └── preload.js
* │
* ```
*/
APP_ROOT: string;
/** /dist/ or /public/ */
VITE_PUBLIC: string;
}
}

// Used in Renderer process, expose in `preload.ts`
interface Window {
ipcRenderer: import('electron').IpcRenderer;
}
68 changes: 68 additions & 0 deletions code/apps/desktop/electron/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { app, BrowserWindow } from 'electron';
import { fileURLToPath } from 'node:url';
import path from 'node:path';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// The built directory structure
//
// ├─┬─┬ dist
// │ │ └── index.html
// │ │
// │ ├─┬ dist-electron
// │ │ ├── main.js
// │ │ └── preload.mjs
// │
process.env.APP_ROOT = path.join(__dirname, '..');

// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x
export const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL'];
export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron');
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist');

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
? path.join(process.env.APP_ROOT, 'public')
: RENDERER_DIST;

let win: BrowserWindow | null;

function createWindow() {
win = new BrowserWindow({
icon: path.join(process.env.VITE_PUBLIC, 'electron-vite.svg'),
webPreferences: {
preload: path.join(__dirname, 'preload.mjs'),
},
});

// Test active push message to Renderer-process.
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', new Date().toLocaleString());
});

if (VITE_DEV_SERVER_URL) {
win.loadURL(VITE_DEV_SERVER_URL);
} else {
// win.loadFile('dist/index.html')
win.loadFile(path.join(RENDERER_DIST, 'index.html'));
}
}

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
win = null;
}
});

app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});

app.whenReady().then(createWindow);
Loading