- Updated MarketplaceDrawer to include security notes and manual installation hints. - Refactored SkillDetailDrawer to display default icons for skills. - Simplified SkillListItem to use default icons for better readability. - Integrated gateway status checks and warnings in SkillsPage for improved user awareness. - Enhanced error handling for skill installation and fetching, providing clearer feedback to users. - Added new translations for error messages and gateway warnings to improve localization support.
113 lines
3.3 KiB
JavaScript
113 lines
3.3 KiB
JavaScript
/**
|
|
* Self-Improvement Hook for OpenClaw
|
|
*
|
|
* Injects a reminder to evaluate learnings during agent bootstrap.
|
|
* Fires on agent:bootstrap event before workspace files are injected.
|
|
*/
|
|
|
|
const REMINDER_NAME = 'SELF_IMPROVEMENT_REMINDER.md';
|
|
const REMINDER_PATH = REMINDER_NAME;
|
|
|
|
const REMINDER_CONTENT = `
|
|
## Self-Improvement Reminder
|
|
|
|
After completing tasks, evaluate whether any learnings should be captured.
|
|
|
|
Only log if this repo or workspace is using the self-improvement skill.
|
|
|
|
Before logging:
|
|
- Create only missing \`.learnings/\` files; never overwrite existing content
|
|
- Do not log secrets, tokens, private keys, environment variables, or raw transcripts
|
|
- Prefer short summaries or redacted excerpts over full command output
|
|
|
|
**Log when:**
|
|
- User corrects you → \`.learnings/LEARNINGS.md\`
|
|
- Command/operation fails → \`.learnings/ERRORS.md\`
|
|
- User wants missing capability → \`.learnings/FEATURE_REQUESTS.md\`
|
|
- You discover your knowledge was wrong → \`.learnings/LEARNINGS.md\`
|
|
- You find a better approach → \`.learnings/LEARNINGS.md\`
|
|
|
|
**Promote when pattern is proven:**
|
|
- Behavioral patterns → \`SOUL.md\`
|
|
- Workflow improvements → \`AGENTS.md\`
|
|
- Tool gotchas → \`TOOLS.md\`
|
|
|
|
Keep entries simple: date, title, what happened, and what to do differently.
|
|
`.trim();
|
|
|
|
function isObject(value) {
|
|
return !!value && typeof value === 'object';
|
|
}
|
|
|
|
function isInjectedReminderFile(value) {
|
|
if (!isObject(value) || value.path !== REMINDER_PATH) {
|
|
return false;
|
|
}
|
|
|
|
return (
|
|
value.virtual === true ||
|
|
value.content === REMINDER_CONTENT
|
|
);
|
|
}
|
|
|
|
const handler = async (event) => {
|
|
// Safety checks for event structure
|
|
if (!event || typeof event !== 'object') {
|
|
return;
|
|
}
|
|
|
|
// Only handle agent:bootstrap events
|
|
if (event.type !== 'agent' || event.action !== 'bootstrap') {
|
|
return;
|
|
}
|
|
|
|
// Safety check for context
|
|
if (!event.context || typeof event.context !== 'object') {
|
|
return;
|
|
}
|
|
|
|
// Skip sub-agent sessions to avoid bootstrap issues
|
|
// Sub-agents have sessionKey patterns like "agent:main:subagent:..."
|
|
const sessionKey = event.sessionKey || '';
|
|
if (sessionKey.includes(':subagent:')) {
|
|
return;
|
|
}
|
|
|
|
// Inject the reminder as a virtual bootstrap file
|
|
// Check that bootstrapFiles is an array before pushing
|
|
if (Array.isArray(event.context.bootstrapFiles)) {
|
|
const occupiedByOtherFile = event.context.bootstrapFiles.some(
|
|
(file) => isObject(file) && file.path === REMINDER_PATH && !isInjectedReminderFile(file),
|
|
);
|
|
if (occupiedByOtherFile) {
|
|
return;
|
|
}
|
|
|
|
const cleanedBootstrapFiles = event.context.bootstrapFiles.filter(
|
|
(file, index, files) =>
|
|
!isInjectedReminderFile(file) ||
|
|
files.findIndex((candidate) => isInjectedReminderFile(candidate)) === index,
|
|
);
|
|
|
|
const reminderFile = {
|
|
name: REMINDER_NAME,
|
|
path: REMINDER_PATH,
|
|
content: REMINDER_CONTENT,
|
|
missing: false,
|
|
virtual: true,
|
|
};
|
|
|
|
const existingIndex = cleanedBootstrapFiles.findIndex((file) => isInjectedReminderFile(file));
|
|
if (existingIndex === -1) {
|
|
cleanedBootstrapFiles.push(reminderFile);
|
|
} else {
|
|
cleanedBootstrapFiles[existingIndex] = reminderFile;
|
|
}
|
|
|
|
event.context.bootstrapFiles = cleanedBootstrapFiles;
|
|
}
|
|
};
|
|
|
|
module.exports = handler;
|
|
module.exports.default = handler;
|