mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-11 22:40:26 +01:00
Support running multiple Yaak instances via git worktrees (#341)
This commit is contained in:
35
.claude/skills/worktree.md
Normal file
35
.claude/skills/worktree.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Worktree Management Skill
|
||||||
|
|
||||||
|
## Creating Worktrees
|
||||||
|
|
||||||
|
When creating git worktrees for this project, ALWAYS use the path format:
|
||||||
|
```
|
||||||
|
../yaak-worktrees/<NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
- `git worktree add ../yaak-worktrees/feature-auth`
|
||||||
|
- `git worktree add ../yaak-worktrees/bugfix-login`
|
||||||
|
- `git worktree add ../yaak-worktrees/refactor-api`
|
||||||
|
|
||||||
|
## What Happens Automatically
|
||||||
|
|
||||||
|
The post-checkout hook will automatically:
|
||||||
|
1. Create `.env.local` with unique ports (YAAK_DEV_PORT and YAAK_PLUGIN_MCP_SERVER_PORT)
|
||||||
|
2. Copy gitignored editor config folders (.zed, .idea, etc.)
|
||||||
|
3. Run `npm install && npm run bootstrap`
|
||||||
|
|
||||||
|
## Deleting Worktrees
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git worktree remove ../yaak-worktrees/<NAME>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Port Assignments
|
||||||
|
|
||||||
|
- Main worktree: 1420 (Vite), 64343 (MCP)
|
||||||
|
- First worktree: 1421, 64344
|
||||||
|
- Second worktree: 1422, 64345
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
Each worktree can run `npm run app-dev` simultaneously without conflicts.
|
||||||
1
.husky/post-checkout
Executable file
1
.husky/post-checkout
Executable file
@@ -0,0 +1 @@
|
|||||||
|
node scripts/git-hooks/post-checkout.mjs "$@"
|
||||||
140
package-lock.json
generated
140
package-lock.json
generated
@@ -66,6 +66,8 @@
|
|||||||
"@biomejs/biome": "^2.3.10",
|
"@biomejs/biome": "^2.3.10",
|
||||||
"@tauri-apps/cli": "^2.9.6",
|
"@tauri-apps/cli": "^2.9.6",
|
||||||
"@yaakapp/cli": "^0.3.4",
|
"@yaakapp/cli": "^0.3.4",
|
||||||
|
"dotenv-cli": "^11.0.0",
|
||||||
|
"husky": "^9.1.7",
|
||||||
"nodejs-file-downloader": "^4.13.0",
|
"nodejs-file-downloader": "^4.13.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
@@ -7057,6 +7059,128 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv-cli": {
|
||||||
|
"version": "11.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-11.0.0.tgz",
|
||||||
|
"integrity": "sha512-r5pA8idbk7GFWuHEU7trSTflWcdBpQEK+Aw17UrSHjS6CReuhrrPcyC3zcQBPQvhArRHnBo/h6eLH1fkCvNlww==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.6",
|
||||||
|
"dotenv": "^17.1.0",
|
||||||
|
"dotenv-expand": "^12.0.0",
|
||||||
|
"minimist": "^1.2.6"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"dotenv": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/cross-spawn": {
|
||||||
|
"version": "7.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
|
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/dotenv": {
|
||||||
|
"version": "17.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||||
|
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/shebang-command": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"shebang-regex": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/shebang-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-cli/node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-expand": {
|
||||||
|
"version": "12.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz",
|
||||||
|
"integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv-expand/node_modules/dotenv": {
|
||||||
|
"version": "16.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||||
|
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
@@ -9423,6 +9547,22 @@
|
|||||||
"node": ">=14.18.0"
|
"node": ">=14.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/husky": {
|
||||||
|
"version": "9.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
|
||||||
|
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"husky": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hyphenate-style-name": {
|
"node_modules/hyphenate-style-name": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
|
||||||
|
|||||||
@@ -62,9 +62,11 @@
|
|||||||
"src-web"
|
"src-web"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prepare": "husky",
|
||||||
|
"init": "npm install && npm run bootstrap",
|
||||||
"start": "npm run app-dev",
|
"start": "npm run app-dev",
|
||||||
"app-build": "tauri build",
|
"app-build": "tauri build",
|
||||||
"app-dev": "tauri dev --no-watch --config ./src-tauri/tauri.development.conf.json",
|
"app-dev": "node scripts/run-dev.mjs",
|
||||||
"migration": "node scripts/create-migration.cjs",
|
"migration": "node scripts/create-migration.cjs",
|
||||||
"build": "npm run --workspaces --if-present build",
|
"build": "npm run --workspaces --if-present build",
|
||||||
"build-plugins": "npm run --workspaces --if-present build",
|
"build-plugins": "npm run --workspaces --if-present build",
|
||||||
@@ -93,6 +95,8 @@
|
|||||||
"@biomejs/biome": "^2.3.10",
|
"@biomejs/biome": "^2.3.10",
|
||||||
"@tauri-apps/cli": "^2.9.6",
|
"@tauri-apps/cli": "^2.9.6",
|
||||||
"@yaakapp/cli": "^0.3.4",
|
"@yaakapp/cli": "^0.3.4",
|
||||||
|
"dotenv-cli": "^11.0.0",
|
||||||
|
"husky": "^9.1.7",
|
||||||
"nodejs-file-downloader": "^4.13.0",
|
"nodejs-file-downloader": "^4.13.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Context, PluginDefinition } from '@yaakapp/api';
|
import type { Context, PluginDefinition } from '@yaakapp/api';
|
||||||
import { createMcpServer } from './server.js';
|
import { createMcpServer } from './server.js';
|
||||||
|
|
||||||
const serverPort = 64343;
|
const serverPort = parseInt(process.env.YAAK_PLUGIN_MCP_SERVER_PORT ?? '64343', 10);
|
||||||
|
|
||||||
let mcpServer: Awaited<ReturnType<typeof createMcpServer>> | null = null;
|
let mcpServer: Awaited<ReturnType<typeof createMcpServer>> | null = null;
|
||||||
|
|
||||||
|
|||||||
153
scripts/git-hooks/post-checkout.mjs
Normal file
153
scripts/git-hooks/post-checkout.mjs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Git post-checkout hook for auto-configuring worktree environments.
|
||||||
|
* This runs after 'git checkout' or 'git worktree add'.
|
||||||
|
*
|
||||||
|
* Args from git:
|
||||||
|
* process.argv[2] - previous HEAD ref
|
||||||
|
* process.argv[3] - new HEAD ref
|
||||||
|
* process.argv[4] - flag (1 = branch checkout, 0 = file checkout)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { execSync, execFileSync } from 'child_process';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
const isBranchCheckout = process.argv[4] === '1';
|
||||||
|
|
||||||
|
if (!isBranchCheckout) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're in a worktree by looking for .git file (not directory)
|
||||||
|
const gitPath = path.join(process.cwd(), '.git');
|
||||||
|
const isWorktree = fs.existsSync(gitPath) && fs.statSync(gitPath).isFile();
|
||||||
|
|
||||||
|
if (!isWorktree) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const envLocalPath = path.join(process.cwd(), '.env.local');
|
||||||
|
|
||||||
|
// Don't overwrite existing .env.local
|
||||||
|
if (fs.existsSync(envLocalPath)) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Detected new worktree - configuring ports in .env.local');
|
||||||
|
|
||||||
|
// Find the highest ports in use across all worktrees
|
||||||
|
// Main worktree (first in list) is assumed to use default ports 1420/64343
|
||||||
|
let maxMcpPort = 64343;
|
||||||
|
let maxDevPort = 1420;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const worktreeList = execSync('git worktree list --porcelain', { encoding: 'utf8' });
|
||||||
|
const worktreePaths = worktreeList
|
||||||
|
.split('\n')
|
||||||
|
.filter(line => line.startsWith('worktree '))
|
||||||
|
.map(line => line.replace('worktree ', '').trim());
|
||||||
|
|
||||||
|
// Skip the first worktree (main) since it uses default ports
|
||||||
|
for (let i = 1; i < worktreePaths.length; i++) {
|
||||||
|
const worktreePath = worktreePaths[i];
|
||||||
|
const envPath = path.join(worktreePath, '.env.local');
|
||||||
|
|
||||||
|
if (fs.existsSync(envPath)) {
|
||||||
|
const content = fs.readFileSync(envPath, 'utf8');
|
||||||
|
|
||||||
|
const mcpMatch = content.match(/^YAAK_PLUGIN_MCP_SERVER_PORT=(\d+)/m);
|
||||||
|
if (mcpMatch) {
|
||||||
|
const port = parseInt(mcpMatch[1], 10);
|
||||||
|
if (port > maxMcpPort) {
|
||||||
|
maxMcpPort = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const devMatch = content.match(/^YAAK_DEV_PORT=(\d+)/m);
|
||||||
|
if (devMatch) {
|
||||||
|
const port = parseInt(devMatch[1], 10);
|
||||||
|
if (port > maxDevPort) {
|
||||||
|
maxDevPort = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment to get the next available port
|
||||||
|
maxDevPort++;
|
||||||
|
maxMcpPort++;
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Warning: Could not check other worktrees for port conflicts:', err.message);
|
||||||
|
// Continue with default ports
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create .env.local with unique ports
|
||||||
|
const envContent = `# Auto-generated by git post-checkout hook
|
||||||
|
# This file configures ports for this worktree to avoid conflicts
|
||||||
|
|
||||||
|
# Vite dev server port (main worktree uses 1420)
|
||||||
|
YAAK_DEV_PORT=${maxDevPort}
|
||||||
|
|
||||||
|
# MCP Server port (main worktree uses 64343)
|
||||||
|
YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}
|
||||||
|
`;
|
||||||
|
|
||||||
|
fs.writeFileSync(envLocalPath, envContent, 'utf8');
|
||||||
|
console.log(`Created .env.local with YAAK_DEV_PORT=${maxDevPort} and YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}`);
|
||||||
|
|
||||||
|
// Copy gitignored editor config folders from main worktree (.zed, .vscode, .claude, etc.)
|
||||||
|
// This ensures your editor settings, tasks, and configurations are available in the new worktree
|
||||||
|
// without needing to manually copy them or commit them to git.
|
||||||
|
try {
|
||||||
|
const worktreeList = execSync('git worktree list --porcelain', { encoding: 'utf8' });
|
||||||
|
const mainWorktreePath = worktreeList
|
||||||
|
.split('\n')
|
||||||
|
.find(line => line.startsWith('worktree '))
|
||||||
|
?.replace('worktree ', '')
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
if (mainWorktreePath) {
|
||||||
|
// Find all .* folders in main worktree root that are gitignored
|
||||||
|
const entries = fs.readdirSync(mainWorktreePath, { withFileTypes: true });
|
||||||
|
const dotFolders = entries
|
||||||
|
.filter(entry => entry.isDirectory() && entry.name.startsWith('.'))
|
||||||
|
.map(entry => entry.name);
|
||||||
|
|
||||||
|
for (const folder of dotFolders) {
|
||||||
|
const sourcePath = path.join(mainWorktreePath, folder);
|
||||||
|
const destPath = path.join(process.cwd(), folder);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if it's gitignored - run from main worktree directory
|
||||||
|
execFileSync('git', ['check-ignore', '-q', folder], {
|
||||||
|
stdio: 'pipe',
|
||||||
|
cwd: mainWorktreePath
|
||||||
|
});
|
||||||
|
|
||||||
|
// It's gitignored, copy it
|
||||||
|
fs.cpSync(sourcePath, destPath, { recursive: true });
|
||||||
|
console.log(`Copied ${folder} from main worktree`);
|
||||||
|
} catch {
|
||||||
|
// Not gitignored or doesn't exist, skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Warning: Could not copy files from main worktree:', err.message);
|
||||||
|
// Continue anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run npm run init to install dependencies and bootstrap
|
||||||
|
console.log('\nRunning npm run init to install dependencies and bootstrap...');
|
||||||
|
try {
|
||||||
|
execSync('npm run init', { stdio: 'inherit' });
|
||||||
|
console.log('\n✓ Worktree setup complete!');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('\n✗ Failed to run npm run init. You may need to run it manually.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
49
scripts/run-dev.mjs
Normal file
49
scripts/run-dev.mjs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script to run Tauri dev server with dynamic port configuration.
|
||||||
|
* Loads port from .env.local if present, otherwise uses default port 1420.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { spawnSync } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
// Load .env.local if it exists
|
||||||
|
const envLocalPath = path.join(__dirname, '..', '.env.local');
|
||||||
|
if (fs.existsSync(envLocalPath)) {
|
||||||
|
const envContent = fs.readFileSync(envLocalPath, 'utf8');
|
||||||
|
const envVars = envContent
|
||||||
|
.split('\n')
|
||||||
|
.filter(line => line && !line.startsWith('#'))
|
||||||
|
.reduce((acc, line) => {
|
||||||
|
const [key, value] = line.split('=');
|
||||||
|
if (key && value) {
|
||||||
|
acc[key.trim()] = value.trim();
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
Object.assign(process.env, envVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
const port = process.env.YAAK_DEV_PORT || '1420';
|
||||||
|
const config = JSON.stringify({ build: { devUrl: `http://localhost:${port}` } });
|
||||||
|
|
||||||
|
// Get additional arguments passed after npm run app-dev --
|
||||||
|
const additionalArgs = process.argv.slice(2);
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
'dev',
|
||||||
|
'--no-watch',
|
||||||
|
'--config', './src-tauri/tauri.development.conf.json',
|
||||||
|
'--config', config,
|
||||||
|
...additionalArgs
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = spawnSync('tauri', args, { stdio: 'inherit', shell: false, env: process.env });
|
||||||
|
|
||||||
|
process.exit(result.status || 0);
|
||||||
@@ -1417,43 +1417,48 @@ async fn cmd_check_for_updates<R: Runtime>(
|
|||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
#[allow(unused_mut)]
|
let mut builder = tauri::Builder::default().plugin(
|
||||||
let mut builder = tauri::Builder::default()
|
Builder::default()
|
||||||
.plugin(
|
.targets([
|
||||||
Builder::default()
|
Target::new(TargetKind::Stdout),
|
||||||
.targets([
|
Target::new(TargetKind::LogDir { file_name: None }),
|
||||||
Target::new(TargetKind::Stdout),
|
Target::new(TargetKind::Webview),
|
||||||
Target::new(TargetKind::LogDir { file_name: None }),
|
])
|
||||||
Target::new(TargetKind::Webview),
|
.level_for("plugin_runtime", log::LevelFilter::Info)
|
||||||
])
|
.level_for("cookie_store", log::LevelFilter::Info)
|
||||||
.level_for("plugin_runtime", log::LevelFilter::Info)
|
.level_for("eventsource_client::event_parser", log::LevelFilter::Info)
|
||||||
.level_for("cookie_store", log::LevelFilter::Info)
|
.level_for("h2", log::LevelFilter::Info)
|
||||||
.level_for("eventsource_client::event_parser", log::LevelFilter::Info)
|
.level_for("hyper", log::LevelFilter::Info)
|
||||||
.level_for("h2", log::LevelFilter::Info)
|
.level_for("hyper_util", log::LevelFilter::Info)
|
||||||
.level_for("hyper", log::LevelFilter::Info)
|
.level_for("hyper_rustls", log::LevelFilter::Info)
|
||||||
.level_for("hyper_util", log::LevelFilter::Info)
|
.level_for("reqwest", log::LevelFilter::Info)
|
||||||
.level_for("hyper_rustls", log::LevelFilter::Info)
|
.level_for("sqlx", log::LevelFilter::Debug)
|
||||||
.level_for("reqwest", log::LevelFilter::Info)
|
.level_for("tao", log::LevelFilter::Info)
|
||||||
.level_for("sqlx", log::LevelFilter::Debug)
|
.level_for("tokio_util", log::LevelFilter::Info)
|
||||||
.level_for("tao", log::LevelFilter::Info)
|
.level_for("tonic", log::LevelFilter::Info)
|
||||||
.level_for("tokio_util", log::LevelFilter::Info)
|
.level_for("tower", log::LevelFilter::Info)
|
||||||
.level_for("tonic", log::LevelFilter::Info)
|
.level_for("tracing", log::LevelFilter::Warn)
|
||||||
.level_for("tower", log::LevelFilter::Info)
|
.level_for("swc_ecma_codegen", log::LevelFilter::Off)
|
||||||
.level_for("tracing", log::LevelFilter::Warn)
|
.level_for("swc_ecma_transforms_base", log::LevelFilter::Off)
|
||||||
.level_for("swc_ecma_codegen", log::LevelFilter::Off)
|
.with_colors(ColoredLevelConfig::default())
|
||||||
.level_for("swc_ecma_transforms_base", log::LevelFilter::Off)
|
.level(if is_dev() { log::LevelFilter::Debug } else { log::LevelFilter::Info })
|
||||||
.with_colors(ColoredLevelConfig::default())
|
.build(),
|
||||||
.level(if is_dev() { log::LevelFilter::Debug } else { log::LevelFilter::Info })
|
);
|
||||||
.build(),
|
|
||||||
)
|
// Only enable single-instance in production builds. In dev mode, we want to allow
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
// multiple instances for testing and worktree workflows (running multiple branches).
|
||||||
|
if !is_dev() {
|
||||||
|
builder = builder.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
||||||
// When trying to open a new app instance (common operation on Linux),
|
// When trying to open a new app instance (common operation on Linux),
|
||||||
// focus the first existing window we find instead of opening a new one
|
// focus the first existing window we find instead of opening a new one
|
||||||
// TODO: Keep track of the last focused window and always focus that one
|
// TODO: Keep track of the last focused window and always focus that one
|
||||||
if let Some(window) = app.webview_windows().values().next() {
|
if let Some(window) = app.webview_windows().values().next() {
|
||||||
let _ = window.set_focus();
|
let _ = window.set_focus();
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = builder
|
||||||
.plugin(tauri_plugin_clipboard_manager::init())
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
// Don't restore StateFlags::DECORATIONS because we want to be able to toggle them on/off on a restart
|
// Don't restore StateFlags::DECORATIONS because we want to be able to toggle them on/off on a restart
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { tanstackRouter } from '@tanstack/router-plugin/vite';
|
import { tanstackRouter } from '@tanstack/router-plugin/vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import { internalIpV4 } from 'internal-ip';
|
|
||||||
import { createRequire } from 'node:module';
|
import { createRequire } from 'node:module';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { defineConfig, normalizePath } from 'vite';
|
import { defineConfig, normalizePath } from 'vite';
|
||||||
@@ -18,10 +17,9 @@ const standardFontsDir = normalizePath(
|
|||||||
path.join(path.dirname(require.resolve('pdfjs-dist/package.json')), 'standard_fonts'),
|
path.join(path.dirname(require.resolve('pdfjs-dist/package.json')), 'standard_fonts'),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM ?? '');
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(async () => ({
|
export default defineConfig(async () => {
|
||||||
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
wasm(),
|
wasm(),
|
||||||
tanstackRouter({
|
tanstackRouter({
|
||||||
@@ -54,16 +52,9 @@ export default defineConfig(async () => ({
|
|||||||
},
|
},
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
server: {
|
server: {
|
||||||
port: 1420,
|
port: parseInt(process.env.YAAK_DEV_PORT ?? '1420', 10),
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
host: mobile ? '0.0.0.0' : false,
|
|
||||||
hmr: mobile
|
|
||||||
? {
|
|
||||||
protocol: 'ws',
|
|
||||||
host: await internalIpV4(),
|
|
||||||
port: 1421,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
},
|
},
|
||||||
envPrefix: ['VITE_', 'TAURI_'],
|
envPrefix: ['VITE_', 'TAURI_'],
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user