@happycastle/oh-my-openclaw 0.9.0 → 0.10.0

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.
@@ -1,2 +1,6 @@
1
1
  import { OmocPluginApi } from '../types.js';
2
+ export declare function resetPersonaInjectorState(): void;
3
+ export declare function getPersonaInjectorState(): {
4
+ lastInjectedPersonaId: string | null;
5
+ };
2
6
  export declare function registerPersonaInjector(api: OmocPluginApi): void;
@@ -1,5 +1,12 @@
1
1
  import { getActivePersona } from '../utils/persona-state.js';
2
2
  import { readPersonaPromptSync } from '../agents/persona-prompts.js';
3
+ let lastInjectedPersonaId = null;
4
+ export function resetPersonaInjectorState() {
5
+ lastInjectedPersonaId = null;
6
+ }
7
+ export function getPersonaInjectorState() {
8
+ return { lastInjectedPersonaId };
9
+ }
3
10
  export function registerPersonaInjector(api) {
4
11
  api.registerHook('agent:bootstrap', (event) => {
5
12
  const personaId = getActivePersona();
@@ -9,12 +16,20 @@ export function registerPersonaInjector(api) {
9
16
  if (!event.context.bootstrapFiles) {
10
17
  event.context.bootstrapFiles = [];
11
18
  }
19
+ const alreadyInFiles = event.context.bootstrapFiles.some((f) => f.path.startsWith('omoc://persona/'));
20
+ if (alreadyInFiles) {
21
+ return;
22
+ }
23
+ if (lastInjectedPersonaId === personaId) {
24
+ return;
25
+ }
12
26
  try {
13
27
  const content = readPersonaPromptSync(personaId);
14
28
  event.context.bootstrapFiles.push({
15
29
  path: `omoc://persona/${personaId}`,
16
30
  content,
17
31
  });
32
+ lastInjectedPersonaId = personaId;
18
33
  api.logger.info(`[omoc] Persona injected: ${personaId}`);
19
34
  }
20
35
  catch (err) {
@@ -22,6 +37,6 @@ export function registerPersonaInjector(api) {
22
37
  }
23
38
  }, {
24
39
  name: 'oh-my-openclaw.persona-injector',
25
- description: 'Injects active persona prompt into agent bootstrap',
40
+ description: 'Injects active persona prompt once per persona change',
26
41
  });
27
42
  }
@@ -1,8 +1,6 @@
1
1
  import { OmocPluginApi } from '../types.js';
2
+ export type AgentRole = 'orchestrator' | 'worker' | 'lightweight';
3
+ export declare function classifyAgentRole(agentId?: string): AgentRole;
2
4
  export declare function resetEnforcerState(): void;
3
- export declare function getEnforcerState(): {
4
- lastInjectionTime: number;
5
- consecutiveFailures: number;
6
- disabledByFailures: boolean;
7
- };
5
+ export declare function getEnforcerState(): {};
8
6
  export declare function registerTodoEnforcer(api: OmocPluginApi): void;
@@ -1,28 +1,46 @@
1
1
  import { getConfig } from '../utils/config.js';
2
- const DIRECTIVE_TEXT = `[SYSTEM DIRECTIVE: OH-MY-OPENCLAW - TODO CONTINUATION]
3
- You MUST continue working on incomplete todos.
4
- - Do NOT stop until all tasks are marked complete
5
- - Do NOT ask for permission to continue
2
+ const ORCHESTRATOR_IDS = new Set([
3
+ 'omoc_prometheus',
4
+ 'omoc_atlas',
5
+ ]);
6
+ const WORKER_IDS = new Set([
7
+ 'omoc_sisyphus',
8
+ 'omoc_hephaestus',
9
+ 'omoc_frontend',
10
+ ]);
11
+ export function classifyAgentRole(agentId) {
12
+ if (!agentId)
13
+ return 'orchestrator';
14
+ if (ORCHESTRATOR_IDS.has(agentId))
15
+ return 'orchestrator';
16
+ if (WORKER_IDS.has(agentId))
17
+ return 'worker';
18
+ return 'lightweight';
19
+ }
20
+ const ORCHESTRATOR_DIRECTIVE = `[SYSTEM REMINDER - TODO CONTINUATION]
21
+ If you have incomplete todos, continue working on them.
6
22
  - Mark each task complete immediately when finished
7
23
  - If blocked, document the blocker and move to next task
24
+ - Do NOT restate prior messages — output only deltas and next concrete action
25
+ - If no actionable next step remains, declare tasks complete and stop
8
26
 
9
- [SUBAGENT COMPLETION RULE]
10
- When you receive a subagent completion notification ("✅ Subagent finished"):
11
- - This is an ACTION TRIGGER, not an FYI
12
- - IMMEDIATELY check the subagent's result
13
- - Verify against success criteria
14
- - Then proceed to the next task/phase
15
- - NEVER stop after receiving a completion notification`;
16
- let lastInjectionTime = 0;
17
- let consecutiveFailures = 0;
18
- let disabledByFailures = false;
27
+ When you receive a subagent completion notification:
28
+ - Check the subagent's result against success criteria
29
+ - Then proceed to the next task/phase`;
30
+ const WORKER_DIRECTIVE = `[SYSTEM REMINDER - TASK COMPLETION]
31
+ Complete your assigned task, return the result, then stop.
32
+ - Do NOT restate prior messages — output only new findings or changes
33
+ - If blocked, report the blocker and stop`;
34
+ const DIRECTIVES = {
35
+ orchestrator: ORCHESTRATOR_DIRECTIVE,
36
+ worker: WORKER_DIRECTIVE,
37
+ lightweight: null,
38
+ };
19
39
  export function resetEnforcerState() {
20
- lastInjectionTime = 0;
21
- consecutiveFailures = 0;
22
- disabledByFailures = false;
40
+ // no-op — kept for API compatibility (no global state to reset)
23
41
  }
24
42
  export function getEnforcerState() {
25
- return { lastInjectionTime, consecutiveFailures, disabledByFailures };
43
+ return {};
26
44
  }
27
45
  export function registerTodoEnforcer(api) {
28
46
  api.registerHook('agent:bootstrap', (event) => {
@@ -30,36 +48,30 @@ export function registerTodoEnforcer(api) {
30
48
  if (!config.todo_enforcer_enabled) {
31
49
  return;
32
50
  }
33
- if (disabledByFailures) {
34
- api.logger.warn('[omoc] Todo enforcer disabled due to consecutive failures');
35
- return;
36
- }
37
- const now = Date.now();
38
- if (config.todo_enforcer_cooldown_ms > 0 && (now - lastInjectionTime) < config.todo_enforcer_cooldown_ms) {
39
- api.logger.info('[omoc] Todo enforcer skipped (cooldown)');
51
+ const role = classifyAgentRole(event.context.agentId);
52
+ const directive = DIRECTIVES[role];
53
+ if (!directive) {
40
54
  return;
41
55
  }
42
56
  if (!event.context.bootstrapFiles) {
43
57
  event.context.bootstrapFiles = [];
44
58
  }
59
+ const alreadyInjected = event.context.bootstrapFiles.some((f) => f.path === 'omoc://todo-enforcer');
60
+ if (alreadyInjected) {
61
+ return;
62
+ }
45
63
  try {
46
64
  event.context.bootstrapFiles.push({
47
65
  path: 'omoc://todo-enforcer',
48
- content: DIRECTIVE_TEXT,
66
+ content: directive,
49
67
  });
50
- lastInjectionTime = now;
51
- consecutiveFailures = 0;
52
- api.logger.info('[omoc] Todo enforcer directive injected');
68
+ api.logger.info(`[omoc] Todo enforcer injected (role: ${role})`);
53
69
  }
54
- catch {
55
- consecutiveFailures++;
56
- if (config.todo_enforcer_max_failures > 0 && consecutiveFailures >= config.todo_enforcer_max_failures) {
57
- disabledByFailures = true;
58
- api.logger.error(`[omoc] Todo enforcer disabled after ${consecutiveFailures} consecutive failures`);
59
- }
70
+ catch (err) {
71
+ api.logger.error('[omoc] Todo enforcer injection failed:', err);
60
72
  }
61
73
  }, {
62
74
  name: 'oh-my-openclaw.todo-enforcer',
63
- description: 'Injects TODO continuation directive into agent bootstrap',
75
+ description: 'Injects role-aware TODO directive into agent bootstrap',
64
76
  });
65
77
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happycastle/oh-my-openclaw",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Oh-My-OpenClaw plugin — multi-agent orchestration, todo enforcer, ralph loop, and custom tools for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",