@happycastle/oh-my-openclaw 0.14.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/keyword-detector/analyze-mode.d.ts +12 -0
- package/dist/hooks/keyword-detector/analyze-mode.js +30 -0
- package/dist/hooks/keyword-detector/coding-mode.d.ts +12 -0
- package/dist/hooks/keyword-detector/coding-mode.js +29 -0
- package/dist/hooks/keyword-detector/detector.d.ts +6 -0
- package/dist/hooks/keyword-detector/detector.js +21 -0
- package/dist/hooks/keyword-detector/hook.d.ts +2 -0
- package/dist/hooks/keyword-detector/hook.js +15 -0
- package/dist/hooks/keyword-detector/search-mode.d.ts +12 -0
- package/dist/hooks/keyword-detector/search-mode.js +32 -0
- package/dist/hooks/keyword-detector/ultrawork-mode.d.ts +2 -0
- package/dist/hooks/keyword-detector/ultrawork-mode.js +24 -0
- package/dist/hooks/session-sync.js +5 -4
- package/dist/hooks/spawn-guard.js +2 -2
- package/dist/index.js +6 -0
- package/dist/utils/config.js +6 -3
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.js +14 -0
- package/dist/utils/persona-state.d.ts +5 -4
- package/dist/utils/persona-state.js +32 -22
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: analyze, analyse, investigate, examine, research, study, deep-dive, inspect, audit, evaluate, assess, review, diagnose, scrutinize, dissect, debug, comprehend, interpret, breakdown, understand
|
|
6
|
+
* KO: 분석, 조사, 파악, 연구, 검토, 진단, 이해, 설명, 원인, 이유, 뜯어봐, 따져봐, 평가, 해석, 디버깅, 디버그, 어떻게, 왜, 살펴
|
|
7
|
+
* JA: 分析, 調査, 解析, 検討, 研究, 診断, 理解, 説明, 検証, 精査, 究明, デバッグ, なぜ, どう, 仕組み
|
|
8
|
+
* ZH: 调查, 检查, 剖析, 深入, 诊断, 解释, 调试, 为什么, 原理, 搞清楚, 弄明白
|
|
9
|
+
* VI: phân tích, điều tra, nghiên cứu, kiểm tra, xem xét, chẩn đoán, giải thích, tìm hiểu, gỡ lỗi, tại sao
|
|
10
|
+
*/
|
|
11
|
+
export declare const ANALYZE_PATTERN: RegExp;
|
|
12
|
+
export declare const ANALYZE_MESSAGE = "[analyze-mode]\nANALYSIS MODE. Gather context from ALL channels before diving deep:\n\nCONTEXT GATHERING (parallel):\n- omoc_delegate(agent_id=\"omoc_explore\") \u2014 codebase patterns, implementations\n- omoc_delegate(agent_id=\"omoc_librarian\") \u2014 external docs, API references\n- web-search-prime / context7 \u2014 official docs, known issues, changelogs\n- grep_app.search \u2014 how others solved similar problems in OSS\n- gemini CLI with @google \u2014 Google Search grounding for real-time info\n\nVISUAL/MULTIMODAL ANALYSIS (if needed):\n- gemini CLI (via tmux) with -f flag \u2014 analyze PDFs, screenshots, architecture diagrams\n- omoc_look_at \u2014 quick multimodal analysis of images/screenshots\n\nIF COMPLEX \u2014 delegate to specialists:\n- omoc_delegate(agent_id=\"omoc_oracle\") \u2014 architecture, debugging, complex logic\n- omoc_delegate(category=\"artistry\") \u2014 unconventional approaches\n\nSYNTHESIZE findings before proceeding.";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: analyze, analyse, investigate, examine, research, study, deep-dive, inspect, audit, evaluate, assess, review, diagnose, scrutinize, dissect, debug, comprehend, interpret, breakdown, understand
|
|
6
|
+
* KO: 분석, 조사, 파악, 연구, 검토, 진단, 이해, 설명, 원인, 이유, 뜯어봐, 따져봐, 평가, 해석, 디버깅, 디버그, 어떻게, 왜, 살펴
|
|
7
|
+
* JA: 分析, 調査, 解析, 検討, 研究, 診断, 理解, 説明, 検証, 精査, 究明, デバッグ, なぜ, どう, 仕組み
|
|
8
|
+
* ZH: 调查, 检查, 剖析, 深入, 诊断, 解释, 调试, 为什么, 原理, 搞清楚, 弄明白
|
|
9
|
+
* VI: phân tích, điều tra, nghiên cứu, kiểm tra, xem xét, chẩn đoán, giải thích, tìm hiểu, gỡ lỗi, tại sao
|
|
10
|
+
*/
|
|
11
|
+
export const ANALYZE_PATTERN = /\b(analyze|analyse|investigate|examine|research|study|deep[\s-]?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to|분석|조사|파악|연구|검토|진단|이해|설명|원인|이유|뜯어봐|따져봐|평가|해석|디버깅|디버그|어떻게|왜|살펴|分析|調査|解析|検討|研究|診断|理解|説明|検証|精査|究明|デバッグ|なぜ|どう|仕組み|调查|检查|剖析|深入|诊断|解释|调试|为什么|原理|搞清楚|弄明白|phân tích|điều tra|nghiên cứu|kiểm tra|xem xét|chẩn đoán|giải thích|tìm hiểu|gỡ lỗi|tại sao/i;
|
|
12
|
+
export const ANALYZE_MESSAGE = `[analyze-mode]
|
|
13
|
+
ANALYSIS MODE. Gather context from ALL channels before diving deep:
|
|
14
|
+
|
|
15
|
+
CONTEXT GATHERING (parallel):
|
|
16
|
+
- omoc_delegate(agent_id="omoc_explore") — codebase patterns, implementations
|
|
17
|
+
- omoc_delegate(agent_id="omoc_librarian") — external docs, API references
|
|
18
|
+
- web-search-prime / context7 — official docs, known issues, changelogs
|
|
19
|
+
- grep_app.search — how others solved similar problems in OSS
|
|
20
|
+
- gemini CLI with @google — Google Search grounding for real-time info
|
|
21
|
+
|
|
22
|
+
VISUAL/MULTIMODAL ANALYSIS (if needed):
|
|
23
|
+
- gemini CLI (via tmux) with -f flag — analyze PDFs, screenshots, architecture diagrams
|
|
24
|
+
- omoc_look_at — quick multimodal analysis of images/screenshots
|
|
25
|
+
|
|
26
|
+
IF COMPLEX — delegate to specialists:
|
|
27
|
+
- omoc_delegate(agent_id="omoc_oracle") — architecture, debugging, complex logic
|
|
28
|
+
- omoc_delegate(category="artistry") — unconventional approaches
|
|
29
|
+
|
|
30
|
+
SYNTHESIZE findings before proceeding.`;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: implement, code, build, develop, refactor, fix, patch, write code, program, create, scaffold, migrate, port, convert
|
|
6
|
+
* KO: 구현, 코딩, 개발, 리팩토링, 수정, 패치, 코드 작성, 만들어, 짜줘, 고쳐, 빌드, 변환, 마이그레이션
|
|
7
|
+
* JA: 実装, コーディング, 開発, リファクタリング, 修正, パッチ, コード, 作って, ビルド, 変換
|
|
8
|
+
* ZH: 实现, 编码, 开发, 重构, 修复, 补丁, 写代码, 构建, 转换, 迁移
|
|
9
|
+
* VI: triển khai, lập trình, phát triển, tái cấu trúc, sửa lỗi, viết code, xây dựng, chuyển đổi
|
|
10
|
+
*/
|
|
11
|
+
export declare const CODING_PATTERN: RegExp;
|
|
12
|
+
export declare const CODING_MESSAGE = "[coding-mode]\nCODING TASK DETECTED. Use the right execution channel:\n\nPRIMARY \u2014 tmux OpenCode/OmO session (opencode-controller skill):\n- Delegate implementation to OpenCode running in tmux for full OmO power\n- Use for: heavy coding, multi-file refactors, test writing, build/lint cycles\n\nALTERNATIVE \u2014 omoc_delegate for lighter tasks:\n- omoc_delegate(category=\"quick\", agent_id=\"omoc_sisyphus\") \u2014 simple fixes, single-file changes\n- omoc_delegate(category=\"deep\", agent_id=\"omoc_hephaestus\") \u2014 complex refactoring, architecture changes\n\nCONTEXT GATHERING (parallel, before coding):\n- omoc_delegate(agent_id=\"omoc_explore\") \u2014 understand existing patterns first\n- context7 / grep_app.search \u2014 check library APIs, find OSS examples\n\nVERIFICATION (after coding):\n- Run tests, linter, type-check, build via tmux opencode session\n- gemini CLI with -f flag \u2014 visual verification of UI changes if applicable";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: implement, code, build, develop, refactor, fix, patch, write code, program, create, scaffold, migrate, port, convert
|
|
6
|
+
* KO: 구현, 코딩, 개발, 리팩토링, 수정, 패치, 코드 작성, 만들어, 짜줘, 고쳐, 빌드, 변환, 마이그레이션
|
|
7
|
+
* JA: 実装, コーディング, 開発, リファクタリング, 修正, パッチ, コード, 作って, ビルド, 変換
|
|
8
|
+
* ZH: 实现, 编码, 开发, 重构, 修复, 补丁, 写代码, 构建, 转换, 迁移
|
|
9
|
+
* VI: triển khai, lập trình, phát triển, tái cấu trúc, sửa lỗi, viết code, xây dựng, chuyển đổi
|
|
10
|
+
*/
|
|
11
|
+
export const CODING_PATTERN = /\b(implement|code|build|develop|refactor|fix|patch|program|scaffold|migrate|port|convert)\b|write\s+code|구현|코딩|개발|리팩토링|수정|패치|코드\s*작성|만들어|짜줘|고쳐|빌드|변환|마이그레이션|実装|コーディング|開発|リファクタリング|修正|パッチ|コード|作って|ビルド|変換|实现|编码|开发|重构|修复|补丁|写代码|构建|转换|迁移|triển khai|lập trình|phát triển|tái cấu trúc|sửa lỗi|viết code|xây dựng|chuyển đổi/i;
|
|
12
|
+
export const CODING_MESSAGE = `[coding-mode]
|
|
13
|
+
CODING TASK DETECTED. Use the right execution channel:
|
|
14
|
+
|
|
15
|
+
PRIMARY — tmux OpenCode/OmO session (opencode-controller skill):
|
|
16
|
+
- Delegate implementation to OpenCode running in tmux for full OmO power
|
|
17
|
+
- Use for: heavy coding, multi-file refactors, test writing, build/lint cycles
|
|
18
|
+
|
|
19
|
+
ALTERNATIVE — omoc_delegate for lighter tasks:
|
|
20
|
+
- omoc_delegate(category="quick", agent_id="omoc_sisyphus") — simple fixes, single-file changes
|
|
21
|
+
- omoc_delegate(category="deep", agent_id="omoc_hephaestus") — complex refactoring, architecture changes
|
|
22
|
+
|
|
23
|
+
CONTEXT GATHERING (parallel, before coding):
|
|
24
|
+
- omoc_delegate(agent_id="omoc_explore") — understand existing patterns first
|
|
25
|
+
- context7 / grep_app.search — check library APIs, find OSS examples
|
|
26
|
+
|
|
27
|
+
VERIFICATION (after coding):
|
|
28
|
+
- Run tests, linter, type-check, build via tmux opencode session
|
|
29
|
+
- gemini CLI with -f flag — visual verification of UI changes if applicable`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SEARCH_PATTERN, SEARCH_MESSAGE } from './search-mode.js';
|
|
2
|
+
import { ANALYZE_PATTERN, ANALYZE_MESSAGE } from './analyze-mode.js';
|
|
3
|
+
import { ULTRAWORK_PATTERN, ULTRAWORK_MESSAGE } from './ultrawork-mode.js';
|
|
4
|
+
import { CODING_PATTERN, CODING_MESSAGE } from './coding-mode.js';
|
|
5
|
+
const CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
|
|
6
|
+
const INLINE_CODE_PATTERN = /`[^`]+`/g;
|
|
7
|
+
const KEYWORD_DETECTORS = [
|
|
8
|
+
{ type: 'ultrawork', pattern: ULTRAWORK_PATTERN, message: ULTRAWORK_MESSAGE },
|
|
9
|
+
{ type: 'search', pattern: SEARCH_PATTERN, message: SEARCH_MESSAGE },
|
|
10
|
+
{ type: 'analyze', pattern: ANALYZE_PATTERN, message: ANALYZE_MESSAGE },
|
|
11
|
+
{ type: 'coding', pattern: CODING_PATTERN, message: CODING_MESSAGE },
|
|
12
|
+
];
|
|
13
|
+
function removeCodeBlocks(text) {
|
|
14
|
+
return text.replace(CODE_BLOCK_PATTERN, '').replace(INLINE_CODE_PATTERN, '');
|
|
15
|
+
}
|
|
16
|
+
export function detectKeywords(text) {
|
|
17
|
+
const cleaned = removeCodeBlocks(text);
|
|
18
|
+
return KEYWORD_DETECTORS
|
|
19
|
+
.filter(({ pattern }) => pattern.test(cleaned))
|
|
20
|
+
.map(({ type, message }) => ({ type, message }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LOG_PREFIX } from '../../constants.js';
|
|
2
|
+
import { detectKeywords } from './detector.js';
|
|
3
|
+
export function registerKeywordDetector(api) {
|
|
4
|
+
api.on('before_prompt_build', (event, _ctx) => {
|
|
5
|
+
const prompt = event.prompt;
|
|
6
|
+
if (!prompt || typeof prompt !== 'string')
|
|
7
|
+
return;
|
|
8
|
+
const detected = detectKeywords(prompt);
|
|
9
|
+
if (detected.length === 0)
|
|
10
|
+
return;
|
|
11
|
+
const merged = detected.map((k) => k.message).join('\n\n');
|
|
12
|
+
api.logger.info(`${LOG_PREFIX} Keyword detector: ${detected.map((k) => k.type).join(', ')} detected`);
|
|
13
|
+
return { prependContext: merged };
|
|
14
|
+
}, { priority: 75 });
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: search, find, locate, lookup, explore, discover, scan, grep, query, browse, detect, trace, seek, track, pinpoint, hunt
|
|
6
|
+
* KO: 검색, 찾아, 탐색, 조회, 스캔, 서치, 뒤져, 찾기, 어디, 추적, 탐지, 찾아봐, 찾아내, 보여줘, 목록
|
|
7
|
+
* JA: 検索, 探して, 見つけて, サーチ, 探索, スキャン, どこ, 発見, 捜索, 見つけ出す, 一覧
|
|
8
|
+
* ZH: 搜索, 查找, 寻找, 查询, 检索, 定位, 扫描, 发现, 在哪里, 找出来, 列出
|
|
9
|
+
* VI: tìm kiếm, tra cứu, định vị, quét, phát hiện, truy tìm, tìm ra, ở đâu, liệt kê
|
|
10
|
+
*/
|
|
11
|
+
export declare const SEARCH_PATTERN: RegExp;
|
|
12
|
+
export declare const SEARCH_MESSAGE = "[search-mode]\nMAXIMIZE SEARCH EFFORT. Use ALL available channels IN PARALLEL:\n\nAGENT DELEGATION (omoc_delegate):\n- agent_id=\"omoc_explore\" \u2014 codebase patterns, file structures, cross-module references\n- agent_id=\"omoc_librarian\" \u2014 external docs, OSS examples, API references\n\nWEB SEARCH (mcporter MCP + OpenClaw native):\n- web-search-prime.webSearchPrime \u2014 keyword web search (news, blogs, latest info)\n- exa.web_search_exa \u2014 semantic web search (better for question-format queries)\n- context7 \u2014 library/framework official documentation\n- grep_app.search \u2014 open-source code pattern search on GitHub\n- zread \u2014 direct GitHub repo file exploration\n- web_fetch \u2014 direct URL reading\n\nGEMINI CLI (via tmux gemini session):\n- gemini with @google extension \u2014 Google Search grounding for real-time info\n- gemini with -f flag \u2014 analyze PDFs/images/screenshots if visual context needed\n\nLaunch multiple delegates + web searches simultaneously.\nNEVER stop at first result \u2014 be exhaustive.";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search mode — multilingual keyword regex.
|
|
3
|
+
* Necessary: documents 5-language regex for maintainability.
|
|
4
|
+
*
|
|
5
|
+
* EN: search, find, locate, lookup, explore, discover, scan, grep, query, browse, detect, trace, seek, track, pinpoint, hunt
|
|
6
|
+
* KO: 검색, 찾아, 탐색, 조회, 스캔, 서치, 뒤져, 찾기, 어디, 추적, 탐지, 찾아봐, 찾아내, 보여줘, 목록
|
|
7
|
+
* JA: 検索, 探して, 見つけて, サーチ, 探索, スキャン, どこ, 発見, 捜索, 見つけ出す, 一覧
|
|
8
|
+
* ZH: 搜索, 查找, 寻找, 查询, 检索, 定位, 扫描, 发现, 在哪里, 找出来, 列出
|
|
9
|
+
* VI: tìm kiếm, tra cứu, định vị, quét, phát hiện, truy tìm, tìm ra, ở đâu, liệt kê
|
|
10
|
+
*/
|
|
11
|
+
export const SEARCH_PATTERN = /\b(search|find|locate|lookup|look\s*up|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all|검색|찾아|탐색|조회|스캔|서치|뒤져|찾기|어디|추적|탐지|찾아봐|찾아내|보여줘|목록|検索|探して|見つけて|サーチ|探索|スキャン|どこ|発見|捜索|見つけ出す|一覧|搜索|查找|寻找|查询|检索|定位|扫描|发现|在哪里|找出来|列出|tìm kiếm|tra cứu|định vị|quét|phát hiện|truy tìm|tìm ra|ở đâu|liệt kê/i;
|
|
12
|
+
export const SEARCH_MESSAGE = `[search-mode]
|
|
13
|
+
MAXIMIZE SEARCH EFFORT. Use ALL available channels IN PARALLEL:
|
|
14
|
+
|
|
15
|
+
AGENT DELEGATION (omoc_delegate):
|
|
16
|
+
- agent_id="omoc_explore" — codebase patterns, file structures, cross-module references
|
|
17
|
+
- agent_id="omoc_librarian" — external docs, OSS examples, API references
|
|
18
|
+
|
|
19
|
+
WEB SEARCH (mcporter MCP + OpenClaw native):
|
|
20
|
+
- web-search-prime.webSearchPrime — keyword web search (news, blogs, latest info)
|
|
21
|
+
- exa.web_search_exa — semantic web search (better for question-format queries)
|
|
22
|
+
- context7 — library/framework official documentation
|
|
23
|
+
- grep_app.search — open-source code pattern search on GitHub
|
|
24
|
+
- zread — direct GitHub repo file exploration
|
|
25
|
+
- web_fetch — direct URL reading
|
|
26
|
+
|
|
27
|
+
GEMINI CLI (via tmux gemini session):
|
|
28
|
+
- gemini with @google extension — Google Search grounding for real-time info
|
|
29
|
+
- gemini with -f flag — analyze PDFs/images/screenshots if visual context needed
|
|
30
|
+
|
|
31
|
+
Launch multiple delegates + web searches simultaneously.
|
|
32
|
+
NEVER stop at first result — be exhaustive.`;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const ULTRAWORK_PATTERN: RegExp;
|
|
2
|
+
export declare const ULTRAWORK_MESSAGE = "[ultrawork-mode]\nULTRAWORK MODE ACTIVATED. Maximum precision engaged. ALL channels available.\n\nMANDATORY WORKFLOW:\n1. PLANNING: omoc_delegate(agent_id=\"omoc_prometheus\") \u2014 strategic breakdown\n2. REVIEW: omoc_delegate(agent_id=\"omoc_momus\") \u2014 plan critique before execution\n3. EXECUTION: tmux opencode session for coding, omoc_delegate for non-coding tasks\n4. VERIFICATION: Run diagnostics, tests, build after completion\n\nAGENT DELEGATION (omoc_delegate):\n- Prometheus \u2014 strategic planning\n- Oracle \u2014 architecture decisions, root cause analysis\n- Explore/Librarian \u2014 context gathering (parallel, background=true)\n- Momus \u2014 plan review and gap detection\n- Sisyphus/Hephaestus \u2014 task execution\n\nRESEARCH & ANALYSIS:\n- mcporter MCP (web-search-prime, exa, context7, grep_app, zread) \u2014 web research\n- gemini CLI with @google \u2014 Google Search grounding for real-time info\n- gemini CLI with -f flag \u2014 multimodal analysis (PDFs, images, diagrams)\n- omoc_look_at \u2014 quick visual analysis\n\nDO NOT CUT CORNERS. Every step verified. Every todo completed.";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const ULTRAWORK_PATTERN = /\b(ultrawork|ulw)\b/i;
|
|
2
|
+
export const ULTRAWORK_MESSAGE = `[ultrawork-mode]
|
|
3
|
+
ULTRAWORK MODE ACTIVATED. Maximum precision engaged. ALL channels available.
|
|
4
|
+
|
|
5
|
+
MANDATORY WORKFLOW:
|
|
6
|
+
1. PLANNING: omoc_delegate(agent_id="omoc_prometheus") — strategic breakdown
|
|
7
|
+
2. REVIEW: omoc_delegate(agent_id="omoc_momus") — plan critique before execution
|
|
8
|
+
3. EXECUTION: tmux opencode session for coding, omoc_delegate for non-coding tasks
|
|
9
|
+
4. VERIFICATION: Run diagnostics, tests, build after completion
|
|
10
|
+
|
|
11
|
+
AGENT DELEGATION (omoc_delegate):
|
|
12
|
+
- Prometheus — strategic planning
|
|
13
|
+
- Oracle — architecture decisions, root cause analysis
|
|
14
|
+
- Explore/Librarian — context gathering (parallel, background=true)
|
|
15
|
+
- Momus — plan review and gap detection
|
|
16
|
+
- Sisyphus/Hephaestus — task execution
|
|
17
|
+
|
|
18
|
+
RESEARCH & ANALYSIS:
|
|
19
|
+
- mcporter MCP (web-search-prime, exa, context7, grep_app, zread) — web research
|
|
20
|
+
- gemini CLI with @google — Google Search grounding for real-time info
|
|
21
|
+
- gemini CLI with -f flag — multimodal analysis (PDFs, images, diagrams)
|
|
22
|
+
- omoc_look_at — quick visual analysis
|
|
23
|
+
|
|
24
|
+
DO NOT CUT CORNERS. Every step verified. Every todo completed.`;
|
|
@@ -4,9 +4,10 @@ import { readPersonaPromptSync } from '../agents/persona-prompts.js';
|
|
|
4
4
|
import { readFileSync } from 'fs';
|
|
5
5
|
/** session_start hook: re-sync AGENTS.md from `.omoc-state` (source of truth). */
|
|
6
6
|
export function registerSessionSync(api) {
|
|
7
|
-
api.on('session_start', async (_event,
|
|
7
|
+
api.on('session_start', async (_event, ctx) => {
|
|
8
8
|
try {
|
|
9
|
-
const
|
|
9
|
+
const wsDir = ctx.workspaceDir;
|
|
10
|
+
const activePersona = await getActivePersona(wsDir);
|
|
10
11
|
if (!activePersona)
|
|
11
12
|
return;
|
|
12
13
|
const personaContent = readPersonaPromptSync(activePersona);
|
|
@@ -14,7 +15,7 @@ export function registerSessionSync(api) {
|
|
|
14
15
|
api.logger.warn(`${LOG_PREFIX} Session sync: persona file issue for ${activePersona}`);
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
const agentsPath = resolveAgentsMdPath();
|
|
18
|
+
const agentsPath = resolveAgentsMdPath(wsDir);
|
|
18
19
|
try {
|
|
19
20
|
const current = readFileSync(agentsPath, 'utf-8');
|
|
20
21
|
if (current.includes(personaContent.slice(0, 100)))
|
|
@@ -23,7 +24,7 @@ export function registerSessionSync(api) {
|
|
|
23
24
|
catch {
|
|
24
25
|
// AGENTS.md missing or unreadable — needs sync
|
|
25
26
|
}
|
|
26
|
-
await replaceAgentsMd(personaContent);
|
|
27
|
+
await replaceAgentsMd(personaContent, wsDir);
|
|
27
28
|
api.logger.info(`${LOG_PREFIX} Session sync: AGENTS.md re-synced with .omoc-state (persona=${activePersona})`);
|
|
28
29
|
}
|
|
29
30
|
catch (err) {
|
|
@@ -5,13 +5,13 @@ const SPAWN_TOOL_NAME = 'sessions_spawn';
|
|
|
5
5
|
const AVAILABLE_AGENTS = ALL_AGENT_IDS.map((id) => id.replace('omoc_', '')).join(', ');
|
|
6
6
|
/** before_tool_call hook: block sessions_spawn without agentId when OmOC persona is active. */
|
|
7
7
|
export function registerSpawnGuard(api) {
|
|
8
|
-
api.on('before_tool_call', async (event,
|
|
8
|
+
api.on('before_tool_call', async (event, ctx) => {
|
|
9
9
|
if (event.toolName !== SPAWN_TOOL_NAME) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
let activePersona;
|
|
13
13
|
try {
|
|
14
|
-
activePersona = await getActivePersona();
|
|
14
|
+
activePersona = await getActivePersona(ctx.workspaceDir);
|
|
15
15
|
}
|
|
16
16
|
catch {
|
|
17
17
|
return;
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { registerPersonaCommands } from './commands/persona-commands.js';
|
|
|
17
17
|
import { registerContextInjector } from './hooks/context-injector.js';
|
|
18
18
|
import { registerSessionSync } from './hooks/session-sync.js';
|
|
19
19
|
import { registerSpawnGuard } from './hooks/spawn-guard.js';
|
|
20
|
+
import { registerKeywordDetector } from './hooks/keyword-detector/hook.js';
|
|
20
21
|
import { registerSetupCli } from './cli/setup.js';
|
|
21
22
|
/**
|
|
22
23
|
* Generation counter for multi-registration handling.
|
|
@@ -78,6 +79,11 @@ export default function register(api) {
|
|
|
78
79
|
registry.hooks.push('gateway-startup');
|
|
79
80
|
api.logger.info(`[${PLUGIN_ID}] Gateway startup hook registered`);
|
|
80
81
|
});
|
|
82
|
+
safeRegister(api, 'keyword-detector', 'hook', () => {
|
|
83
|
+
registerKeywordDetector(guarded);
|
|
84
|
+
registry.hooks.push('keyword-detector');
|
|
85
|
+
api.logger.info(`[${PLUGIN_ID}] Keyword detector hook registered (before_prompt_build, priority 75)`);
|
|
86
|
+
});
|
|
81
87
|
safeRegister(api, 'context-injector', 'hook', () => {
|
|
82
88
|
registerContextInjector(guarded);
|
|
83
89
|
registry.hooks.push('context-injector');
|
package/dist/utils/config.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
1
2
|
import { ABSOLUTE_MAX_RALPH_ITERATIONS } from '../types.js';
|
|
3
|
+
import { resolveOpenClawWorkspaceDir } from './paths.js';
|
|
2
4
|
export function getConfig(api) {
|
|
5
|
+
const wsDir = resolveOpenClawWorkspaceDir();
|
|
3
6
|
const defaults = {
|
|
4
7
|
max_ralph_iterations: 10,
|
|
5
8
|
todo_enforcer_enabled: false,
|
|
6
9
|
todo_enforcer_cooldown_ms: 2000,
|
|
7
10
|
todo_enforcer_max_failures: 5,
|
|
8
11
|
comment_checker_enabled: true,
|
|
9
|
-
notepad_dir: '
|
|
10
|
-
plans_dir: '
|
|
11
|
-
checkpoint_dir: '
|
|
12
|
+
notepad_dir: join(wsDir, 'notepads'),
|
|
13
|
+
plans_dir: join(wsDir, 'plans'),
|
|
14
|
+
checkpoint_dir: join(wsDir, 'checkpoints'),
|
|
12
15
|
tmux_socket: '/tmp/openclaw-tmux-sockets/openclaw.sock',
|
|
13
16
|
model_routing: undefined,
|
|
14
17
|
};
|
package/dist/utils/paths.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export declare const PLUGIN_ROOT: string;
|
|
2
2
|
export declare function resolvePluginPath(...segments: string[]): string;
|
|
3
3
|
export declare function resolveWorkspacePath(workspaceDir: string, ...segments: string[]): string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the OpenClaw workspace directory (absolute path).
|
|
6
|
+
* Uses explicit workspaceDir when provided (e.g. from hook context),
|
|
7
|
+
* otherwise falls back to ~/.openclaw/workspace with OPENCLAW_PROFILE support.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveOpenClawWorkspaceDir(workspaceDir?: string): string;
|
package/dist/utils/paths.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fileURLToPath } from 'url';
|
|
2
2
|
import { dirname, join, resolve } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
3
4
|
const __filename = fileURLToPath(import.meta.url);
|
|
4
5
|
const __dirname = dirname(__filename);
|
|
5
6
|
// Resolves to plugin root (from dist/utils/ → go up ../../)
|
|
@@ -11,3 +12,16 @@ export function resolvePluginPath(...segments) {
|
|
|
11
12
|
export function resolveWorkspacePath(workspaceDir, ...segments) {
|
|
12
13
|
return join(workspaceDir, ...segments);
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the OpenClaw workspace directory (absolute path).
|
|
17
|
+
* Uses explicit workspaceDir when provided (e.g. from hook context),
|
|
18
|
+
* otherwise falls back to ~/.openclaw/workspace with OPENCLAW_PROFILE support.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveOpenClawWorkspaceDir(workspaceDir) {
|
|
21
|
+
if (workspaceDir)
|
|
22
|
+
return workspaceDir;
|
|
23
|
+
const profile = process.env.OPENCLAW_PROFILE?.trim();
|
|
24
|
+
return (profile && profile.toLowerCase() !== 'default')
|
|
25
|
+
? join(homedir(), '.openclaw', `workspace-${profile}`)
|
|
26
|
+
: join(homedir(), '.openclaw', 'workspace');
|
|
27
|
+
}
|
|
@@ -2,8 +2,9 @@ import type { OmocPluginApi } from '../types.js';
|
|
|
2
2
|
export declare function initPersonaState(_api: OmocPluginApi): Promise<void>;
|
|
3
3
|
export declare function setActivePersonaId(id: string | null): Promise<void>;
|
|
4
4
|
export declare function setActivePersona(id: string | null): Promise<void>;
|
|
5
|
-
export declare function getActivePersona(): Promise<string | null>;
|
|
5
|
+
export declare function getActivePersona(workspaceDir?: string): Promise<string | null>;
|
|
6
6
|
export declare function resetPersonaState(): Promise<void>;
|
|
7
|
-
export declare
|
|
8
|
-
export declare function
|
|
9
|
-
export declare function
|
|
7
|
+
export declare const OFF_MARKER = "__OFF__";
|
|
8
|
+
export declare function resolveAgentsMdPath(workspaceDir?: string): string;
|
|
9
|
+
export declare function replaceAgentsMd(personaContent: string, workspaceDir?: string): Promise<void>;
|
|
10
|
+
export declare function restoreAgentsMdToDefault(workspaceDir?: string): Promise<void>;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { resolveOpenClawWorkspaceDir } from './paths.js';
|
|
4
4
|
let activePersonaId = null;
|
|
5
5
|
let loaded = false;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
function resolveStateDir(workspaceDir) {
|
|
7
|
+
return join(resolveOpenClawWorkspaceDir(workspaceDir), '.omoc-state');
|
|
8
|
+
}
|
|
9
|
+
function resolveStateFilePath(workspaceDir) {
|
|
10
|
+
return join(resolveStateDir(workspaceDir), 'active-persona');
|
|
11
|
+
}
|
|
8
12
|
export async function initPersonaState(_api) {
|
|
9
13
|
try {
|
|
10
|
-
await mkdir(
|
|
14
|
+
await mkdir(resolveStateDir(), { recursive: true });
|
|
11
15
|
}
|
|
12
16
|
catch (error) {
|
|
13
17
|
console.warn('[omoc] Failed to initialize persona state directory:', error);
|
|
@@ -22,20 +26,20 @@ export async function setActivePersonaId(id) {
|
|
|
22
26
|
export async function setActivePersona(id) {
|
|
23
27
|
await setActivePersonaId(id);
|
|
24
28
|
}
|
|
25
|
-
export async function getActivePersona() {
|
|
29
|
+
export async function getActivePersona(workspaceDir) {
|
|
26
30
|
if (!loaded)
|
|
27
|
-
await loadFromDisk();
|
|
31
|
+
await loadFromDisk(workspaceDir);
|
|
28
32
|
return activePersonaId;
|
|
29
33
|
}
|
|
30
34
|
export async function resetPersonaState() {
|
|
31
35
|
activePersonaId = null;
|
|
32
36
|
loaded = true;
|
|
33
|
-
await
|
|
37
|
+
await saveOffState();
|
|
34
38
|
}
|
|
35
|
-
async function loadFromDisk() {
|
|
39
|
+
async function loadFromDisk(workspaceDir) {
|
|
36
40
|
try {
|
|
37
|
-
const content = (await readFile(
|
|
38
|
-
activePersonaId = content
|
|
41
|
+
const content = (await readFile(resolveStateFilePath(workspaceDir), 'utf-8')).trim();
|
|
42
|
+
activePersonaId = (content && content !== OFF_MARKER) ? content : null;
|
|
39
43
|
}
|
|
40
44
|
catch (error) {
|
|
41
45
|
// ENOENT is expected on first boot — no state file yet
|
|
@@ -46,30 +50,36 @@ async function loadFromDisk() {
|
|
|
46
50
|
}
|
|
47
51
|
loaded = true;
|
|
48
52
|
}
|
|
53
|
+
export const OFF_MARKER = '__OFF__';
|
|
49
54
|
async function saveToDisk() {
|
|
50
55
|
try {
|
|
51
|
-
await mkdir(
|
|
52
|
-
await writeFile(
|
|
56
|
+
await mkdir(resolveStateDir(), { recursive: true });
|
|
57
|
+
await writeFile(resolveStateFilePath(), activePersonaId ?? '', 'utf-8');
|
|
53
58
|
}
|
|
54
59
|
catch (error) {
|
|
55
60
|
console.warn('[omoc] Failed to persist persona state to disk:', error);
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
async function saveOffState() {
|
|
64
|
+
try {
|
|
65
|
+
await mkdir(resolveStateDir(), { recursive: true });
|
|
66
|
+
await writeFile(resolveStateFilePath(), OFF_MARKER, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.warn('[omoc] Failed to persist persona off-state to disk:', error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function resolveAgentsMdPath(workspaceDir) {
|
|
73
|
+
return join(resolveOpenClawWorkspaceDir(workspaceDir), 'AGENTS.md');
|
|
64
74
|
}
|
|
65
|
-
export async function replaceAgentsMd(personaContent) {
|
|
66
|
-
const agentsPath = resolveAgentsMdPath();
|
|
75
|
+
export async function replaceAgentsMd(personaContent, workspaceDir) {
|
|
76
|
+
const agentsPath = resolveAgentsMdPath(workspaceDir);
|
|
67
77
|
await mkdir(dirname(agentsPath), { recursive: true });
|
|
68
78
|
const merged = `${DEFAULT_AGENTS_MD}\n---\n\n${personaContent}`;
|
|
69
79
|
await writeFile(agentsPath, merged, 'utf-8');
|
|
70
80
|
}
|
|
71
|
-
export async function restoreAgentsMdToDefault() {
|
|
72
|
-
const agentsPath = resolveAgentsMdPath();
|
|
81
|
+
export async function restoreAgentsMdToDefault(workspaceDir) {
|
|
82
|
+
const agentsPath = resolveAgentsMdPath(workspaceDir);
|
|
73
83
|
await mkdir(dirname(agentsPath), { recursive: true });
|
|
74
84
|
await writeFile(agentsPath, DEFAULT_AGENTS_MD, 'utf-8');
|
|
75
85
|
}
|
package/package.json
CHANGED