@happycastle/oh-my-openclaw 0.21.1 → 0.21.3
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/subagent-tracker.js +11 -17
- package/dist/hooks/todo-reminder.js +3 -0
- package/dist/tools/todo/session-key.d.ts +3 -0
- package/dist/tools/todo/session-key.js +16 -0
- package/dist/tools/todo/todo-create.js +2 -2
- package/dist/tools/todo/todo-list.js +2 -2
- package/dist/tools/todo/todo-update.js +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LOG_PREFIX } from '../constants.js';
|
|
2
2
|
import { trackSubagentSpawn, clearSubagentTracking, getCallerSessionKey, getTrackedSubagents } from '../services/webhook-bridge.js';
|
|
3
|
-
import {
|
|
3
|
+
import { callHooksWake } from '../utils/webhook-client.js';
|
|
4
4
|
import { getConfig } from '../utils/config.js';
|
|
5
5
|
const SPAWN_TOOL_NAME = 'sessions_spawn';
|
|
6
6
|
function extractSpawnResult(content) {
|
|
@@ -105,17 +105,15 @@ export function registerSubagentTracker(api) {
|
|
|
105
105
|
const wakeMessage = requesterSessionKey
|
|
106
106
|
? `[System] Sub-agent completed (runId=${runId}, requester=${requesterSessionKey}). Process the result and continue pending work.`
|
|
107
107
|
: `[System] Sub-agent completed (runId=${runId}). Process the result and continue pending work.`;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
...(targetSession ? { sessionKey: targetSession } : {}),
|
|
113
|
-
}, api.logger);
|
|
108
|
+
// Use /hooks/wake to directly inject system event into the main session
|
|
109
|
+
// and trigger an immediate heartbeat. /hooks/agent creates a NEW isolated
|
|
110
|
+
// session which is not what we want — we need the main agent to wake up.
|
|
111
|
+
const result = await callHooksWake(wakeMessage, { gateway_url: config.gateway_url, hooks_token: config.hooks_token }, api.logger);
|
|
114
112
|
if (result.ok) {
|
|
115
|
-
api.logger.info(`${LOG_PREFIX}
|
|
113
|
+
api.logger.info(`${LOG_PREFIX} Wake triggered from subagent_ended: runId=${runId}`);
|
|
116
114
|
}
|
|
117
115
|
else {
|
|
118
|
-
api.logger.warn(`${LOG_PREFIX}
|
|
116
|
+
api.logger.warn(`${LOG_PREFIX} Wake from subagent_ended failed: ${result.error ?? `status ${result.status}`}`);
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
}, { priority: 120 });
|
|
@@ -132,19 +130,15 @@ export function registerSubagentTracker(api) {
|
|
|
132
130
|
const callerSession = getCallerSessionKey(matchedRunId);
|
|
133
131
|
clearSubagentTracking(matchedRunId);
|
|
134
132
|
api.logger.info(`${LOG_PREFIX} Sub-agent announce detected: runId=${matchedRunId} (callerSession=${callerSession ?? 'unknown'})`);
|
|
135
|
-
//
|
|
133
|
+
// Use /hooks/wake to directly inject into main session and trigger heartbeat
|
|
136
134
|
const config = getConfig(api);
|
|
137
135
|
if (config.webhook_bridge_enabled && config.gateway_url && config.hooks_token) {
|
|
138
|
-
void
|
|
139
|
-
name: 'OmOC-SubagentAnnounce',
|
|
140
|
-
deliver: false,
|
|
141
|
-
...(callerSession ? { sessionKey: callerSession } : {}),
|
|
142
|
-
}, api.logger).then((result) => {
|
|
136
|
+
void callHooksWake(`[System] Sub-agent completed (runId=${matchedRunId}). Process the announce result and continue any pending work.`, { gateway_url: config.gateway_url, hooks_token: config.hooks_token }, api.logger).then((result) => {
|
|
143
137
|
if (result.ok) {
|
|
144
|
-
api.logger.info(`${LOG_PREFIX}
|
|
138
|
+
api.logger.info(`${LOG_PREFIX} Wake triggered after sub-agent announce: runId=${matchedRunId}`);
|
|
145
139
|
}
|
|
146
140
|
else {
|
|
147
|
-
api.logger.warn(`${LOG_PREFIX}
|
|
141
|
+
api.logger.warn(`${LOG_PREFIX} Wake after announce failed: ${result.error ?? `status ${result.status}`}`);
|
|
148
142
|
}
|
|
149
143
|
});
|
|
150
144
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TOOL_PREFIX, LOG_PREFIX } from '../constants.js';
|
|
2
2
|
import { getIncompleteTodos, resetStore } from '../tools/todo/store.js';
|
|
3
|
+
import { setCurrentSessionKey } from '../tools/todo/session-key.js';
|
|
3
4
|
import { getConfig } from '../utils/config.js';
|
|
4
5
|
import { callHooksWake } from '../utils/webhook-client.js';
|
|
5
6
|
const TODO_TOOL_NAMES = new Set([
|
|
@@ -89,12 +90,14 @@ export function registerSessionCleanup(api) {
|
|
|
89
90
|
const sessionKey = ctx.sessionKey ?? ctx.sessionId ?? event.sessionId;
|
|
90
91
|
if (!sessionKey)
|
|
91
92
|
return;
|
|
93
|
+
setCurrentSessionKey(sessionKey);
|
|
92
94
|
clearSession(sessionKey, api, 'new session');
|
|
93
95
|
}, { priority: 190 });
|
|
94
96
|
api.on('session_end', async (event, ctx) => {
|
|
95
97
|
const sessionKey = ctx.sessionId ?? event.sessionId;
|
|
96
98
|
if (!sessionKey)
|
|
97
99
|
return;
|
|
100
|
+
setCurrentSessionKey(undefined);
|
|
98
101
|
clearSession(sessionKey, api, 'session_end');
|
|
99
102
|
}, { priority: 50 });
|
|
100
103
|
}
|
|
@@ -1 +1,4 @@
|
|
|
1
|
+
export declare function setCurrentSessionKey(key: string | undefined): void;
|
|
2
|
+
export declare function getCurrentSessionKey(): string | undefined;
|
|
1
3
|
export declare function extractSessionKey(options?: unknown): string | undefined;
|
|
4
|
+
export declare function resolveSessionKey(options?: unknown): string | undefined;
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// Module-level state to capture session key from session_start hook
|
|
2
|
+
let currentSessionKey;
|
|
3
|
+
export function setCurrentSessionKey(key) {
|
|
4
|
+
currentSessionKey = key;
|
|
5
|
+
}
|
|
6
|
+
export function getCurrentSessionKey() {
|
|
7
|
+
return currentSessionKey;
|
|
8
|
+
}
|
|
1
9
|
export function extractSessionKey(options) {
|
|
2
10
|
if (typeof options === 'object' && options !== null) {
|
|
3
11
|
const opts = options;
|
|
@@ -8,3 +16,11 @@ export function extractSessionKey(options) {
|
|
|
8
16
|
}
|
|
9
17
|
return undefined;
|
|
10
18
|
}
|
|
19
|
+
export function resolveSessionKey(options) {
|
|
20
|
+
// First try extracting from options (for future OpenClaw API changes)
|
|
21
|
+
const extracted = extractSessionKey(options);
|
|
22
|
+
if (extracted !== undefined)
|
|
23
|
+
return extracted;
|
|
24
|
+
// Fall back to captured session key from session_start hook
|
|
25
|
+
return getCurrentSessionKey();
|
|
26
|
+
}
|
|
@@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
2
2
|
import { toolResponse, toolError } from '../../utils/helpers.js';
|
|
3
3
|
import { TOOL_PREFIX } from '../../constants.js';
|
|
4
4
|
import { createTodo } from './store.js';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveSessionKey } from './session-key.js';
|
|
6
6
|
const TodoCreateParamsSchema = Type.Object({
|
|
7
7
|
content: Type.String({ description: 'What needs to be done' }),
|
|
8
8
|
priority: Type.Optional(Type.Unsafe({
|
|
@@ -27,7 +27,7 @@ export function registerTodoCreateTool(api) {
|
|
|
27
27
|
const content = params.content?.trim();
|
|
28
28
|
if (!content)
|
|
29
29
|
return toolError('content is required');
|
|
30
|
-
const sessionKey =
|
|
30
|
+
const sessionKey = resolveSessionKey(options);
|
|
31
31
|
const item = createTodo(content, params.priority, params.status, sessionKey);
|
|
32
32
|
return toolResponse(JSON.stringify({ todo: item }, null, 2));
|
|
33
33
|
},
|
|
@@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
2
2
|
import { toolResponse } from '../../utils/helpers.js';
|
|
3
3
|
import { TOOL_PREFIX } from '../../constants.js';
|
|
4
4
|
import { listTodos } from './store.js';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveSessionKey } from './session-key.js';
|
|
6
6
|
const TodoListParamsSchema = Type.Object({
|
|
7
7
|
status: Type.Optional(Type.Unsafe({
|
|
8
8
|
type: 'string',
|
|
@@ -18,7 +18,7 @@ export function registerTodoListTool(api) {
|
|
|
18
18
|
parameters: TodoListParamsSchema,
|
|
19
19
|
optional: true,
|
|
20
20
|
execute: async (_callId, params, options) => {
|
|
21
|
-
const sessionKey =
|
|
21
|
+
const sessionKey = resolveSessionKey(options);
|
|
22
22
|
const items = listTodos(params.status, sessionKey);
|
|
23
23
|
return toolResponse(JSON.stringify({ todos: items, count: items.length }, null, 2));
|
|
24
24
|
},
|
|
@@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
2
2
|
import { toolResponse, toolError } from '../../utils/helpers.js';
|
|
3
3
|
import { TOOL_PREFIX } from '../../constants.js';
|
|
4
4
|
import { updateTodo } from './store.js';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveSessionKey } from './session-key.js';
|
|
6
6
|
const TodoUpdateParamsSchema = Type.Object({
|
|
7
7
|
id: Type.String({ description: 'Todo ID (e.g. todo-1)' }),
|
|
8
8
|
status: Type.Optional(Type.Unsafe({
|
|
@@ -31,7 +31,7 @@ export function registerTodoUpdateTool(api) {
|
|
|
31
31
|
if (!params.status && !params.priority && !params.content) {
|
|
32
32
|
return toolError('At least one of status, priority, or content must be provided');
|
|
33
33
|
}
|
|
34
|
-
const sessionKey =
|
|
34
|
+
const sessionKey = resolveSessionKey(options);
|
|
35
35
|
const updated = updateTodo(id, {
|
|
36
36
|
status: params.status,
|
|
37
37
|
priority: params.priority,
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "oh-my-openclaw",
|
|
3
3
|
"name": "Oh-My-OpenClaw",
|
|
4
4
|
"description": "Multi-agent orchestration plugin — 11 agents, category-based model routing, todo enforcer, ralph loop, agent setup CLI, and custom tools",
|
|
5
|
-
"version": "0.21.
|
|
5
|
+
"version": "0.21.3",
|
|
6
6
|
"skills": [
|
|
7
7
|
"skills"
|
|
8
8
|
],
|
package/package.json
CHANGED