fix(md): clawx md injection error (#193)
This commit is contained in:
@@ -197,12 +197,22 @@ async function initialize(): Promise<void> {
|
|||||||
mainWindow?.webContents.send('gateway:error', String(error));
|
mainWindow?.webContents.send('gateway:error', String(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge ClawX context snippets into the (now fully-seeded) bootstrap files
|
// Merge ClawX context snippets into the workspace bootstrap files.
|
||||||
try {
|
// The gateway seeds workspace files asynchronously after its HTTP server
|
||||||
ensureClawXContext();
|
// is ready, so ensureClawXContext will retry until the target files appear.
|
||||||
} catch (error) {
|
void ensureClawXContext().catch((error) => {
|
||||||
logger.warn('Failed to merge ClawX context into workspace:', error);
|
logger.warn('Failed to merge ClawX context into workspace:', error);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
// Re-apply ClawX context after every gateway restart because the gateway
|
||||||
|
// may re-seed workspace files with clean templates (losing ClawX markers).
|
||||||
|
gatewayManager.on('status', (status: { state: string }) => {
|
||||||
|
if (status.state === 'running') {
|
||||||
|
void ensureClawXContext().catch((error) => {
|
||||||
|
logger.warn('Failed to re-merge ClawX context after gateway reconnect:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Application lifecycle
|
// Application lifecycle
|
||||||
|
|||||||
@@ -116,29 +116,26 @@ function resolveAllWorkspaceDirs(): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure ClawX context snippets are merged into the openclaw workspace
|
* Synchronously merge ClawX context snippets into workspace bootstrap
|
||||||
* bootstrap files. Reads `*.clawx.md` templates from resources/context/
|
* files that already exist on disk. Returns the number of target files
|
||||||
* and injects them as marker-delimited sections into the corresponding
|
* that were skipped because they don't exist yet.
|
||||||
* workspace `.md` files (e.g. AGENTS.clawx.md -> AGENTS.md).
|
|
||||||
*
|
|
||||||
* Iterates over every discovered agent workspace so all agents receive
|
|
||||||
* the ClawX context regardless of which one is active.
|
|
||||||
*/
|
*/
|
||||||
export function ensureClawXContext(): void {
|
function mergeClawXContextOnce(): number {
|
||||||
const contextDir = join(getResourcesDir(), 'context');
|
const contextDir = join(getResourcesDir(), 'context');
|
||||||
if (!existsSync(contextDir)) {
|
if (!existsSync(contextDir)) {
|
||||||
logger.debug('ClawX context directory not found, skipping context merge');
|
logger.debug('ClawX context directory not found, skipping context merge');
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let files: string[];
|
let files: string[];
|
||||||
try {
|
try {
|
||||||
files = readdirSync(contextDir).filter((f) => f.endsWith('.clawx.md'));
|
files = readdirSync(contextDir).filter((f) => f.endsWith('.clawx.md'));
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspaceDirs = resolveAllWorkspaceDirs();
|
const workspaceDirs = resolveAllWorkspaceDirs();
|
||||||
|
let skipped = 0;
|
||||||
|
|
||||||
for (const workspaceDir of workspaceDirs) {
|
for (const workspaceDir of workspaceDirs) {
|
||||||
if (!existsSync(workspaceDir)) {
|
if (!existsSync(workspaceDir)) {
|
||||||
@@ -151,6 +148,7 @@ export function ensureClawXContext(): void {
|
|||||||
|
|
||||||
if (!existsSync(targetPath)) {
|
if (!existsSync(targetPath)) {
|
||||||
logger.debug(`Skipping ${targetName} in ${workspaceDir} (file does not exist yet, will be seeded by gateway)`);
|
logger.debug(`Skipping ${targetName} in ${workspaceDir} (file does not exist yet, will be seeded by gateway)`);
|
||||||
|
skipped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,4 +162,37 @@ export function ensureClawXContext(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return skipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RETRY_INTERVAL_MS = 2000;
|
||||||
|
const MAX_RETRIES = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure ClawX context snippets are merged into the openclaw workspace
|
||||||
|
* bootstrap files. Reads `*.clawx.md` templates from resources/context/
|
||||||
|
* and injects them as marker-delimited sections into the corresponding
|
||||||
|
* workspace `.md` files (e.g. AGENTS.clawx.md -> AGENTS.md).
|
||||||
|
*
|
||||||
|
* The gateway seeds workspace files asynchronously after its HTTP server
|
||||||
|
* starts, so the target files may not exist yet when this is first called.
|
||||||
|
* When files are missing, retries with a delay until all targets are merged
|
||||||
|
* or the retry budget is exhausted.
|
||||||
|
*/
|
||||||
|
export async function ensureClawXContext(): Promise<void> {
|
||||||
|
let skipped = mergeClawXContextOnce();
|
||||||
|
if (skipped === 0) return;
|
||||||
|
|
||||||
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
||||||
|
await new Promise((r) => setTimeout(r, RETRY_INTERVAL_MS));
|
||||||
|
skipped = mergeClawXContextOnce();
|
||||||
|
if (skipped === 0) {
|
||||||
|
logger.info(`ClawX context merge completed after ${attempt} retry(ies)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(`ClawX context merge: ${skipped} file(s) still missing (retry ${attempt}/${MAX_RETRIES})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn(`ClawX context merge: ${skipped} file(s) still missing after ${MAX_RETRIES} retries`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
## ClawX Environment
|
## ClawX Environment
|
||||||
|
|
||||||
You are ClawX, a desktop AI assistant application based on OpenClaw.
|
You are ClawX, a desktop AI assistant application based on OpenClaw. See TOOLS.md for ClawX-specific tool notes (uv, browser automation, etc.).
|
||||||
|
|
||||||
- **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`.
|
|
||||||
- **Browser**: Full browser automation is available via the `browser` tool. The default "openclaw" profile uses an isolated browser instance. Use it for web scraping, form filling, testing, and any browser automation task. For simply opening a URL for the user to view, use `shell:openExternal` instead.
|
|
||||||
- **Shell**: You have full shell access on the user's machine. Prefer using tools directly over asking the user to run commands manually.
|
|
||||||
- Always confirm before running destructive operations.
|
|
||||||
|
|||||||
@@ -2,16 +2,12 @@
|
|||||||
|
|
||||||
### uv (Python)
|
### uv (Python)
|
||||||
|
|
||||||
- `uv` is the default Python environment manager. It is bundled with ClawX and on PATH.
|
- `uv` is bundled with ClawX and on PATH. Do NOT use bare `python` or `pip`.
|
||||||
- Use `uv run python <script>` to execute Python scripts.
|
- Run scripts: `uv run python <script>` | Install packages: `uv pip install <package>`
|
||||||
- Use `uv pip install <package>` to install packages.
|
|
||||||
- Do NOT use bare `python` or `pip` -- always go through `uv`.
|
|
||||||
|
|
||||||
### Browser
|
### Browser
|
||||||
|
|
||||||
- The `browser` tool provides full browser automation via OpenClaw's browser control server.
|
- `browser` tool provides full automation (scraping, form filling, testing) via an isolated managed browser.
|
||||||
- Default profile is "openclaw" (isolated managed browser using system Chrome/Brave/Edge).
|
- Flow: `action="start"` → `action="snapshot"` (see page + get element refs like `e12`) → `action="act"` (click/type using refs).
|
||||||
- Use `action="start"` to launch the browser, then `action="snapshot"` to see the page, `action="act"` to interact.
|
- Open new tabs: `action="open"` with `targetUrl`.
|
||||||
- Use `action="open"` with `targetUrl` to open new tabs.
|
- To just open a URL for the user to view, use `shell:openExternal` instead.
|
||||||
- Refs from snapshots (e.g. `e12`) are used in `act` actions to click/type on specific elements.
|
|
||||||
- For simple "open a URL for the user to see", use `shell:openExternal` instead.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user