Run oxfmt across repo, add format script and docs

Add .oxfmtignore to skip generated bindings and wasm-pack output.
Add npm format script, update DEVELOPMENT.md for Vite+ toolchain,
and format all non-generated files with oxfmt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-03-13 10:15:49 -07:00
parent 45262edfbd
commit b4a1c418bb
664 changed files with 13638 additions and 13492 deletions

View File

@@ -1,7 +1,7 @@
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const slugify = require('slugify');
const fs = require("fs");
const path = require("path");
const readline = require("readline");
const slugify = require("slugify");
const rl = readline.createInterface({
input: process.stdin,
@@ -11,33 +11,33 @@ const rl = readline.createInterface({
function generateTimestamp() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `${year}${month}${day}${hours}${minutes}${seconds}`;
}
async function createMigration() {
try {
const migrationName = await new Promise((resolve) => {
rl.question('Enter migration name: ', resolve);
rl.question("Enter migration name: ", resolve);
});
const timestamp = generateTimestamp();
const fileName = `${timestamp}_${slugify(String(migrationName), { lower: true })}.sql`;
const migrationsDir = path.join(__dirname, '../crates/yaak-models/migrations');
const migrationsDir = path.join(__dirname, "../crates/yaak-models/migrations");
const filePath = path.join(migrationsDir, fileName);
if (!fs.existsSync(migrationsDir)) {
fs.mkdirSync(migrationsDir, { recursive: true });
}
fs.writeFileSync(filePath, '-- Add migration SQL here\n');
fs.writeFileSync(filePath, "-- Add migration SQL here\n");
console.log(`Created migration file: ${fileName}`);
} catch (error) {
console.error('Error creating migration:', error);
console.error("Error creating migration:", error);
} finally {
rl.close();
}

View File

@@ -10,35 +10,35 @@
* 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';
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';
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 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');
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');
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
@@ -46,19 +46,19 @@ let maxMcpPort = 64343;
let maxDevPort = 1420;
try {
const worktreeList = execSync('git worktree list --porcelain', { encoding: 'utf8' });
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());
.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');
const envPath = path.join(worktreePath, ".env.local");
if (fs.existsSync(envPath)) {
const content = fs.readFileSync(envPath, 'utf8');
const content = fs.readFileSync(envPath, "utf8");
const mcpMatch = content.match(/^YAAK_PLUGIN_MCP_SERVER_PORT=(\d+)/m);
if (mcpMatch) {
@@ -82,7 +82,7 @@ try {
maxDevPort++;
maxMcpPort++;
} catch (err) {
console.error('Warning: Could not check other worktrees for port conflicts:', err.message);
console.error("Warning: Could not check other worktrees for port conflicts:", err.message);
// Continue with default ports
}
@@ -100,37 +100,44 @@ YAAK_DEV_PORT=${maxDevPort}
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}`);
fs.writeFileSync(envLocalPath, envContent, "utf8");
console.log(
`Created .env.local with YAAK_DEV_PORT=${maxDevPort} and YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}`,
);
// Create tauri.worktree.conf.json with unique app identifier for complete isolation
// This gives each worktree its own app data directory, avoiding the need for DB path prefixes
const tauriWorktreeConfig = {
identifier: `app.yaak.desktop.dev.${worktreeName}`,
productName: `Daak (${worktreeName})`
productName: `Daak (${worktreeName})`,
};
const tauriConfigPath = path.join(process.cwd(), 'crates-tauri', 'yaak-app', 'tauri.worktree.conf.json');
fs.writeFileSync(tauriConfigPath, JSON.stringify(tauriWorktreeConfig, null, 2) + '\n', 'utf8');
const tauriConfigPath = path.join(
process.cwd(),
"crates-tauri",
"yaak-app",
"tauri.worktree.conf.json",
);
fs.writeFileSync(tauriConfigPath, JSON.stringify(tauriWorktreeConfig, null, 2) + "\n", "utf8");
console.log(`Created tauri.worktree.conf.json with identifier: ${tauriWorktreeConfig.identifier}`);
// 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 worktreeList = execSync("git worktree list --porcelain", { encoding: "utf8" });
const mainWorktreePath = worktreeList
.split('\n')
.find(line => line.startsWith('worktree '))
?.replace('worktree ', '')
.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);
.filter((entry) => entry.isDirectory() && entry.name.startsWith("."))
.map((entry) => entry.name);
for (const folder of dotFolders) {
const sourcePath = path.join(mainWorktreePath, folder);
@@ -138,9 +145,9 @@ try {
try {
// Check if it's gitignored - run from main worktree directory
execFileSync('git', ['check-ignore', '-q', folder], {
stdio: 'pipe',
cwd: mainWorktreePath
execFileSync("git", ["check-ignore", "-q", folder], {
stdio: "pipe",
cwd: mainWorktreePath,
});
// It's gitignored, copy it
@@ -152,8 +159,8 @@ try {
}
}
} catch (err) {
console.warn('Warning: Could not copy files from main worktree:', err.message);
console.warn("Warning: Could not copy files from main worktree:", err.message);
// Continue anyway
}
console.log('\n✓ Worktree setup complete! Run `npm run init` to install dependencies.');
console.log("\n✓ Worktree setup complete! Run `npm run init` to install dependencies.");

View File

@@ -1,18 +1,18 @@
const { execSync } = require('node:child_process');
const { execSync } = require("node:child_process");
const version = tryExecSync('wasm-pack --version');
if (version.startsWith('wasm-pack ')) {
console.log('wasm-pack already installed');
const version = tryExecSync("wasm-pack --version");
if (version.startsWith("wasm-pack ")) {
console.log("wasm-pack already installed");
return;
}
console.log('Installing wasm-pack via cargo...');
execSync('cargo install wasm-pack --locked', { stdio: 'inherit' });
console.log("Installing wasm-pack via cargo...");
execSync("cargo install wasm-pack --locked", { stdio: "inherit" });
function tryExecSync(cmd) {
try {
return execSync(cmd, { stdio: 'pipe' }).toString('utf-8');
return execSync(cmd, { stdio: "pipe" }).toString("utf-8");
} catch {
return '';
return "";
}
}

View File

@@ -1,15 +1,19 @@
const { readdirSync } = require('node:fs');
const path = require('node:path');
const { execSync } = require('node:child_process');
const { readdirSync } = require("node:fs");
const path = require("node:path");
const { execSync } = require("node:child_process");
const pluginsDir = path.join(__dirname, '..', 'plugins');
const pluginsDir = path.join(__dirname, "..", "plugins");
console.log('Publishing core Yaak plugins');
console.log("Publishing core Yaak plugins");
for (const name of readdirSync(pluginsDir)) {
const dir = path.join(pluginsDir, name);
if (name.startsWith('.')) continue;
console.log('Building plugin', dir);
execSync('npm run build', { stdio: 'inherit', cwd: dir });
execSync('yaakcli publish', { stdio: 'inherit', cwd: dir, env: { ...process.env, ENVIRONMENT: 'development' } });
if (name.startsWith(".")) continue;
console.log("Building plugin", dir);
execSync("npm run build", { stdio: "inherit", cwd: dir });
execSync("yaakcli publish", {
stdio: "inherit",
cwd: dir,
env: { ...process.env, ENVIRONMENT: "development" },
});
}

View File

@@ -1,15 +1,15 @@
const path = require('path');
const fs = require('fs');
const path = require("path");
const fs = require("fs");
const version = process.env.YAAK_VERSION?.replace('v', '');
const version = process.env.YAAK_VERSION?.replace("v", "");
if (!version) {
throw new Error('YAAK_VERSION environment variable not set')
throw new Error("YAAK_VERSION environment variable not set");
}
const tauriConfigPath = path.join(__dirname, '../crates-tauri/yaak-app/tauri.conf.json');
const tauriConfig = JSON.parse(fs.readFileSync(tauriConfigPath, 'utf8'));
const tauriConfigPath = path.join(__dirname, "../crates-tauri/yaak-app/tauri.conf.json");
const tauriConfig = JSON.parse(fs.readFileSync(tauriConfigPath, "utf8"));
tauriConfig.version = version;
console.log('Writing version ' + version + ' to ' + tauriConfigPath)
console.log("Writing version " + version + " to " + tauriConfigPath);
fs.writeFileSync(tauriConfigPath, JSON.stringify(tauriConfig, null, 2));

View File

@@ -5,23 +5,23 @@
* 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';
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));
const rootDir = path.join(__dirname, '..');
const rootDir = path.join(__dirname, "..");
// Load .env.local if it exists
const envLocalPath = path.join(rootDir, '.env.local');
const envLocalPath = path.join(rootDir, ".env.local");
if (fs.existsSync(envLocalPath)) {
const envContent = fs.readFileSync(envLocalPath, 'utf8');
const envContent = fs.readFileSync(envLocalPath, "utf8");
const envVars = envContent
.split('\n')
.filter(line => line && !line.startsWith('#'))
.split("\n")
.filter((line) => line && !line.startsWith("#"))
.reduce((acc, line) => {
const [key, value] = line.split('=');
const [key, value] = line.split("=");
if (key && value) {
acc[key.trim()] = value.trim();
}
@@ -31,23 +31,28 @@ if (fs.existsSync(envLocalPath)) {
Object.assign(process.env, envVars);
}
const port = process.env.YAAK_DEV_PORT || '1420';
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', 'crates-tauri/yaak-app/tauri.development.conf.json',
'--config', config,
...additionalArgs
"dev",
"--no-watch",
"--config",
"crates-tauri/yaak-app/tauri.development.conf.json",
"--config",
config,
...additionalArgs,
];
// Invoke the tauri CLI JS entry point directly via node to avoid shell escaping issues on Windows
const tauriJs = path.join(rootDir, 'node_modules', '@tauri-apps', 'cli', 'tauri.js');
const tauriJs = path.join(rootDir, "node_modules", "@tauri-apps", "cli", "tauri.js");
const result = spawnSync(process.execPath, [tauriJs, ...args], { stdio: 'inherit', env: process.env });
const result = spawnSync(process.execPath, [tauriJs, ...args], {
stdio: "inherit",
env: process.env,
});
process.exit(result.status || 0);

View File

@@ -5,28 +5,28 @@
* Handles cleanup of child processes on exit.
*/
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { spawn } from "child_process";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rootDir = path.join(__dirname, '..');
const rootDir = path.join(__dirname, "..");
// Read root package.json to get workspaces
const rootPkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
const rootPkg = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"));
const workspaces = rootPkg.workspaces || [];
// Find all workspaces with a dev script
const workspacesWithDev = workspaces.filter((ws) => {
const pkgPath = path.join(rootDir, ws, 'package.json');
const pkgPath = path.join(rootDir, ws, "package.json");
if (!fs.existsSync(pkgPath)) return false;
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
return pkg.scripts?.dev != null;
});
if (workspacesWithDev.length === 0) {
console.log('No workspaces with dev script found');
console.log("No workspaces with dev script found");
process.exit(0);
}
@@ -37,13 +37,13 @@ const children = [];
// Spawn all dev processes
for (const ws of workspacesWithDev) {
const cwd = path.join(rootDir, ws);
const child = spawn('npm', ['run', 'dev'], {
const child = spawn("npm", ["run", "dev"], {
cwd,
stdio: 'inherit',
shell: process.platform === 'win32',
stdio: "inherit",
shell: process.platform === "win32",
});
child.on('error', (err) => {
child.on("error", (err) => {
console.error(`Error in ${ws}:`, err.message);
});
@@ -55,27 +55,27 @@ function cleanup() {
for (const { child } of children) {
if (child.exitCode === null) {
// Process still running
if (process.platform === 'win32') {
spawn('taskkill', ['/pid', child.pid, '/f', '/t'], { shell: true });
if (process.platform === "win32") {
spawn("taskkill", ["/pid", child.pid, "/f", "/t"], { shell: true });
} else {
child.kill('SIGTERM');
child.kill("SIGTERM");
}
}
}
}
// Handle various exit signals
process.on('SIGINT', () => {
process.on("SIGINT", () => {
cleanup();
process.exit(0);
});
process.on('SIGTERM', () => {
process.on("SIGTERM", () => {
cleanup();
process.exit(0);
});
process.on('exit', cleanup);
process.on("exit", cleanup);
// Keep the process running
process.stdin.resume();

View File

@@ -1,20 +1,20 @@
const path = require('node:path');
const crypto = require('node:crypto');
const fs = require('node:fs');
const decompress = require('decompress');
const Downloader = require('nodejs-file-downloader');
const { rmSync, cpSync, mkdirSync, existsSync } = require('node:fs');
const { execSync } = require('node:child_process');
const path = require("node:path");
const crypto = require("node:crypto");
const fs = require("node:fs");
const decompress = require("decompress");
const Downloader = require("nodejs-file-downloader");
const { rmSync, cpSync, mkdirSync, existsSync } = require("node:fs");
const { execSync } = require("node:child_process");
const NODE_VERSION = 'v24.11.1';
const NODE_VERSION = "v24.11.1";
// `${process.platform}_${process.arch}`
const MAC_ARM = 'darwin_arm64';
const MAC_X64 = 'darwin_x64';
const LNX_ARM = 'linux_arm64';
const LNX_X64 = 'linux_x64';
const WIN_X64 = 'win32_x64';
const WIN_ARM = 'win32_arm64';
const MAC_ARM = "darwin_arm64";
const MAC_X64 = "darwin_x64";
const LNX_ARM = "linux_arm64";
const LNX_X64 = "linux_x64";
const WIN_X64 = "win32_x64";
const WIN_ARM = "win32_arm64";
const URL_MAP = {
[MAC_ARM]: `https://nodejs.org/download/release/${NODE_VERSION}/node-${NODE_VERSION}-darwin-arm64.tar.gz`,
@@ -35,31 +35,31 @@ const SRC_BIN_MAP = {
};
const DST_BIN_MAP = {
[MAC_ARM]: 'yaaknode',
[MAC_X64]: 'yaaknode',
[LNX_ARM]: 'yaaknode',
[LNX_X64]: 'yaaknode',
[WIN_X64]: 'yaaknode.exe',
[WIN_ARM]: 'yaaknode.exe',
[MAC_ARM]: "yaaknode",
[MAC_X64]: "yaaknode",
[LNX_ARM]: "yaaknode",
[LNX_X64]: "yaaknode",
[WIN_X64]: "yaaknode.exe",
[WIN_ARM]: "yaaknode.exe",
};
const SHA256_MAP = {
[MAC_ARM]: 'b05aa3a66efe680023f930bd5af3fdbbd542794da5644ca2ad711d68cbd4dc35',
[MAC_X64]: '096081b6d6fcdd3f5ba0f5f1d44a47e83037ad2e78eada26671c252fe64dd111',
[LNX_ARM]: '0dc93ec5c798b0d347f068db6d205d03dea9a71765e6a53922b682b91265d71f',
[LNX_X64]: '58a5ff5cc8f2200e458bea22e329d5c1994aa1b111d499ca46ec2411d58239ca',
[WIN_X64]: '5355ae6d7c49eddcfde7d34ac3486820600a831bf81dc3bdca5c8db6a9bb0e76',
[WIN_ARM]: 'ce9ee4e547ebdff355beb48e309b166c24df6be0291c9eaf103ce15f3de9e5b4',
[MAC_ARM]: "b05aa3a66efe680023f930bd5af3fdbbd542794da5644ca2ad711d68cbd4dc35",
[MAC_X64]: "096081b6d6fcdd3f5ba0f5f1d44a47e83037ad2e78eada26671c252fe64dd111",
[LNX_ARM]: "0dc93ec5c798b0d347f068db6d205d03dea9a71765e6a53922b682b91265d71f",
[LNX_X64]: "58a5ff5cc8f2200e458bea22e329d5c1994aa1b111d499ca46ec2411d58239ca",
[WIN_X64]: "5355ae6d7c49eddcfde7d34ac3486820600a831bf81dc3bdca5c8db6a9bb0e76",
[WIN_ARM]: "ce9ee4e547ebdff355beb48e309b166c24df6be0291c9eaf103ce15f3de9e5b4",
};
const key = `${process.platform}_${process.env.YAAK_TARGET_ARCH ?? process.arch}`;
const destDir = path.join(__dirname, `..`, 'crates-tauri', 'yaak-app', 'vendored', 'node');
const destDir = path.join(__dirname, `..`, "crates-tauri", "yaak-app", "vendored", "node");
const binDest = path.join(destDir, DST_BIN_MAP[key]);
console.log(`Vendoring NodeJS ${NODE_VERSION} for ${key}`);
if (existsSync(binDest) && tryExecSync(`${binDest} --version`).trim() === NODE_VERSION) {
console.log('NodeJS already vendored');
console.log("NodeJS already vendored");
return;
}
@@ -67,12 +67,12 @@ rmSync(destDir, { recursive: true, force: true });
mkdirSync(destDir, { recursive: true });
const url = URL_MAP[key];
const tmpDir = path.join(__dirname, 'tmp-node');
const tmpDir = path.join(__dirname, "tmp-node");
rmSync(tmpDir, { recursive: true, force: true });
(async function () {
// Download GitHub release artifact
console.log('Downloading NodeJS at', url);
console.log("Downloading NodeJS at", url);
const { filePath } = await new Downloader({
url,
directory: tmpDir,
@@ -82,11 +82,13 @@ rmSync(tmpDir, { recursive: true, force: true });
// Verify SHA256
const expectedHash = SHA256_MAP[key];
const fileBuffer = fs.readFileSync(filePath);
const actualHash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
const actualHash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
if (actualHash !== expectedHash) {
throw new Error(`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`);
throw new Error(
`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`,
);
}
console.log('SHA256 verified:', actualHash);
console.log("SHA256 verified:", actualHash);
// Decompress to the same directory
await decompress(filePath, tmpDir, {});
@@ -96,16 +98,16 @@ rmSync(tmpDir, { recursive: true, force: true });
cpSync(binSrc, binDest);
rmSync(tmpDir, { recursive: true, force: true });
console.log('Downloaded NodeJS to', binDest);
console.log("Downloaded NodeJS to", binDest);
})().catch((err) => {
console.log('Script failed:', err);
console.log("Script failed:", err);
process.exit(1);
});
function tryExecSync(cmd) {
try {
return execSync(cmd, { stdio: 'pipe' }).toString('utf-8');
return execSync(cmd, { stdio: "pipe" }).toString("utf-8");
} catch {
return '';
return "";
}
}

View File

@@ -1,31 +1,31 @@
const { readdirSync, cpSync, existsSync, mkdirSync } = require('node:fs');
const path = require('node:path');
const { readdirSync, cpSync, existsSync, mkdirSync } = require("node:fs");
const path = require("node:path");
const pluginsDir = path.join(__dirname, '..', 'plugins');
const externalPluginsDir = path.join(__dirname, '..', 'plugins-external');
const pluginsDir = path.join(__dirname, "..", "plugins");
const externalPluginsDir = path.join(__dirname, "..", "plugins-external");
// Get list of external (non-bundled) plugins
const externalPlugins = new Set();
if (existsSync(externalPluginsDir)) {
for (const name of readdirSync(externalPluginsDir)) {
if (!name.startsWith('.')) {
if (!name.startsWith(".")) {
externalPlugins.add(name);
}
}
}
console.log('Copying Yaak plugins to', pluginsDir);
console.log("Copying Yaak plugins to", pluginsDir);
for (const name of readdirSync(pluginsDir)) {
const dir = path.join(pluginsDir, name);
if (name.startsWith('.')) continue;
if (name.startsWith(".")) continue;
if (externalPlugins.has(name)) {
console.log(`Skipping ${name} (external plugin)`);
continue;
}
const destDir = path.join(__dirname, '../crates-tauri/yaak-app/vendored/plugins/', name);
const destDir = path.join(__dirname, "../crates-tauri/yaak-app/vendored/plugins/", name);
mkdirSync(destDir, { recursive: true });
console.log(`Copying ${name} to ${destDir}`);
cpSync(path.join(dir, 'package.json'), path.join(destDir, 'package.json'));
cpSync(path.join(dir, 'build'), path.join(destDir, 'build'), { recursive: true });
cpSync(path.join(dir, "package.json"), path.join(destDir, "package.json"));
cpSync(path.join(dir, "build"), path.join(destDir, "build"), { recursive: true });
}

View File

@@ -1,20 +1,20 @@
const crypto = require('node:crypto');
const fs = require('node:fs');
const decompress = require('decompress');
const Downloader = require('nodejs-file-downloader');
const path = require('node:path');
const { rmSync, mkdirSync, cpSync, existsSync, statSync, chmodSync } = require('node:fs');
const { execSync } = require('node:child_process');
const crypto = require("node:crypto");
const fs = require("node:fs");
const decompress = require("decompress");
const Downloader = require("nodejs-file-downloader");
const path = require("node:path");
const { rmSync, mkdirSync, cpSync, existsSync, statSync, chmodSync } = require("node:fs");
const { execSync } = require("node:child_process");
const VERSION = '33.1';
const VERSION = "33.1";
// `${process.platform}_${process.arch}`
const MAC_ARM = 'darwin_arm64';
const MAC_X64 = 'darwin_x64';
const LNX_ARM = 'linux_arm64';
const LNX_X64 = 'linux_x64';
const WIN_X64 = 'win32_x64';
const WIN_ARM = 'win32_arm64';
const MAC_ARM = "darwin_arm64";
const MAC_X64 = "darwin_x64";
const LNX_ARM = "linux_arm64";
const LNX_X64 = "linux_x64";
const WIN_X64 = "win32_x64";
const WIN_ARM = "win32_arm64";
const URL_MAP = {
[MAC_ARM]: `https://github.com/protocolbuffers/protobuf/releases/download/v${VERSION}/protoc-${VERSION}-osx-aarch_64.zip`,
@@ -26,43 +26,43 @@ const URL_MAP = {
};
const SRC_BIN_MAP = {
[MAC_ARM]: 'bin/protoc',
[MAC_X64]: 'bin/protoc',
[LNX_ARM]: 'bin/protoc',
[LNX_X64]: 'bin/protoc',
[WIN_X64]: 'bin/protoc.exe',
[WIN_ARM]: 'bin/protoc.exe',
[MAC_ARM]: "bin/protoc",
[MAC_X64]: "bin/protoc",
[LNX_ARM]: "bin/protoc",
[LNX_X64]: "bin/protoc",
[WIN_X64]: "bin/protoc.exe",
[WIN_ARM]: "bin/protoc.exe",
};
const DST_BIN_MAP = {
[MAC_ARM]: 'yaakprotoc',
[MAC_X64]: 'yaakprotoc',
[LNX_ARM]: 'yaakprotoc',
[LNX_X64]: 'yaakprotoc',
[WIN_X64]: 'yaakprotoc.exe',
[WIN_ARM]: 'yaakprotoc.exe',
[MAC_ARM]: "yaakprotoc",
[MAC_X64]: "yaakprotoc",
[LNX_ARM]: "yaakprotoc",
[LNX_X64]: "yaakprotoc",
[WIN_X64]: "yaakprotoc.exe",
[WIN_ARM]: "yaakprotoc.exe",
};
const SHA256_MAP = {
[MAC_ARM]: 'db7e66ff7f9080614d0f5505a6b0ac488cf89a15621b6a361672d1332ec2e14e',
[MAC_X64]: 'e20b5f930e886da85e7402776a4959efb1ed60c57e72794bcade765e67abaa82',
[LNX_ARM]: '6018147740548e0e0f764408c87f4cd040e6e1c1203e13aeacaf811892b604f3',
[LNX_X64]: 'f3340e28a83d1c637d8bafdeed92b9f7db6a384c26bca880a6e5217b40a4328b',
[WIN_X64]: 'd7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b',
[WIN_ARM]: 'd7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b',
[MAC_ARM]: "db7e66ff7f9080614d0f5505a6b0ac488cf89a15621b6a361672d1332ec2e14e",
[MAC_X64]: "e20b5f930e886da85e7402776a4959efb1ed60c57e72794bcade765e67abaa82",
[LNX_ARM]: "6018147740548e0e0f764408c87f4cd040e6e1c1203e13aeacaf811892b604f3",
[LNX_X64]: "f3340e28a83d1c637d8bafdeed92b9f7db6a384c26bca880a6e5217b40a4328b",
[WIN_X64]: "d7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b",
[WIN_ARM]: "d7a207fb6eec0e4b1b6613be3b7d11905375b6fd1147a071116eb8e9f24ac53b",
};
const dstDir = path.join(__dirname, `..`, 'crates-tauri', 'yaak-app', 'vendored', 'protoc');
const dstDir = path.join(__dirname, `..`, "crates-tauri", "yaak-app", "vendored", "protoc");
const key = `${process.platform}_${process.env.YAAK_TARGET_ARCH ?? process.arch}`;
console.log(`Vendoring protoc ${VERSION} for ${key}`);
const url = URL_MAP[key];
const tmpDir = path.join(__dirname, 'tmp-protoc');
const tmpDir = path.join(__dirname, "tmp-protoc");
const binSrc = path.join(tmpDir, SRC_BIN_MAP[key]);
const binDst = path.join(dstDir, DST_BIN_MAP[key]);
if (existsSync(binDst) && tryExecSync(`${binDst} --version`).trim().includes(VERSION)) {
console.log('Protoc already vendored');
console.log("Protoc already vendored");
return;
}
@@ -77,11 +77,13 @@ mkdirSync(dstDir, { recursive: true });
// Verify SHA256
const expectedHash = SHA256_MAP[key];
const fileBuffer = fs.readFileSync(filePath);
const actualHash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
const actualHash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
if (actualHash !== expectedHash) {
throw new Error(`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`);
throw new Error(
`SHA256 mismatch for ${path.basename(filePath)}\n expected: ${expectedHash}\n actual: ${actualHash}`,
);
}
console.log('SHA256 verified:', actualHash);
console.log("SHA256 verified:", actualHash);
// Decompress to the same directory
await decompress(filePath, tmpDir, {});
@@ -90,8 +92,8 @@ mkdirSync(dstDir, { recursive: true });
cpSync(binSrc, binDst);
// Copy other files
const includeSrc = path.join(tmpDir, 'include');
const includeDst = path.join(dstDir, 'include');
const includeSrc = path.join(tmpDir, "include");
const includeDst = path.join(dstDir, "include");
cpSync(includeSrc, includeDst, { recursive: true });
rmSync(tmpDir, { recursive: true, force: true });
@@ -100,13 +102,13 @@ mkdirSync(dstDir, { recursive: true });
const newMode = stat.mode | 0o200;
chmodSync(binDst, newMode);
console.log('Downloaded protoc to', binDst);
})().catch((err) => console.log('Script failed:', err));
console.log("Downloaded protoc to", binDst);
})().catch((err) => console.log("Script failed:", err));
function tryExecSync(cmd) {
try {
return execSync(cmd, { stdio: 'pipe' }).toString('utf-8');
return execSync(cmd, { stdio: "pipe" }).toString("utf-8");
} catch {
return '';
return "";
}
}