feat(openclaw): add repair function for ClawX-only bootstrap files an… (#180)

This commit is contained in:
Haze
2026-02-26 11:55:19 +08:00
committed by GitHub
Unverified
parent 96ac13fd90
commit 1ca0017f85
3 changed files with 76 additions and 10 deletions

View File

@@ -14,7 +14,7 @@ import { logger } from '../utils/logger';
import { warmupNetworkOptimization } from '../utils/uv-env';
import { ClawHubService } from '../gateway/clawhub';
import { ensureClawXContext } from '../utils/openclaw-workspace';
import { ensureClawXContext, repairClawXOnlyBootstrapFiles } from '../utils/openclaw-workspace';
// Disable GPU acceleration for better compatibility
app.disableHardwareAcceleration();
@@ -178,14 +178,16 @@ async function initialize(): Promise<void> {
mainWindow = null;
});
// Merge ClawX context snippets into the openclaw workspace bootstrap files
// Repair any bootstrap files that only contain ClawX markers (no OpenClaw
// template content). This fixes a race condition where ensureClawXContext()
// previously created the file before the gateway could seed the full template.
try {
ensureClawXContext();
repairClawXOnlyBootstrapFiles();
} catch (error) {
logger.warn('Failed to merge ClawX context into workspace:', error);
logger.warn('Failed to repair bootstrap files:', error);
}
// Start Gateway automatically
// Start Gateway automatically (this seeds missing bootstrap files with full templates)
try {
logger.debug('Auto-starting Gateway...');
await gatewayManager.start();
@@ -194,6 +196,13 @@ async function initialize(): Promise<void> {
logger.error('Gateway auto-start failed:', error);
mainWindow?.webContents.send('gateway:error', String(error));
}
// Merge ClawX context snippets into the (now fully-seeded) bootstrap files
try {
ensureClawXContext();
} catch (error) {
logger.warn('Failed to merge ClawX context into workspace:', error);
}
}
// Application lifecycle

View File

@@ -1,4 +1,4 @@
import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync } from 'fs';
import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync, unlinkSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { logger } from './logger';
@@ -22,6 +22,49 @@ export function mergeClawXSection(existing: string, section: string): string {
return existing.trimEnd() + '\n\n' + wrapped + '\n';
}
/**
* Detect and remove bootstrap .md files that contain only ClawX markers
* with no meaningful OpenClaw content outside them. This repairs a race
* condition where ensureClawXContext() created the file before the gateway
* could seed the full template. Deleting the hollow file lets the gateway
* re-seed the complete template on next start.
*/
export function repairClawXOnlyBootstrapFiles(): void {
const workspaceDirs = resolveAllWorkspaceDirs();
for (const workspaceDir of workspaceDirs) {
if (!existsSync(workspaceDir)) continue;
let entries: string[];
try {
entries = readdirSync(workspaceDir).filter((f) => f.endsWith('.md'));
} catch {
continue;
}
for (const file of entries) {
const filePath = join(workspaceDir, file);
let content: string;
try {
content = readFileSync(filePath, 'utf-8');
} catch {
continue;
}
const beginIdx = content.indexOf(CLAWX_BEGIN);
const endIdx = content.indexOf(CLAWX_END);
if (beginIdx === -1 || endIdx === -1) continue;
const before = content.slice(0, beginIdx).trim();
const after = content.slice(endIdx + CLAWX_END.length).trim();
if (before === '' && after === '') {
try {
unlinkSync(filePath);
logger.info(`Removed ClawX-only bootstrap file for re-seeding: ${file} (${workspaceDir})`);
} catch {
logger.warn(`Failed to remove ClawX-only bootstrap file: ${filePath}`);
}
}
}
}
}
/**
* Collect all unique workspace directories from the openclaw config:
* the defaults workspace, each agent's workspace, and any workspace-*
@@ -105,13 +148,15 @@ export function ensureClawXContext(): void {
for (const file of files) {
const targetName = file.replace('.clawx.md', '.md');
const targetPath = join(workspaceDir, targetName);
const section = readFileSync(join(contextDir, file), 'utf-8');
let existing = '';
if (existsSync(targetPath)) {
existing = readFileSync(targetPath, 'utf-8');
if (!existsSync(targetPath)) {
logger.debug(`Skipping ${targetName} in ${workspaceDir} (file does not exist yet, will be seeded by gateway)`);
continue;
}
const section = readFileSync(join(contextDir, file), 'utf-8');
const existing = readFileSync(targetPath, 'utf-8');
const merged = mergeClawXSection(existing, section);
if (merged !== existing) {
writeFileSync(targetPath, merged, 'utf-8');