feat: pre-install feishu skills to ~/.openclaw/skills on first launch (#252)

This commit is contained in:
paisley
2026-03-02 13:20:07 +08:00
committed by GitHub
Unverified
parent 91cb69d01c
commit 0bc4b7cbc2
2 changed files with 58 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ import { ClawHubService } from '../gateway/clawhub';
import { ensureClawXContext, repairClawXOnlyBootstrapFiles } from '../utils/openclaw-workspace';
import { autoInstallCliIfNeeded, generateCompletionCache, installCompletionToProfile } from '../utils/openclaw-cli';
import { isQuitting, setQuitting } from './app-state';
import { ensureBuiltinSkillsInstalled } from '../utils/skill-config';
// Disable GPU hardware acceleration globally for maximum stability across
// all GPU configurations (no GPU, integrated, discrete).
@@ -187,6 +188,12 @@ async function initialize(): Promise<void> {
logger.warn('Failed to repair bootstrap files:', error);
});
// Pre-deploy built-in skills (feishu-doc, feishu-drive, feishu-perm, feishu-wiki)
// to ~/.openclaw/skills/ so they are immediately available without manual install.
void ensureBuiltinSkillsInstalled().catch((error) => {
logger.warn('Failed to install built-in skills:', error);
});
// Start Gateway automatically (this seeds missing bootstrap files with full templates)
try {
logger.debug('Auto-starting Gateway...');

View File

@@ -5,10 +5,13 @@
*
* All file I/O uses async fs/promises to avoid blocking the main thread.
*/
import { readFile, writeFile, access } from 'fs/promises';
import { readFile, writeFile, access, cp, mkdir } from 'fs/promises';
import { existsSync } from 'fs';
import { constants } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { getOpenClawDir } from './paths';
import { logger } from './logger';
const OPENCLAW_CONFIG_PATH = join(homedir(), '.openclaw', 'openclaw.json');
@@ -132,3 +135,50 @@ export async function getAllSkillConfigs(): Promise<Record<string, SkillEntry>>
const config = await readConfig();
return config.skills?.entries || {};
}
/**
* Built-in skills bundled with ClawX that should be pre-deployed to
* ~/.openclaw/skills/ on first launch. These come from the openclaw package's
* extensions directory and are available in both dev and packaged builds.
*/
const BUILTIN_SKILLS = [
{ slug: 'feishu-doc', sourceExtension: 'feishu' },
{ slug: 'feishu-drive', sourceExtension: 'feishu' },
{ slug: 'feishu-perm', sourceExtension: 'feishu' },
{ slug: 'feishu-wiki', sourceExtension: 'feishu' },
] as const;
/**
* Ensure built-in skills are deployed to ~/.openclaw/skills/<slug>/.
* Skips any skill that already has a SKILL.md present (idempotent).
* Runs at app startup; all errors are logged and swallowed so they never
* block the normal startup flow.
*/
export async function ensureBuiltinSkillsInstalled(): Promise<void> {
const skillsRoot = join(homedir(), '.openclaw', 'skills');
for (const { slug, sourceExtension } of BUILTIN_SKILLS) {
const targetDir = join(skillsRoot, slug);
const targetManifest = join(targetDir, 'SKILL.md');
if (existsSync(targetManifest)) {
continue; // already installed
}
const openclawDir = getOpenClawDir();
const sourceDir = join(openclawDir, 'extensions', sourceExtension, 'skills', slug);
if (!existsSync(join(sourceDir, 'SKILL.md'))) {
logger.warn(`Built-in skill source not found, skipping: ${sourceDir}`);
continue;
}
try {
await mkdir(targetDir, { recursive: true });
await cp(sourceDir, targetDir, { recursive: true });
logger.info(`Installed built-in skill: ${slug} -> ${targetDir}`);
} catch (error) {
logger.warn(`Failed to install built-in skill ${slug}:`, error);
}
}
}