feat: complete debranding of MoreMinimore by removing Dyad dependencies and integrating custom features
This commit is contained in:
1
src/custom/index.ts
Normal file
1
src/custom/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const REMOVE_LIMIT_ENABLED = true;
|
||||
@@ -1,94 +0,0 @@
|
||||
import fetch from "node-fetch"; // Electron main process might need node-fetch
|
||||
import log from "electron-log";
|
||||
import { createLoggedHandler } from "./safe_handle";
|
||||
import { readSettings } from "../../main/settings"; // Assuming settings are read this way
|
||||
import { UserBudgetInfo, UserBudgetInfoSchema } from "../ipc_types";
|
||||
import { IS_TEST_BUILD } from "../utils/test_utils";
|
||||
import { z } from "zod";
|
||||
|
||||
export const UserInfoResponseSchema = z.object({
|
||||
usedCredits: z.number(),
|
||||
totalCredits: z.number(),
|
||||
budgetResetDate: z.string(), // ISO date string from API
|
||||
userId: z.string(),
|
||||
});
|
||||
export type UserInfoResponse = z.infer<typeof UserInfoResponseSchema>;
|
||||
|
||||
const logger = log.scope("pro_handlers");
|
||||
const handle = createLoggedHandler(logger);
|
||||
|
||||
export function registerProHandlers() {
|
||||
// This method should try to avoid throwing errors because this is auxiliary
|
||||
// information and isn't critical to using the app
|
||||
handle("get-user-budget", async (): Promise<UserBudgetInfo | null> => {
|
||||
if (IS_TEST_BUILD) {
|
||||
// Return mock budget data for E2E tests instead of spamming the API
|
||||
const resetDate = new Date();
|
||||
resetDate.setDate(resetDate.getDate() + 30); // Reset in 30 days
|
||||
return {
|
||||
usedCredits: 100,
|
||||
totalCredits: 1000,
|
||||
budgetResetDate: resetDate,
|
||||
redactedUserId: "<redacted-user-id-testing>",
|
||||
};
|
||||
}
|
||||
logger.info("Attempting to fetch user budget information.");
|
||||
|
||||
const settings = readSettings();
|
||||
|
||||
const apiKey = settings.providerSettings?.auto?.apiKey?.value;
|
||||
|
||||
if (!apiKey) {
|
||||
logger.error("LLM Gateway API key (Dyad Pro) is not configured.");
|
||||
return null;
|
||||
}
|
||||
|
||||
const url = "https://api.dyad.sh/v1/user/info";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
};
|
||||
|
||||
try {
|
||||
// Use native fetch if available, otherwise node-fetch will be used via import
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
logger.error(
|
||||
`Failed to fetch user budget. Status: ${response.status}. Body: ${errorBody}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawData = await response.json();
|
||||
|
||||
// Validate the API response structure
|
||||
const data = UserInfoResponseSchema.parse(rawData);
|
||||
|
||||
// Turn user_abc1234 => "****1234"
|
||||
// Preserve the last 4 characters so we can correlate bug reports
|
||||
// with the user.
|
||||
const redactedUserId =
|
||||
data.userId.length > 8 ? "****" + data.userId.slice(-4) : "<redacted>";
|
||||
|
||||
logger.info("Successfully fetched user budget information.");
|
||||
|
||||
// Transform to UserBudgetInfo format
|
||||
const userBudgetInfo = UserBudgetInfoSchema.parse({
|
||||
usedCredits: data.usedCredits,
|
||||
totalCredits: data.totalCredits,
|
||||
budgetResetDate: new Date(data.budgetResetDate),
|
||||
redactedUserId: redactedUserId,
|
||||
});
|
||||
|
||||
return userBudgetInfo;
|
||||
} catch (error: any) {
|
||||
logger.error(`Error fetching user budget: ${error.message}`, error);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import log from "electron-log";
|
||||
import fetch from "node-fetch";
|
||||
import { createLoggedHandler } from "./safe_handle";
|
||||
import { DoesReleaseNoteExistParams } from "../ipc_types";
|
||||
import { IS_TEST_BUILD } from "../utils/test_utils";
|
||||
@@ -23,41 +22,9 @@ export function registerReleaseNoteHandlers() {
|
||||
if (IS_TEST_BUILD) {
|
||||
return { exists: false };
|
||||
}
|
||||
const releaseNoteUrl = `https://www.dyad.sh/docs/releases/${version}`;
|
||||
|
||||
logger.debug(`Checking for release note at: ${releaseNoteUrl}`);
|
||||
|
||||
try {
|
||||
const response = await fetch(releaseNoteUrl, { method: "HEAD" }); // Use HEAD to check existence without downloading content
|
||||
if (response.ok) {
|
||||
logger.debug(
|
||||
`Release note found for version ${version} at ${releaseNoteUrl}`,
|
||||
);
|
||||
return { exists: true, url: releaseNoteUrl };
|
||||
} else if (response.status === 404) {
|
||||
logger.debug(
|
||||
`Release note not found for version ${version} at ${releaseNoteUrl}`,
|
||||
);
|
||||
return { exists: false };
|
||||
} else {
|
||||
// Log other non-404 errors but still treat as "not found" for the client,
|
||||
// as the primary goal is to check existence.
|
||||
logger.warn(
|
||||
`Unexpected status code ${response.status} when checking for release note: ${releaseNoteUrl}`,
|
||||
);
|
||||
return { exists: false };
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Error fetching release note for version ${version} at ${releaseNoteUrl}:`,
|
||||
error,
|
||||
);
|
||||
// In case of network errors, etc., assume it doesn't exist or is inaccessible.
|
||||
// Throwing an error here would propagate to the client and might be too disruptive
|
||||
// if the check is just for UI purposes (e.g., showing a link).
|
||||
// Consider if specific errors should be thrown based on requirements.
|
||||
return { exists: false };
|
||||
}
|
||||
// Release notes disabled - removed Dyad API dependency
|
||||
logger.debug(`Release notes check disabled for version ${version}`);
|
||||
return { exists: false };
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import { registerLanguageModelHandlers } from "./handlers/language_model_handler
|
||||
import { registerReleaseNoteHandlers } from "./handlers/release_note_handlers";
|
||||
import { registerImportHandlers } from "./handlers/import_handlers";
|
||||
import { registerSessionHandlers } from "./handlers/session_handlers";
|
||||
import { registerProHandlers } from "./handlers/pro_handlers";
|
||||
import { registerContextPathsHandlers } from "./handlers/context_paths_handlers";
|
||||
import { registerAppUpgradeHandlers } from "./handlers/app_upgrade_handlers";
|
||||
import { registerCapacitorHandlers } from "./handlers/capacitor_handlers";
|
||||
@@ -60,7 +59,6 @@ export function registerIpcHandlers() {
|
||||
registerReleaseNoteHandlers();
|
||||
registerImportHandlers();
|
||||
registerSessionHandlers();
|
||||
registerProHandlers();
|
||||
registerContextPathsHandlers();
|
||||
registerAppUpgradeHandlers();
|
||||
registerCapacitorHandlers();
|
||||
|
||||
@@ -19,14 +19,14 @@ import log from "electron-log";
|
||||
import { FREE_OPENROUTER_MODEL_NAMES } from "../shared/language_model_constants";
|
||||
import { getLanguageModelProviders } from "../shared/language_model_helpers";
|
||||
import { LanguageModelProvider } from "../ipc_types";
|
||||
import { createDyadEngine } from "./llm_engine_provider";
|
||||
// import { createDyadEngine } from "./llm_engine_provider"; // Removed - Dyad Engine dependency
|
||||
|
||||
import { LM_STUDIO_BASE_URL } from "./lm_studio_utils";
|
||||
import { createOllamaProvider } from "./ollama_provider";
|
||||
import { getOllamaApiUrl } from "../handlers/local_model_ollama_handler";
|
||||
import { createFallback } from "./fallback_ai_model";
|
||||
|
||||
const dyadEngineUrl = process.env.DYAD_ENGINE_URL;
|
||||
// const dyadEngineUrl = process.env.DYAD_ENGINE_URL; // Removed - Dyad Engine dependency
|
||||
|
||||
const AUTO_MODELS = [
|
||||
{
|
||||
@@ -73,56 +73,13 @@ export async function getModelClient(
|
||||
throw new Error(`Configuration not found for provider: ${model.provider}`);
|
||||
}
|
||||
|
||||
// Handle Dyad Pro override
|
||||
// Dyad Pro functionality removed - eliminated Dyad Engine dependency
|
||||
// All models now use direct provider connections
|
||||
if (dyadApiKey && settings.enableDyadPro) {
|
||||
// Check if the selected provider supports Dyad Pro (has a gateway prefix) OR
|
||||
// we're using local engine.
|
||||
// IMPORTANT: some providers like OpenAI have an empty string gateway prefix,
|
||||
// so we do a nullish and not a truthy check here.
|
||||
if (providerConfig.gatewayPrefix != null || dyadEngineUrl) {
|
||||
const enableSmartFilesContext = settings.enableProSmartFilesContextMode;
|
||||
const provider = createDyadEngine({
|
||||
apiKey: dyadApiKey,
|
||||
baseURL: dyadEngineUrl ?? "https://engine.dyad.sh/v1",
|
||||
originalProviderId: model.provider,
|
||||
dyadOptions: {
|
||||
enableLazyEdits:
|
||||
settings.selectedChatMode === "ask"
|
||||
? false
|
||||
: settings.enableProLazyEditsMode &&
|
||||
settings.proLazyEditsMode !== "v2",
|
||||
enableSmartFilesContext,
|
||||
enableWebSearch: settings.enableProWebSearch,
|
||||
},
|
||||
settings,
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`\x1b[1;97;44m Using Dyad Pro API key for model: ${model.name} \x1b[0m`,
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`\x1b[1;30;42m Using Dyad Pro engine: ${dyadEngineUrl ?? "<prod>"} \x1b[0m`,
|
||||
);
|
||||
|
||||
// Do not use free variant (for openrouter).
|
||||
const modelName = model.name.split(":free")[0];
|
||||
const autoModelClient = {
|
||||
model: provider(`${providerConfig.gatewayPrefix || ""}${modelName}`),
|
||||
builtinProviderId: model.provider,
|
||||
};
|
||||
|
||||
return {
|
||||
modelClient: autoModelClient,
|
||||
isEngineEnabled: true,
|
||||
isSmartContextEnabled: enableSmartFilesContext,
|
||||
};
|
||||
} else {
|
||||
logger.warn(
|
||||
`Dyad Pro enabled, but provider ${model.provider} does not have a gateway prefix defined. Falling back to direct provider connection.`,
|
||||
);
|
||||
// Fall through to regular provider logic if gateway prefix is missing
|
||||
}
|
||||
logger.warn(
|
||||
`Dyad Pro was enabled but has been disabled to remove Dyad API dependency. Falling back to direct provider connection.`,
|
||||
);
|
||||
// Fall through to regular provider logic
|
||||
}
|
||||
// Handle 'auto' provider by trying each model in AUTO_MODELS until one works
|
||||
if (model.provider === "auto") {
|
||||
|
||||
@@ -1,71 +1,14 @@
|
||||
import {
|
||||
type Template,
|
||||
type ApiTemplate,
|
||||
localTemplatesData,
|
||||
} from "../../shared/templates";
|
||||
import log from "electron-log";
|
||||
|
||||
const logger = log.scope("template_utils");
|
||||
|
||||
// In-memory cache for API templates
|
||||
let apiTemplatesCache: Template[] | null = null;
|
||||
let apiTemplatesFetchPromise: Promise<Template[]> | null = null;
|
||||
|
||||
// Convert API template to our Template interface
|
||||
function convertApiTemplate(apiTemplate: ApiTemplate): Template {
|
||||
return {
|
||||
id: `${apiTemplate.githubOrg}/${apiTemplate.githubRepo}`,
|
||||
title: apiTemplate.title,
|
||||
description: apiTemplate.description,
|
||||
imageUrl: apiTemplate.imageUrl,
|
||||
githubUrl: `https://github.com/${apiTemplate.githubOrg}/${apiTemplate.githubRepo}`,
|
||||
isOfficial: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch templates from API with caching
|
||||
export async function fetchApiTemplates(): Promise<Template[]> {
|
||||
// Return cached data if available
|
||||
if (apiTemplatesCache) {
|
||||
return apiTemplatesCache;
|
||||
}
|
||||
|
||||
// Return existing promise if fetch is already in progress
|
||||
if (apiTemplatesFetchPromise) {
|
||||
return apiTemplatesFetchPromise;
|
||||
}
|
||||
|
||||
// Start new fetch
|
||||
apiTemplatesFetchPromise = (async (): Promise<Template[]> => {
|
||||
try {
|
||||
const response = await fetch("https://api.dyad.sh/v1/templates");
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch templates: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const apiTemplates: ApiTemplate[] = await response.json();
|
||||
const convertedTemplates = apiTemplates.map(convertApiTemplate);
|
||||
|
||||
// Cache the result
|
||||
apiTemplatesCache = convertedTemplates;
|
||||
return convertedTemplates;
|
||||
} catch (error) {
|
||||
logger.error("Failed to fetch API templates:", error);
|
||||
// Reset the promise so we can retry later
|
||||
apiTemplatesFetchPromise = null;
|
||||
return []; // Return empty array on error
|
||||
}
|
||||
})();
|
||||
|
||||
return apiTemplatesFetchPromise;
|
||||
}
|
||||
|
||||
// Get all templates (local + API)
|
||||
// Get all templates (local only - API templates removed)
|
||||
export async function getAllTemplates(): Promise<Template[]> {
|
||||
const apiTemplates = await fetchApiTemplates();
|
||||
return [...localTemplatesData, ...apiTemplates];
|
||||
return [...localTemplatesData];
|
||||
}
|
||||
|
||||
export async function getTemplateOrThrow(
|
||||
|
||||
22
src/main.ts
22
src/main.ts
@@ -4,7 +4,7 @@ import { registerIpcHandlers } from "./ipc/ipc_host";
|
||||
import dotenv from "dotenv";
|
||||
// @ts-ignore
|
||||
import started from "electron-squirrel-startup";
|
||||
import { updateElectronApp, UpdateSourceType } from "update-electron-app";
|
||||
// import { updateElectronApp, UpdateSourceType } from "update-electron-app"; // Removed - Dyad API dependency
|
||||
import log from "electron-log";
|
||||
import {
|
||||
getSettingsFilePath,
|
||||
@@ -107,23 +107,9 @@ export async function onReady() {
|
||||
await onFirstRunMaybe(settings);
|
||||
createWindow();
|
||||
|
||||
logger.info("Auto-update enabled=", settings.enableAutoUpdate);
|
||||
if (settings.enableAutoUpdate) {
|
||||
// Technically we could just pass the releaseChannel directly to the host,
|
||||
// but this is more explicit and falls back to stable if there's an unknown
|
||||
// release channel.
|
||||
const postfix = settings.releaseChannel === "beta" ? "beta" : "stable";
|
||||
const host = `https://api.dyad.sh/v1/update/${postfix}`;
|
||||
logger.info("Auto-update release channel=", postfix);
|
||||
updateElectronApp({
|
||||
logger,
|
||||
updateSource: {
|
||||
type: UpdateSourceType.ElectronPublicUpdateService,
|
||||
repo: "dyad-sh/dyad",
|
||||
host,
|
||||
},
|
||||
}); // additional configuration options available
|
||||
}
|
||||
logger.info("Auto-update disabled - removed Dyad API dependency");
|
||||
// Auto-update functionality removed to eliminate Dyad API dependency
|
||||
// Users can manually update by downloading new releases from GitHub
|
||||
}
|
||||
|
||||
export async function onFirstRunMaybe(settings: UserSettings) {
|
||||
|
||||
Reference in New Issue
Block a user