chore: remove dead code (59 unused files + ~125 unused exports) (#1835)

* chore: remove dead/unreferenced files across ui, vscode

Remove 59 unused source files (components, hooks, lib utils, stores,
barrels, and orphaned vscode github modules) that are not imported by
any entry-reachable code. Also drop a stale test mock for the removed
execCommands module.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* refactor: remove unused exported symbols (types, functions, consts, hooks)

Remove exported symbols whose identifier is referenced nowhere in the
repository (verified via repo-wide search), across ui types/contracts,
lib utilities, sync layer, stores, and components. Also drop the few
imports/private helpers orphaned by these removals.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* refactor: remove more unused exports (desktop, shortcuts, worktree, vscode)

Continue removing repo-wide unreferenced exported functions, consts and
types across lib/desktop, shortcuts, worktreeSessionCreator, sync, and
vscode gitService, with cascading orphaned helpers/imports cleaned up.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* chore: add dead-code cleanup tooling

* refactor: checkpoint dead-code cleanup

* refactor: remove dead-code suppressions

---------

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Serhii Dziupin
2026-06-26 19:27:53 +03:00
committed by GitHub
co-authored by Serhii Dziupin Bohdan Triapitsyn
parent 4a37b9a005
commit 00821700de
324 changed files with 444 additions and 14876 deletions
+2 -2
View File
@@ -41,7 +41,7 @@ export async function checkCloudflaredAvailable() {
return { available: false, path: null, version: null };
}
export function printCloudflareTunnelInstallHelp() {
function printCloudflareTunnelInstallHelp() {
const platform = process.platform;
let installCmd = '';
@@ -600,7 +600,7 @@ export async function startCloudflareManagedLocalTunnel({ configPath, hostname }
};
}
export async function startCloudflareTunnel({ originUrl, port }) {
async function startCloudflareTunnel({ originUrl, port }) {
void port;
return startCloudflareQuickTunnel({ originUrl });
}
@@ -2,7 +2,7 @@ import { createUpstreamSseReader } from './upstream-reader.js';
// Raised from 512 → 2048 to improve recovery after brief disconnects during
// long-running agent sessions where many events accumulate quickly.
export const MESSAGE_STREAM_GLOBAL_REPLAY_LIMIT = 2048;
const MESSAGE_STREAM_GLOBAL_REPLAY_LIMIT = 2048;
export function createGlobalMessageStreamHub({
buildOpenCodeUrl,
@@ -1,25 +1,13 @@
export {
MESSAGE_STREAM_GLOBAL_WS_PATH,
MESSAGE_STREAM_DIRECTORY_WS_PATH,
MESSAGE_STREAM_WS_HEARTBEAT_INTERVAL_MS,
parseSseEventEnvelope,
sendMessageStreamWsFrame,
sendMessageStreamWsEvent,
} from './protocol.js';
export {
createGlobalUiEventBroadcaster,
createMessageStreamWsRuntime,
} from './runtime.js';
export {
MESSAGE_STREAM_GLOBAL_REPLAY_LIMIT,
createGlobalMessageStreamHub,
} from './global-hub.js';
export {
DEFAULT_UPSTREAM_RECONNECT_DELAY_MS,
DEFAULT_UPSTREAM_STALL_TIMEOUT_MS,
UPSTREAM_STALL_TIMEOUT_CONCURRENT_MS,
createUpstreamSseReader,
} from './upstream-reader.js';
@@ -1,6 +1,6 @@
import { WebSocketServer } from 'ws';
import { parseRequestPathname } from '../terminal/index.js';
import { parseRequestPathname } from '../terminal/terminal-ws-protocol.js';
import {
MESSAGE_STREAM_DIRECTORY_WS_PATH,
MESSAGE_STREAM_GLOBAL_WS_PATH,
@@ -1,4 +1 @@
export { truncateNotificationText, prepareNotificationLastMessage } from './message.js';
export { createNotificationTriggerRuntime } from './runtime.js';
export { createPushRuntime } from './push-runtime.js';
export { createNotificationTemplateRuntime } from './template-runtime.js';
export { prepareNotificationLastMessage } from './message.js';
@@ -685,12 +685,6 @@ function deleteAgent(agentName, workingDirectory, scope) {
}
export {
ensureProjectAgentDir,
getProjectAgentPath,
getUserAgentPath,
getAgentScope,
getAgentWritePath,
getAgentPermissionSource,
getAgentSources,
getAgentConfig,
createAgent,
@@ -327,11 +327,6 @@ function deleteCommand(commandName, workingDirectory) {
}
export {
ensureProjectCommandDir,
getProjectCommandPath,
getUserCommandPath,
getCommandScope,
getCommandWritePath,
getCommandSources,
createCommand,
updateCommand,
@@ -13,6 +13,33 @@ import { registerPluginRoutes } from './plugin-routes.js';
import { getNpmInfo, clearCache as clearNpmCache } from './npm-registry.js';
import { parseNpmSpec, parsePathSpec, isExactSemver } from './plugin-spec.js';
import { registerOpenCodeRoutes } from './routes.js';
import { getProviderSources, removeProviderConfig } from './providers.js';
import { getAgentSources, getAgentConfig, createAgent, updateAgent, deleteAgent } from './agents.js';
import { getCommandSources, createCommand, updateCommand, deleteCommand } from './commands.js';
import { listMcpConfigs, getMcpConfig, createMcpConfig, updateMcpConfig, deleteMcpConfig } from './mcp.js';
import { listSnippets, getSnippet, createSnippet, updateSnippet, deleteSnippet, expandSnippets } from './snippets.js';
import {
listPluginEntries,
getPluginEntry,
createPluginEntry,
updatePluginEntry,
deletePluginEntry,
listPluginDirFiles,
readPluginDirFile,
writePluginDirFile,
deletePluginDirFile,
encodePluginId,
decodePluginId,
} from './plugins.js';
import { SKILL_DIR, SKILL_SCOPE, readSkillSupportingFile, writeSkillSupportingFile, deleteSkillSupportingFile } from './shared.js';
import { getSkillSources, discoverSkills, mergeDiscoveredSkills, createSkill, updateSkill, deleteSkill } from './skills.js';
import { getCuratedSkillsSources } from '../skills-catalog/curated-sources.js';
import { getCacheKey, getCachedScan, setCachedScan } from '../skills-catalog/cache.js';
import { isClawdHubSource, parseSkillRepoSource } from '../skills-catalog/source.js';
import { scanSkillsRepository } from '../skills-catalog/scan.js';
import { installSkillsFromRepository } from '../skills-catalog/install.js';
import { scanClawdHubPage } from '../skills-catalog/clawdhub/scan.js';
import { installSkillsFromClawdHub } from '../skills-catalog/clawdhub/install.js';
export const createFeatureRoutesRuntime = (dependencies) => {
const {
@@ -63,8 +90,6 @@ export const createFeatureRoutesRuntime = (dependencies) => {
writeSseEvent,
} = routeDependencies;
const { getProviderSources, removeProviderConfig } = await import('./index.js');
registerSettingsUtilityRoutes(app, {
readCustomThemesFromDisk,
refreshOpenCodeAfterConfigChange,
@@ -111,40 +136,6 @@ export const createFeatureRoutesRuntime = (dependencies) => {
writeSseEvent,
});
const {
getAgentSources,
getAgentConfig,
createAgent,
updateAgent,
deleteAgent,
getCommandSources,
createCommand,
updateCommand,
deleteCommand,
listMcpConfigs,
getMcpConfig,
createMcpConfig,
updateMcpConfig,
deleteMcpConfig,
listSnippets,
getSnippet,
createSnippet,
updateSnippet,
deleteSnippet,
expandSnippets,
listPluginEntries,
getPluginEntry,
createPluginEntry,
updatePluginEntry,
deletePluginEntry,
listPluginDirFiles,
readPluginDirFile,
writePluginDirFile,
deletePluginDirFile,
encodePluginId,
decodePluginId,
} = await import('./index.js');
registerConfigEntityRoutes(app, {
resolveProjectDirectory,
resolveOptionalProjectDirectory,
@@ -193,32 +184,6 @@ export const createFeatureRoutesRuntime = (dependencies) => {
isExactSemver,
});
const {
getSkillSources,
discoverSkills,
mergeDiscoveredSkills,
createSkill,
updateSkill,
deleteSkill,
readSkillSupportingFile,
writeSkillSupportingFile,
deleteSkillSupportingFile,
SKILL_SCOPE,
SKILL_DIR,
} = await import('./index.js');
const {
getCuratedSkillsSources,
getCacheKey,
getCachedScan,
setCachedScan,
parseSkillRepoSource,
scanSkillsRepository,
installSkillsFromRepository,
scanClawdHubPage,
installSkillsFromClawdHub,
isClawdHubSource,
} = await import('../skills-catalog/index.js');
const { getProfiles, getProfile } = await import('../git/index.js');
registerSkillRoutes(app, {
-95
View File
@@ -1,95 +0,0 @@
export {
AGENT_DIR,
COMMAND_DIR,
SKILL_DIR,
CONFIG_FILE,
AGENT_SCOPE,
COMMAND_SCOPE,
SKILL_SCOPE,
readConfig,
writeConfig,
readSkillSupportingFile,
writeSkillSupportingFile,
deleteSkillSupportingFile,
} from './shared.js';
export {
getAgentScope,
getAgentPermissionSource,
getAgentSources,
getAgentConfig,
createAgent,
updateAgent,
deleteAgent,
} from './agents.js';
export {
getCommandScope,
getCommandSources,
createCommand,
updateCommand,
deleteCommand,
} from './commands.js';
export {
getSkillSources,
getSkillScope,
discoverSkills,
mergeDiscoveredSkills,
createSkill,
updateSkill,
deleteSkill,
} from './skills.js';
export {
getProviderSources,
removeProviderConfig,
} from './providers.js';
export {
readAuthFile,
writeAuthFile,
removeProviderAuth,
getProviderAuth,
listProviderAuths,
AUTH_FILE,
OPENCODE_DATA_DIR,
} from './auth.js';
export { createUiAuth } from '../ui-auth/ui-auth.js';
export {
listMcpConfigs,
getMcpConfig,
createMcpConfig,
updateMcpConfig,
deleteMcpConfig,
} from './mcp.js';
export {
listPluginEntries,
getPluginEntry,
createPluginEntry,
updatePluginEntry,
deletePluginEntry,
listPluginDirFiles,
readPluginDirFile,
writePluginDirFile,
deletePluginDirFile,
encodePluginId,
decodePluginId,
parsePluginRaw,
serializePluginEntry,
} from './plugins.js';
export {
listSnippets,
getSnippet,
createSnippet,
updateSnippet,
deleteSnippet,
expandSnippets,
} from './snippets.js';
export { getNpmInfo, lookupNpmPackage, clearCache as clearNpmCache } from './npm-registry.js';
export { parseNpmSpec, parsePathSpec, isExactSemver } from './plugin-spec.js';
@@ -2,9 +2,9 @@ import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
export const NPM_CACHE_TTL_MS = 3_600_000;
export const NPM_FETCH_TIMEOUT_MS = 5_000;
export const NPM_REGISTRY_BASE = 'https://registry.npmjs.org';
const NPM_CACHE_TTL_MS = 3_600_000;
const NPM_FETCH_TIMEOUT_MS = 5_000;
const NPM_REGISTRY_BASE = 'https://registry.npmjs.org';
/**
* @typedef {Object} NpmPackagePayload
+3 -3
View File
@@ -50,7 +50,7 @@ export const normalizeForwardedDirectoryHeaders = (headers) => {
return headers;
};
export const waitForSseDrain = (res, signal) => new Promise((resolve) => {
const waitForSseDrain = (res, signal) => new Promise((resolve) => {
if (signal?.aborted || res.writableEnded || res.destroyed) {
resolve();
return;
@@ -132,7 +132,7 @@ const SESSION_LIST_ALLOWED_FIELDS = [
'project',
];
export const sanitizeSessionListItem = (session) => {
const sanitizeSessionListItem = (session) => {
if (!session || typeof session !== 'object' || Array.isArray(session)) {
return session;
}
@@ -168,7 +168,7 @@ export const sanitizeSessionListItem = (session) => {
return sanitized;
};
export const sanitizeSessionListPayload = (payload) => {
const sanitizeSessionListPayload = (payload) => {
if (!Array.isArray(payload)) {
return payload;
}
@@ -507,20 +507,14 @@ export {
COMMAND_DIR,
SKILL_DIR,
CONFIG_FILE,
CUSTOM_CONFIG_FILE,
PROMPT_FILE_PATTERN,
AGENT_SCOPE,
COMMAND_SCOPE,
SKILL_SCOPE,
ensureDirs,
parseMdFile,
writeMdFile,
getProjectConfigCandidates,
getProjectConfigPath,
getConfigPaths,
readConfigFile,
isPlainObject,
mergeConfigs,
readConfigLayers,
readConfig,
getConfigForPath,
@@ -594,8 +594,6 @@ function deleteSkill(skillName, workingDirectory) {
export {
getSkillSources,
getSkillScope,
getSkillWritePath,
discoverSkills,
mergeDiscoveredSkills,
createSkill,
@@ -240,5 +240,3 @@ export function expandSnippets(text, workingDirectory) {
const expanded = expandText(text || '', registry, new Map(), collector).trim();
return [...collector.prepend, expanded, ...collector.append].filter(Boolean).join('\n\n');
}
export { assertValidSnippetName };
+5 -5
View File
@@ -483,7 +483,7 @@ export function detectPackageManagerDetails() {
};
}
export function detectPackageManager() {
function detectPackageManager() {
return detectPackageManagerDetails().packageManager;
}
@@ -621,7 +621,7 @@ export function getUpdateCommand(pm = detectPackageManager()) {
/**
* Get current installed version from package.json
*/
export function getCurrentVersion() {
function getCurrentVersion() {
try {
const pkgPath = path.resolve(__dirname, '..', '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
@@ -634,7 +634,7 @@ export function getCurrentVersion() {
/**
* Fetch latest version from npm registry
*/
export async function getLatestVersion() {
async function getLatestVersion() {
try {
const response = await fetch(NPM_REGISTRY_URL, {
headers: { Accept: 'application/json' },
@@ -690,7 +690,7 @@ function compareVersions(left, right) {
/**
* Fetch changelog notes between versions
*/
export async function fetchChangelogNotes(fromVersion, toVersion) {
async function fetchChangelogNotes(fromVersion, toVersion) {
try {
const response = await fetch(CHANGELOG_URL, {
signal: AbortSignal.timeout(10000),
@@ -769,7 +769,7 @@ export async function checkForUpdates(options = {}) {
/**
* Execute the update (used by CLI)
*/
export function executeUpdate(pm = detectPackageManager(), options = {}) {
function executeUpdate(pm = detectPackageManager(), options = {}) {
const command = getUpdateCommand(pm);
if (!options?.silent) {
console.log(`Updating ${PACKAGE_NAME} using ${pm}...`);
@@ -557,11 +557,3 @@ export const createProjectConfigRuntime = (deps) => {
resolveProjectConfigPath,
};
};
export {
MAX_TASK_NAME_LENGTH,
MAX_TASK_PROMPT_LENGTH,
MAX_CRON_LENGTH,
MAX_LAST_ERROR_LENGTH,
normalizeTaskForStorage,
};
@@ -7,7 +7,6 @@ This module fetches quota and usage signals for supported providers in the web s
- `packages/web/server/lib/quota/index.js`: public entrypoint imported by `packages/web/server/index.js`.
- `packages/web/server/lib/quota/routes.js`: Express route registration for quota endpoints.
- `packages/web/server/lib/quota/providers/index.js`: provider registry, configured-provider list, and provider dispatcher.
- `packages/web/server/lib/quota/providers/interface.js`: JSDoc provider contract used as implementation reference.
- `packages/web/server/lib/quota/providers/google/`: Google-specific auth, API, and transform modules.
- `packages/web/server/lib/quota/utils/`: shared auth, transform, and formatting helpers.
@@ -42,6 +41,9 @@ All providers should return results via shared helpers to preserve API shape:
- Optional field: `error`
- Unsupported provider requests should return `ok: false`, `configured: false`, `error: Unsupported provider`
Provider modules must export `providerId`, `providerName`, `aliases`, `isConfigured(auth?)`, and `fetchQuota()`.
`fetchQuota()` should return a quota result with `usage.windows` keyed by window name (for example `5h`, `7d`, `daily`) and optional provider-specific `usage.models` data.
## Add a new provider (quick steps)
1. Choose module shape based on complexity:
- Simple providers: create `packages/web/server/lib/quota/providers/<provider>.js`.
@@ -10,7 +10,7 @@ import {
export const providerId = 'claude';
export const providerName = 'Claude';
export const aliases = ['anthropic', 'claude'];
const aliases = ['anthropic', 'claude'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -11,7 +11,7 @@ import {
export const providerId = 'codex';
export const providerName = 'Codex';
export const aliases = ['openai', 'codex', 'chatgpt'];
const aliases = ['openai', 'codex', 'chatgpt'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -40,7 +40,7 @@ const buildCopilotWindows = (payload) => {
export const providerId = 'github-copilot';
export const providerName = 'GitHub Copilot';
export const aliases = ['github-copilot', 'copilot'];
const aliases = ['github-copilot', 'copilot'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -21,7 +21,7 @@ const STATE_DB = join(homedir(), 'Library', 'Application Support', 'Cursor', 'Us
export const providerId = 'cursor';
export const providerName = 'Cursor';
export const aliases = ['cursor'];
const aliases = ['cursor'];
const readJwtPayload = (token) => {
try {
@@ -39,7 +39,7 @@ export const resolveGoogleOAuthClient = (sourceId) => {
};
};
export const resolveGeminiCliAuth = (auth) => {
const resolveGeminiCliAuth = (auth) => {
const entry = normalizeAuthEntry(getAuthEntry(auth, ['google', 'google.oauth']));
const entryObject = asObject(entry);
if (!entryObject) {
@@ -64,7 +64,7 @@ export const resolveGeminiCliAuth = (auth) => {
};
};
export const resolveAntigravityAuth = () => {
const resolveAntigravityAuth = () => {
for (const filePath of ANTIGRAVITY_ACCOUNTS_PATHS) {
const data = readJsonFile(filePath);
const accounts = data?.accounts;
@@ -1,30 +1,3 @@
/**
* Google Provider
*
* Google quota provider implementation.
* @module quota/providers/google
*/
export {
resolveGoogleOAuthClient,
resolveGeminiCliAuth,
resolveAntigravityAuth,
resolveGoogleAuthSources,
DEFAULT_PROJECT_ID
} from './auth.js';
export {
resolveGoogleWindow,
transformQuotaBucket,
transformModelData
} from './transforms.js';
export {
refreshGoogleAccessToken,
fetchGoogleQuotaBuckets,
fetchGoogleModels
} from './api.js';
import { buildResult } from '../../utils/index.js';
import {
resolveGoogleAuthSources,
@@ -29,7 +29,7 @@ export const parseGoogleRefreshToken = (rawRefreshToken) => {
};
};
export const resolveGoogleWindow = (sourceId, resetAt) => {
const resolveGoogleWindow = (sourceId, resetAt) => {
if (sourceId === 'gemini') {
return { label: 'daily', seconds: GOOGLE_DAILY_WINDOW_SECONDS };
}
@@ -168,7 +168,7 @@ export const fetchCopilotAddonQuota = copilot.fetchQuotaAddon;
export const fetchKimiQuota = kimi.fetchQuota;
export const fetchOpenRouterQuota = openrouter.fetchQuota;
export const fetchZaiQuota = zai.fetchQuota;
export const fetchZhipuaiCodingPlanQuota = zhipuaiCodingPlan.fetchQuota;
const fetchZhipuaiCodingPlanQuota = zhipuaiCodingPlan.fetchQuota;
export const fetchNanoGptQuota = nanogpt.fetchQuota;
export const fetchMinimaxCodingPlanQuota = minimaxCodingPlan.fetchQuota;
export const fetchMinimaxCnCodingPlanQuota = minimaxCnCodingPlan.fetchQuota;
@@ -1,55 +0,0 @@
/**
* Quota Provider Interface
*
* Defines the contract for implementing quota providers.
* @module quota/providers
*/
/**
* @typedef {Object} UsageWindow
* @property {number|null} usedPercent - Percentage of usage (0-100)
* @property {number|null} remainingPercent - Percentage remaining (0-100)
* @property {number|null} windowSeconds - Window duration in seconds
* @property {number|null} resetAfterSeconds - Seconds until reset
* @property {number|null} resetAt - Unix timestamp when quota resets
* @property {string|null} resetAtFormatted - Human-readable reset time
* @property {string|null} resetAfterFormatted - Human-readable time until reset
* @property {string|null} valueLabel - Optional label for display (e.g., "$10.00 remaining")
*/
/**
* @typedef {Object} ProviderUsage
* @property {Object.<string, UsageWindow>} windows - Usage windows by key (e.g., '5h', '7d', 'daily')
* @property {Object.<string, Object>} [models] - Model-specific usage (provider-specific)
*/
/**
* @typedef {Object} QuotaProviderResult
* @property {string} providerId - Unique identifier for the provider
* @property {string} providerName - Display name for the provider
* @property {boolean} ok - Whether the fetch was successful
* @property {boolean} configured - Whether the provider is configured
* @property {ProviderUsage|null} usage - Usage data if successful
* @property {string|null} [error] - Error message if not successful
* @property {number} fetchedAt - Unix timestamp when the result was fetched
*/
/**
* @typedef {Function} ProviderQuotaFetcher
* @returns {Promise<QuotaProviderResult>}
*/
/**
* @typedef {Function} ProviderConfigurationChecker
* @param {Object.<string, unknown>} [auth]
* @returns {boolean}
*/
/**
* @typedef {Object} QuotaProvider
* @property {string} providerId
* @property {string} providerName
* @property {string[]} aliases
* @property {ProviderConfigurationChecker} isConfigured
* @property {ProviderQuotaFetcher} fetchQuota
*/
@@ -12,7 +12,7 @@ import {
export const providerId = 'kimi-for-coding';
export const providerName = 'Kimi for Coding';
export const aliases = ['kimi-for-coding', 'kimi'];
const aliases = ['kimi-for-coding', 'kimi'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -10,6 +10,6 @@ const provider = createMiniMaxCodingPlanProvider({
export const providerId = provider.providerId;
export const providerName = provider.providerName;
export const aliases = provider.aliases;
const aliases = provider.aliases;
export const isConfigured = provider.isConfigured;
export const fetchQuota = provider.fetchQuota;
@@ -10,6 +10,6 @@ const provider = createMiniMaxCodingPlanProvider({
export const providerId = provider.providerId;
export const providerName = provider.providerName;
export const aliases = provider.aliases;
const aliases = provider.aliases;
export const isConfigured = provider.isConfigured;
export const fetchQuota = provider.fetchQuota;
@@ -12,7 +12,7 @@ const NANO_GPT_DAILY_WINDOW_SECONDS = 86400;
export const providerId = 'nano-gpt';
export const providerName = 'NanoGPT';
export const aliases = ['nano-gpt', 'nanogpt', 'nano_gpt'];
const aliases = ['nano-gpt', 'nanogpt', 'nano_gpt'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -7,7 +7,7 @@ const COOKIE_PATH = join(homedir(), '.config', 'ollama-quota', 'cookie');
export const providerId = 'ollama-cloud';
export const providerName = 'Ollama Cloud';
export const aliases = ['ollama-cloud', 'ollamacloud'];
const aliases = ['ollama-cloud', 'ollamacloud'];
const readCookieFile = () => {
try {
@@ -8,11 +8,11 @@ import {
toTimestamp
} from '../utils/index.js';
export const providerId = 'openai';
export const providerName = 'OpenAI';
export const aliases = ['openai', 'codex', 'chatgpt'];
const providerId = 'openai';
const providerName = 'OpenAI';
const aliases = ['openai', 'codex', 'chatgpt'];
export const isConfigured = () => {
const isConfigured = () => {
const auth = readAuthFile();
const entry = normalizeAuthEntry(getAuthEntry(auth, aliases));
return Boolean(entry?.access || entry?.token);
@@ -10,7 +10,7 @@ import {
export const providerId = 'openrouter';
export const providerName = 'OpenRouter';
export const aliases = ['openrouter'];
const aliases = ['openrouter'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -12,7 +12,7 @@ import {
export const providerId = 'wafer';
export const providerName = 'Wafer.ai';
export const aliases = ['wafer', 'wafer-ai', 'wafer_ai', 'wafer.ai'];
const aliases = ['wafer', 'wafer-ai', 'wafer_ai', 'wafer.ai'];
const WAFER_QUOTA_URL = 'https://pass.wafer.ai/v1/inference/quota';
const WAFER_WINDOW_SECONDS = 5 * 3600;
@@ -13,7 +13,7 @@ import {
export const providerId = 'zai-coding-plan';
export const providerName = 'z.ai';
export const aliases = ['zai-coding-plan', 'zai', 'z.ai'];
const aliases = ['zai-coding-plan', 'zai', 'z.ai'];
export const isConfigured = () => {
const auth = readAuthFile();
@@ -38,7 +38,7 @@ import {
export const providerId = 'zhipuai-coding-plan';
export const providerName = 'Zhipu AI Coding Plan';
export const aliases = ['zhipuai-coding-plan', 'zhipuai', 'zhipu'];
const aliases = ['zhipuai-coding-plan', 'zhipuai', 'zhipu'];
function getApiKey() {
const auth = readAuthFile();
@@ -23,7 +23,3 @@ export function setCachedScan(key, value, ttlMs = DEFAULT_TTL_MS) {
const ttl = Number.isFinite(ttlMs) ? ttlMs : DEFAULT_TTL_MS;
cache.set(key, { expiresAt: Date.now() + ttl, value });
}
export function clearCache() {
cache.clear();
}
@@ -82,38 +82,6 @@ export async function fetchClawdHubSkills({ cursor } = {}) {
};
}
/**
* Fetch details for a specific skill version
* @param {string} slug - Skill slug/identifier
* @param {string} [version='latest'] - Version string or 'latest'
* @returns {Promise<{ skill: Object, version: Object }>}
*/
export async function fetchClawdHubSkillVersion(slug, version = 'latest') {
// For 'latest', we need to first get the skill metadata to find the latest version
if (version === 'latest') {
const skillResponse = await rateLimitedFetch(`${CLAWDHUB_API_BASE}/skills/${encodeURIComponent(slug)}`);
if (!skillResponse.ok) {
throw new Error(`ClawdHub skill not found: ${slug}`);
}
const skillData = await skillResponse.json();
const latestVersion = skillData.skill?.tags?.latest || skillData.latestVersion?.version;
if (!latestVersion) {
throw new Error(`No latest version found for skill: ${slug}`);
}
version = latestVersion;
}
const url = `${CLAWDHUB_API_BASE}/skills/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version)}`;
const response = await rateLimitedFetch(url);
if (!response.ok) {
const text = await response.text().catch(() => '');
throw new Error(`ClawdHub version error (${response.status}): ${text || response.statusText}`);
}
return response.json();
}
/**
* Download a skill package as a ZIP buffer
* @param {string} slug - Skill slug/identifier
@@ -1,30 +0,0 @@
/**
* ClawdHub integration module
*
* Provides skill browsing and installation from the ClawdHub registry.
* https://clawdhub.com
*/
export { scanClawdHub, scanClawdHubPage } from './scan.js';
export { installSkillsFromClawdHub } from './install.js';
export {
fetchClawdHubSkills,
fetchClawdHubSkillVersion,
fetchClawdHubSkillInfo,
downloadClawdHubSkill,
} from './api.js';
/**
* Check if a source string refers to ClawdHub
* @param {string} source
* @returns {boolean}
*/
export function isClawdHubSource(source) {
return typeof source === 'string' && source.startsWith('clawdhub:');
}
/**
* ClawdHub source identifier used in curated sources
*/
export const CLAWDHUB_SOURCE_ID = 'clawdhub';
export const CLAWDHUB_SOURCE_STRING = 'clawdhub:registry';
@@ -7,7 +7,6 @@
import { fetchClawdHubSkills } from './api.js';
const MAX_PAGES = 20; // Safety limit to prevent infinite loops
const CLAWDHUB_PAGE_LIMIT = 25;
const mapClawdHubItem = (item) => {
@@ -39,57 +38,6 @@ const mapClawdHubItem = (item) => {
};
};
/**
* Scan ClawdHub registry for all available skills
* @returns {Promise<{ ok: boolean, items?: Array, error?: Object }>}
*/
export async function scanClawdHub() {
try {
const allItems = [];
let cursor = null;
for (let page = 0; page < MAX_PAGES; page++) {
let items = [];
let nextCursor = null;
try {
const pageResult = await fetchClawdHubSkills({ cursor });
items = pageResult.items || [];
nextCursor = pageResult.nextCursor || null;
} catch (error) {
if (page > 0 && allItems.length > 0) {
console.warn('ClawdHub pagination failed; returning partial results.');
break;
}
throw error;
}
for (const item of items) {
allItems.push(mapClawdHubItem(item));
}
if (!nextCursor) {
break;
}
cursor = nextCursor;
}
// Sort by downloads (most popular first)
allItems.sort((a, b) => (b.clawdhub?.downloads || 0) - (a.clawdhub?.downloads || 0));
return { ok: true, items: allItems };
} catch (error) {
console.error('ClawdHub scan error:', error);
return {
ok: false,
error: {
kind: 'networkError',
message: error instanceof Error ? error.message : 'Failed to fetch skills from ClawdHub',
},
};
}
}
/**
* Scan a single ClawdHub page (cursor-based)
* @returns {Promise<{ ok: boolean, items?: Array, nextCursor?: string | null, error?: Object }>}
@@ -1,4 +1,4 @@
export const CURATED_SKILLS_SOURCES = [
const CURATED_SKILLS_SOURCES = [
{
id: 'anthropic',
label: 'Anthropic',
@@ -1,42 +0,0 @@
/**
* Skills catalog module
*
* Provides skill scanning, installation, and caching from GitHub repositories and ClawdHub.
*/
export {
CURATED_SKILLS_SOURCES,
getCuratedSkillsSources,
} from './curated-sources.js';
export {
getCacheKey,
getCachedScan,
setCachedScan,
clearCache,
} from './cache.js';
export {
parseSkillRepoSource,
} from './source.js';
export {
scanSkillsRepository,
} from './scan.js';
export {
installSkillsFromRepository,
} from './install.js';
export {
scanClawdHub,
scanClawdHubPage,
installSkillsFromClawdHub,
fetchClawdHubSkills,
fetchClawdHubSkillVersion,
fetchClawdHubSkillInfo,
downloadClawdHubSkill,
isClawdHubSource,
CLAWDHUB_SOURCE_ID,
CLAWDHUB_SOURCE_STRING,
} from './clawdhub/index.js';
@@ -1,4 +1,5 @@
const GITHUB_HOST = 'github.com';
const CLAWDHUB_SOURCE_PREFIX = 'clawdhub:';
function normalizeGitOwnerRepo(owner, repo) {
@@ -85,3 +86,7 @@ export function parseSkillRepoSource(input, options = {}) {
return { ok: false, error: { kind: 'invalidSource', message: 'Unsupported repository source format' } };
}
export function isClawdHubSource(input) {
return typeof input === 'string' && input.trim().toLowerCase().startsWith(CLAWDHUB_SOURCE_PREFIX);
}
-31
View File
@@ -1,31 +0,0 @@
export {
TERMINAL_WS_PATH,
TERMINAL_WS_CONTROL_TAG_JSON,
TERMINAL_WS_MAX_PAYLOAD_BYTES,
isTerminalWsPathname,
parseRequestPathname,
normalizeTerminalWsMessageToBuffer,
normalizeTerminalWsMessageToText,
readTerminalWsControlFrame,
createTerminalWsControlFrame,
pruneRebindTimestamps,
isRebindRateLimited,
} from './terminal-ws-protocol.js';
export {
TERMINAL_WS_PATH as TERMINAL_INPUT_WS_PATH,
TERMINAL_WS_CONTROL_TAG_JSON as TERMINAL_INPUT_WS_CONTROL_TAG_JSON,
TERMINAL_WS_MAX_PAYLOAD_BYTES as TERMINAL_INPUT_WS_MAX_PAYLOAD_BYTES,
normalizeTerminalWsMessageToBuffer as normalizeTerminalInputWsMessageToBuffer,
normalizeTerminalWsMessageToText as normalizeTerminalInputWsMessageToText,
readTerminalWsControlFrame as readTerminalInputWsControlFrame,
createTerminalWsControlFrame as createTerminalInputWsControlFrame,
} from './terminal-ws-protocol.js';
export {
TERMINAL_OUTPUT_REPLAY_MAX_BYTES,
createTerminalOutputReplayBuffer,
appendTerminalOutputReplayChunk,
listTerminalOutputReplayChunksSince,
getLatestTerminalOutputReplayChunkId,
} from './output-replay-buffer.js';
+11 -9
View File
@@ -1,18 +1,20 @@
import { WebSocketServer } from 'ws';
import {
TERMINAL_INPUT_WS_MAX_PAYLOAD_BYTES,
TERMINAL_INPUT_WS_PATH,
TERMINAL_WS_MAX_PAYLOAD_BYTES as TERMINAL_INPUT_WS_MAX_PAYLOAD_BYTES,
TERMINAL_WS_PATH as TERMINAL_INPUT_WS_PATH,
createTerminalWsControlFrame as createTerminalInputWsControlFrame,
isRebindRateLimited,
normalizeTerminalWsMessageToText as normalizeTerminalInputWsMessageToText,
parseRequestPathname,
pruneRebindTimestamps,
readTerminalWsControlFrame as readTerminalInputWsControlFrame,
} from './terminal-ws-protocol.js';
import {
TERMINAL_OUTPUT_REPLAY_MAX_BYTES,
appendTerminalOutputReplayChunk,
createTerminalOutputReplayBuffer,
createTerminalInputWsControlFrame,
isRebindRateLimited,
listTerminalOutputReplayChunksSince,
normalizeTerminalInputWsMessageToText,
parseRequestPathname,
pruneRebindTimestamps,
readTerminalInputWsControlFrame,
} from './index.js';
} from './output-replay-buffer.js';
export function createTerminalRuntime({
app,
@@ -25,7 +25,7 @@ export function sanitizeForTTS(text) {
.trim();
}
export function sanitizeForNotification(text) {
function sanitizeForNotification(text) {
if (!text || typeof text !== 'string') return '';
return text
@@ -13,7 +13,7 @@ import {
} from '../types.js';
import { getTunnelDependencyInstallInfo } from '../install-help.js';
export const ngrokTunnelProviderCapabilities = {
const ngrokTunnelProviderCapabilities = {
provider: TUNNEL_PROVIDER_NGROK,
defaults: {
mode: TUNNEL_MODE_QUICK,
+2 -2
View File
@@ -10,7 +10,7 @@ export const TUNNEL_MODE_MANAGED_LOCAL = 'managed-local';
export const TUNNEL_INTENT_EPHEMERAL_PUBLIC = 'ephemeral-public';
export const TUNNEL_INTENT_PERSISTENT_PUBLIC = 'persistent-public';
export const TUNNEL_INTENT_PRIVATE_NETWORK = 'private-network';
const TUNNEL_INTENT_PRIVATE_NETWORK = 'private-network';
const SUPPORTED_TUNNEL_INTENTS = new Set([
TUNNEL_INTENT_EPHEMERAL_PUBLIC,
@@ -108,7 +108,7 @@ export function normalizeTunnelMode(value) {
return TUNNEL_MODE_QUICK;
}
export function normalizeTunnelIntent(value) {
function normalizeTunnelIntent(value) {
if (typeof value !== 'string') {
return undefined;
}