Skip to content

Commit 0bab4a5

Browse files
hazeonecursoragent
authored andcommitted
feat(electron): integrate ClawX context into openclaw workspace initialization
Co-authored-by: Haze <hazeone@users.noreply.github.com>
1 parent 5d1d704 commit 0bab4a5

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-0
lines changed

electron/main/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { logger } from '../utils/logger';
1414
import { warmupNetworkOptimization } from '../utils/uv-env';
1515

1616
import { ClawHubService } from '../gateway/clawhub';
17+
import { ensureClawXContext } from '../utils/openclaw-workspace';
1718

1819
// Disable GPU acceleration for better compatibility
1920
app.disableHardwareAcceleration();
@@ -177,6 +178,13 @@ async function initialize(): Promise<void> {
177178
mainWindow = null;
178179
});
179180

181+
// Merge ClawX context snippets into the openclaw workspace bootstrap files
182+
try {
183+
ensureClawXContext();
184+
} catch (error) {
185+
logger.warn('Failed to merge ClawX context into workspace:', error);
186+
}
187+
180188
// Start Gateway automatically
181189
try {
182190
logger.debug('Auto-starting Gateway...');
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync } from 'fs';
2+
import { join } from 'path';
3+
import { homedir } from 'os';
4+
import { logger } from './logger';
5+
import { getResourcesDir } from './paths';
6+
7+
const CLAWX_BEGIN = '<!-- clawx:begin -->';
8+
const CLAWX_END = '<!-- clawx:end -->';
9+
10+
/**
11+
* Merge a ClawX context section into an existing file's content.
12+
* If markers already exist, replaces the section in-place.
13+
* Otherwise appends it at the end.
14+
*/
15+
export function mergeClawXSection(existing: string, section: string): string {
16+
const wrapped = `${CLAWX_BEGIN}\n${section.trim()}\n${CLAWX_END}`;
17+
const beginIdx = existing.indexOf(CLAWX_BEGIN);
18+
const endIdx = existing.indexOf(CLAWX_END);
19+
if (beginIdx !== -1 && endIdx !== -1) {
20+
return existing.slice(0, beginIdx) + wrapped + existing.slice(endIdx + CLAWX_END.length);
21+
}
22+
return existing.trimEnd() + '\n\n' + wrapped + '\n';
23+
}
24+
25+
/**
26+
* Collect all unique workspace directories from the openclaw config:
27+
* the defaults workspace, each agent's workspace, and any workspace-*
28+
* directories that already exist under ~/.openclaw/.
29+
*/
30+
function resolveAllWorkspaceDirs(): string[] {
31+
const openclawDir = join(homedir(), '.openclaw');
32+
const dirs = new Set<string>();
33+
34+
const configPath = join(openclawDir, 'openclaw.json');
35+
try {
36+
if (existsSync(configPath)) {
37+
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
38+
39+
const defaultWs = config?.agents?.defaults?.workspace;
40+
if (typeof defaultWs === 'string' && defaultWs.trim()) {
41+
dirs.add(defaultWs.replace(/^~/, homedir()));
42+
}
43+
44+
const agents = config?.agents?.list;
45+
if (Array.isArray(agents)) {
46+
for (const agent of agents) {
47+
const ws = agent?.workspace;
48+
if (typeof ws === 'string' && ws.trim()) {
49+
dirs.add(ws.replace(/^~/, homedir()));
50+
}
51+
}
52+
}
53+
}
54+
} catch {
55+
// ignore config parse errors
56+
}
57+
58+
try {
59+
for (const entry of readdirSync(openclawDir, { withFileTypes: true })) {
60+
if (entry.isDirectory() && entry.name.startsWith('workspace')) {
61+
dirs.add(join(openclawDir, entry.name));
62+
}
63+
}
64+
} catch {
65+
// ignore read errors
66+
}
67+
68+
if (dirs.size === 0) {
69+
dirs.add(join(openclawDir, 'workspace'));
70+
}
71+
72+
return [...dirs];
73+
}
74+
75+
/**
76+
* Ensure ClawX context snippets are merged into the openclaw workspace
77+
* bootstrap files. Reads `*.clawx.md` templates from resources/context/
78+
* and injects them as marker-delimited sections into the corresponding
79+
* workspace `.md` files (e.g. AGENTS.clawx.md -> AGENTS.md).
80+
*
81+
* Iterates over every discovered agent workspace so all agents receive
82+
* the ClawX context regardless of which one is active.
83+
*/
84+
export function ensureClawXContext(): void {
85+
const contextDir = join(getResourcesDir(), 'context');
86+
if (!existsSync(contextDir)) {
87+
logger.debug('ClawX context directory not found, skipping context merge');
88+
return;
89+
}
90+
91+
let files: string[];
92+
try {
93+
files = readdirSync(contextDir).filter((f) => f.endsWith('.clawx.md'));
94+
} catch {
95+
return;
96+
}
97+
98+
const workspaceDirs = resolveAllWorkspaceDirs();
99+
100+
for (const workspaceDir of workspaceDirs) {
101+
if (!existsSync(workspaceDir)) {
102+
mkdirSync(workspaceDir, { recursive: true });
103+
}
104+
105+
for (const file of files) {
106+
const targetName = file.replace('.clawx.md', '.md');
107+
const targetPath = join(workspaceDir, targetName);
108+
const section = readFileSync(join(contextDir, file), 'utf-8');
109+
110+
let existing = '';
111+
if (existsSync(targetPath)) {
112+
existing = readFileSync(targetPath, 'utf-8');
113+
}
114+
115+
const merged = mergeClawXSection(existing, section);
116+
if (merged !== existing) {
117+
writeFileSync(targetPath, merged, 'utf-8');
118+
logger.info(`Merged ClawX context into ${targetName} (${workspaceDir})`);
119+
}
120+
}
121+
}
122+
}

resources/context/AGENTS.clawx.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## ClawX Environment
2+
3+
You are ClawX, a desktop AI assistant application based on OpenClaw.
4+
5+
- **Python**: Always use `uv` to run Python commands. The `uv` binary is bundled and available on PATH. Examples: `uv run python script.py`, `uv pip install package`.
6+
- **Browser**: When asked to open URLs or web pages, use the browser tool to open them in the user's system default browser.
7+
- **Shell**: You have full shell access on the user's machine. Prefer using tools directly over asking the user to run commands manually.
8+
- Always confirm before running destructive operations.

resources/context/TOOLS.clawx.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## ClawX Tool Notes
2+
3+
### uv (Python)
4+
5+
- `uv` is the default Python environment manager. It is bundled with ClawX and on PATH.
6+
- Use `uv run python <script>` to execute Python scripts.
7+
- Use `uv pip install <package>` to install packages.
8+
- Do NOT use bare `python` or `pip` -- always go through `uv`.
9+
10+
### Browser
11+
12+
- Use the `browser` tool to open URLs in the user's default browser.
13+
- When the user asks to "open" a link, default to opening it in the browser.

0 commit comments

Comments
 (0)