mirror of
https://github.com/andy-stack/vaultkeeper-ai.git
synced 2026-07-22 06:42:03 +00:00
Introduce a new AbortService to centralize cancellation logic across all async operations, replacing scattered AbortSignal parameters with a unified singleton service. This improves maintainability and provides consistent cancellation behavior throughout the application. Key changes: - Add AbortService for centralized abort signal management with automatic cleanup - Refactor all AI providers (Claude, Gemini, OpenAI) to use AbortService instead of passing AbortSignal parameters - Update streaming operations to use centralized abort handling - Add CancellationIndicator component to show visual feedback during operation cancellation - Rename ChatAreaThought to ThoughtIndicator for better semantic clarity - Add Environment enum for consistent environment detection - Enhance ChatService lifecycle with proper cancellation state management - Remove scattered abort-related UI selectors and error messages in favor of dedicated indicator - Add safeContinue() factory method to ConversationContent for internal continuations - Update all tests to reflect new abort handling architecture This change simplifies the API surface by removing AbortSignal parameters from method signatures while improving the user experience with clearer cancellation feedback.
167 lines
No EOL
4.5 KiB
JavaScript
167 lines
No EOL
4.5 KiB
JavaScript
import esbuild from "esbuild";
|
|
import process from "process";
|
|
import builtins from "builtin-modules";
|
|
import { copyFileSync, mkdirSync, existsSync, readdirSync, statSync, readFileSync, writeFileSync, unlinkSync, watch as fsWatch } from "fs";
|
|
import { join } from "path";
|
|
import esbuildSvelte from "esbuild-svelte";
|
|
import { sveltePreprocess } from "svelte-preprocess";
|
|
|
|
const banner =
|
|
`/*
|
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
if you want to view the source, please visit the github repository of this plugin
|
|
*/
|
|
`;
|
|
|
|
const prod = (process.argv[2] === "production");
|
|
|
|
// Clean up build artifacts that aren"t needed (main.css, main.js, font files)
|
|
const CLEANUP_BUILD_ARTIFACTS = true; // Set to false if you need to debug these files
|
|
|
|
// Function to copy directory recursively
|
|
function copyDir(src, dest) {
|
|
if (!existsSync(dest)) {
|
|
mkdirSync(dest, { recursive: true });
|
|
}
|
|
|
|
const files = readdirSync(src);
|
|
|
|
for (const file of files) {
|
|
const srcPath = join(src, file);
|
|
const destPath = join(dest, file);
|
|
|
|
if (statSync(srcPath).isDirectory()) {
|
|
copyDir(srcPath, destPath);
|
|
} else {
|
|
copyFileSync(srcPath, destPath);
|
|
console.log(`📁 Copied: ${srcPath} → ${destPath}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Plugin to merge CSS files into styles.css and cleanup build artifacts
|
|
const cssMergerPlugin = {
|
|
name: "css-merger",
|
|
setup(build) {
|
|
build.onEnd(() => {
|
|
// esbuild outputs CSS as main.css (based on outfile: main.js)
|
|
const generatedCss = "main.css";
|
|
const customCssDir = "Styles";
|
|
const outputCss = "styles.css";
|
|
|
|
let mergedCss = "";
|
|
|
|
// Read generated CSS from dependencies if it exists
|
|
if (existsSync(generatedCss)) {
|
|
mergedCss += readFileSync(generatedCss, "utf-8");
|
|
mergedCss += "\n\n/* Custom Styles */\n\n";
|
|
}
|
|
|
|
// Append custom CSS files from styles directory
|
|
if (existsSync(customCssDir)) {
|
|
const cssFiles = readdirSync(customCssDir)
|
|
.filter(file => file.endsWith(".css"))
|
|
.sort();
|
|
|
|
for (const cssFile of cssFiles) {
|
|
const cssPath = join(customCssDir, cssFile);
|
|
mergedCss += readFileSync(cssPath, "utf-8");
|
|
mergedCss += "\n\n";
|
|
console.log(`📦 Merged: ${cssPath}`);
|
|
}
|
|
}
|
|
|
|
// Write merged CSS to styles.css
|
|
writeFileSync(outputCss, mergedCss);
|
|
console.log(`✅ Generated: ${outputCss}`);
|
|
|
|
// Clean up build artifacts if enabled
|
|
if (CLEANUP_BUILD_ARTIFACTS) {
|
|
// Remove main.css (intermediate CSS file)
|
|
if (existsSync(generatedCss)) {
|
|
unlinkSync(generatedCss);
|
|
console.log(`🗑️ Removed: ${generatedCss}`);
|
|
}
|
|
|
|
// Remove KaTeX font files
|
|
let anyRemoved = false;
|
|
const fontExtensions = [".woff", ".woff2", ".ttf"];
|
|
const files = readdirSync(".");
|
|
for (const file of files) {
|
|
const ext = file.substring(file.lastIndexOf("."));
|
|
if (fontExtensions.includes(ext)) {
|
|
unlinkSync(file);
|
|
anyRemoved = true;
|
|
}
|
|
}
|
|
if (anyRemoved) {
|
|
console.log("🗑️ Removed KaTeX Font Files");
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
const buildOptions = {
|
|
plugins: [
|
|
esbuildSvelte({
|
|
compilerOptions: { css: "injected" },
|
|
preprocess: sveltePreprocess(),
|
|
}),
|
|
cssMergerPlugin,
|
|
],
|
|
banner: {
|
|
js: banner,
|
|
},
|
|
entryPoints: ["main.ts"],
|
|
bundle: true,
|
|
define: {
|
|
"process.env.NODE_ENV": JSON.stringify(prod ? "production" : "development"),
|
|
},
|
|
external: [
|
|
"obsidian",
|
|
"electron",
|
|
"@codemirror/autocomplete",
|
|
"@codemirror/collab",
|
|
"@codemirror/commands",
|
|
"@codemirror/language",
|
|
"@codemirror/lint",
|
|
"@codemirror/search",
|
|
"@codemirror/state",
|
|
"@codemirror/view",
|
|
"@lezer/common",
|
|
"@lezer/highlight",
|
|
"@lezer/lr",
|
|
...builtins],
|
|
format: "cjs",
|
|
target: "es2018",
|
|
logLevel: "info",
|
|
sourcemap: prod ? false : "inline",
|
|
treeShaking: true,
|
|
outfile: "main.js",
|
|
minify: prod,
|
|
loader: {
|
|
".css": "css",
|
|
".ttf": "file",
|
|
".woff": "file",
|
|
".woff2": "file",
|
|
},
|
|
};
|
|
|
|
if (prod) {
|
|
await esbuild.build(buildOptions);
|
|
console.log("✅ Production build complete!");
|
|
} else {
|
|
const ctx = await esbuild.context(buildOptions);
|
|
await ctx.watch();
|
|
|
|
// Watch Styles directory for CSS changes
|
|
if (existsSync("Styles")) {
|
|
fsWatch("Styles", { recursive: true }, (_eventType, filename) => {
|
|
if (filename && filename.endsWith(".css")) {
|
|
console.log(`🔄 CSS file changed: ${filename} - Rebuilding...`);
|
|
ctx.rebuild();
|
|
}
|
|
});
|
|
}
|
|
} |