@aight-cool/aight-utils 0.1.11 → 0.1.13
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/openclaw.plugin.json +13 -4
- package/package.json +1 -1
- package/src/bootstrap.ts +86 -11
- package/src/push-hook.ts +28 -0
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "aight-utils",
|
|
3
3
|
"name": "Aight App Utils",
|
|
4
4
|
"description": "Aight App: Push notifications, Today items, config RPC, and agent bootstrap",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.13",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"properties": {
|
|
14
14
|
"mode": {
|
|
15
15
|
"type": "string",
|
|
16
|
-
"enum": [
|
|
16
|
+
"enum": [
|
|
17
|
+
"private",
|
|
18
|
+
"rich"
|
|
19
|
+
],
|
|
17
20
|
"default": "rich"
|
|
18
21
|
},
|
|
19
22
|
"relayUrl": {
|
|
@@ -31,13 +34,19 @@
|
|
|
31
34
|
},
|
|
32
35
|
"platform": {
|
|
33
36
|
"type": "string",
|
|
34
|
-
"enum": [
|
|
37
|
+
"enum": [
|
|
38
|
+
"ios",
|
|
39
|
+
"android"
|
|
40
|
+
]
|
|
35
41
|
},
|
|
36
42
|
"registeredAt": {
|
|
37
43
|
"type": "string"
|
|
38
44
|
}
|
|
39
45
|
},
|
|
40
|
-
"required": [
|
|
46
|
+
"required": [
|
|
47
|
+
"token",
|
|
48
|
+
"platform"
|
|
49
|
+
]
|
|
41
50
|
}
|
|
42
51
|
},
|
|
43
52
|
"relaySecret": {
|
package/package.json
CHANGED
package/src/bootstrap.ts
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
6
|
-
import * as path from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
6
|
|
|
9
7
|
const AIGHT_MD = `# Aight Integration
|
|
10
8
|
|
|
@@ -29,6 +27,13 @@ When the user asks "What can you do?" — here's what to highlight:
|
|
|
29
27
|
|
|
30
28
|
Keep the response conversational and concise — don't dump the whole list. Pick 4-5 highlights that feel most relevant, and mention there's more to explore in Skills and Settings.
|
|
31
29
|
|
|
30
|
+
## Audio / Voice (Aight App)
|
|
31
|
+
|
|
32
|
+
The Aight app handles all speech-to-text and text-to-speech on the client side.
|
|
33
|
+
- **Inbound:** The app converts the user's voice to text before sending it to the gateway. You always receive text.
|
|
34
|
+
- **Outbound:** Always respond with plain text only. If the user has voice mode enabled, the app will convert your text response to speech automatically.
|
|
35
|
+
- **Never use the TTS tool or send audio files** when the channel is an Aight app client. The app cannot stream audio from the gateway and it will cause playback issues.
|
|
36
|
+
|
|
32
37
|
## When to Use \`aight_item\` (Aight App)
|
|
33
38
|
|
|
34
39
|
- User asks to **set a reminder**: create a trigger with \`scheduledFor\` (ISO 8601)
|
|
@@ -135,6 +140,75 @@ The personality prompt should capture:
|
|
|
135
140
|
|
|
136
141
|
---
|
|
137
142
|
|
|
143
|
+
## Task Follow-Up Protocol (Watchdog Pattern)
|
|
144
|
+
|
|
145
|
+
When delegating work to sub-agents or coordinating multi-agent tasks, **never fire-and-forget.** Use watchdog crons to ensure tasks don't stall silently.
|
|
146
|
+
|
|
147
|
+
### Rules
|
|
148
|
+
|
|
149
|
+
1. **Set a watchdog cron when assigning async work.**
|
|
150
|
+
After spawning a sub-agent or assigning a task to another agent, create a one-shot cron job (**5 minutes out**) to check progress:
|
|
151
|
+
\`\`\`
|
|
152
|
+
cron add:
|
|
153
|
+
schedule: { kind: "at", at: "<ISO 8601, 5 min from now>" }
|
|
154
|
+
payload: { kind: "systemEvent", text: "Watchdog: check if <task description> completed. Expected: <files/state>. If not done, check agent status, retry, or do it yourself." }
|
|
155
|
+
sessionTarget: "main"
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
2. **When the watchdog fires:**
|
|
159
|
+
- Check if the expected output exists (files, state changes, messages)
|
|
160
|
+
- If done → great, clean up
|
|
161
|
+
- If not done → check the agent's session (\`sessions_history\`). Is it alive? Stuck? Dead?
|
|
162
|
+
- If stuck/dead → **do the work yourself inline.** No more spawning. No more waiting.
|
|
163
|
+
|
|
164
|
+
3. **Agents must report blockers immediately.**
|
|
165
|
+
If you hit a wall during a task, say so right away: "I'm stuck on X, need Y." Radio silence for 5+ minutes is unacceptable. Silence = escalation.
|
|
166
|
+
|
|
167
|
+
4. **Fallback ownership.**
|
|
168
|
+
If an agent (or you as coordinator) hasn't made progress in 5 minutes, take over or reassign. No task sits in limbo.
|
|
169
|
+
|
|
170
|
+
5. **Never report failure as a final answer.**
|
|
171
|
+
"The sub-agent died" is not acceptable. "The sub-agent died so I did it myself" is. You own the outcome, not the sub-agent.
|
|
172
|
+
|
|
173
|
+
### When to Use Watchdogs
|
|
174
|
+
- Sub-agent spawns (\`sessions_spawn\`)
|
|
175
|
+
- Multi-step group chat tasks (e.g., "build and test this PR")
|
|
176
|
+
- Any async work where you're waiting on another agent
|
|
177
|
+
- Background processes (builds, deploys, long-running scripts)
|
|
178
|
+
|
|
179
|
+
### When NOT Needed
|
|
180
|
+
- Simple inline tasks you do yourself
|
|
181
|
+
- Quick questions to another agent in a group chat
|
|
182
|
+
- One-shot tool calls that return immediately
|
|
183
|
+
|
|
184
|
+
## BUGS Group Chat — Task Protocol
|
|
185
|
+
|
|
186
|
+
When a task is posted in the BUGS group chat, follow these rules **without exception:**
|
|
187
|
+
|
|
188
|
+
### 1. Claim Immediately
|
|
189
|
+
When you start working on something, say so in the group chat. No silent pickups.
|
|
190
|
+
Example: "Claiming this — looking at the inline code rendering in CodeRenderer.m now."
|
|
191
|
+
|
|
192
|
+
### 2. Report Completion
|
|
193
|
+
When done, post in the group:
|
|
194
|
+
- **Commit hash** (or what you changed)
|
|
195
|
+
- **What changed** (1-2 sentences)
|
|
196
|
+
- **What's needed next** (e.g. "needs native rebuild", "ready for QA", "blocked on X")
|
|
197
|
+
|
|
198
|
+
Don't wait to be asked. Don't go silent after finishing.
|
|
199
|
+
|
|
200
|
+
### 3. Report Blockers Fast (<2 min)
|
|
201
|
+
If you're stuck, say so immediately. Don't spend 10 minutes silently struggling.
|
|
202
|
+
Example: "Blocker: CocoaPods fails with Ruby 4.0 encoding error. Need to downgrade Ruby or find workaround."
|
|
203
|
+
|
|
204
|
+
### 4. No Limbo
|
|
205
|
+
If you've been working on something for 5+ minutes with no progress, escalate or hand it off. Tasks do not sit in limbo.
|
|
206
|
+
|
|
207
|
+
### 5. Silence = Escalation
|
|
208
|
+
If an agent goes silent for 5+ minutes during an active task, any other agent (or the coordinator) should take over. Don't wait for permission.
|
|
209
|
+
|
|
210
|
+
**This protocol exists because agents repeatedly picked up tasks, worked silently, and never reported back — forcing Bruno to chase every time. That stops now.**
|
|
211
|
+
|
|
138
212
|
## Shortcuts (Aight App)
|
|
139
213
|
|
|
140
214
|
When you receive a message starting with "shortcut:", extract a short name and emoji for it.
|
|
@@ -151,15 +225,16 @@ Rules:
|
|
|
151
225
|
|
|
152
226
|
export function registerBootstrap(api: OpenClawPluginApi) {
|
|
153
227
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
228
|
+
api.logger.info("[aight-utils] Attempting to register bootstrap hook...");
|
|
229
|
+
api.logger.info(`[aight-utils] api.on type: ${typeof api.on}`);
|
|
230
|
+
api.on("before_agent_start", (_event: unknown, ctx: { sessionKey?: string }) => {
|
|
231
|
+
// Inject AIGHT.md context into every agent session
|
|
232
|
+
api.logger.info(`[aight-utils] Bootstrap: injecting AIGHT.md into session ${ctx?.sessionKey}`);
|
|
233
|
+
return { systemPrompt: AIGHT_MD };
|
|
234
|
+
});
|
|
235
|
+
api.logger.info("[aight-utils] Bootstrap hook registered (before_agent_start)");
|
|
236
|
+
} catch (err) {
|
|
237
|
+
api.logger.error(`[aight-utils] Failed to register bootstrap hook: ${err}`);
|
|
163
238
|
}
|
|
164
239
|
}
|
|
165
240
|
|
package/src/push-hook.ts
CHANGED
|
@@ -16,6 +16,26 @@ export function registerPushHook(api: OpenClawPluginApi) {
|
|
|
16
16
|
const tokens = loadTokens();
|
|
17
17
|
if (tokens.length === 0) return;
|
|
18
18
|
|
|
19
|
+
// Skip hidden/internal sessions — no push notifications for config,
|
|
20
|
+
// security, voice, sub-agent, or other background sessions.
|
|
21
|
+
const sk = ctx.sessionKey ?? "";
|
|
22
|
+
if (
|
|
23
|
+
sk.endsWith(":aight-config") ||
|
|
24
|
+
sk.endsWith(":aight-pentest") ||
|
|
25
|
+
sk.endsWith(":speak") ||
|
|
26
|
+
sk.endsWith(":structured_content") ||
|
|
27
|
+
sk.endsWith(":main") ||
|
|
28
|
+
sk.includes("subagent") ||
|
|
29
|
+
sk.includes("security-audit") ||
|
|
30
|
+
sk.includes("_skill-audit-") ||
|
|
31
|
+
sk.includes("_ensure-skill-defender") ||
|
|
32
|
+
sk.endsWith("security-fix") ||
|
|
33
|
+
sk.endsWith("skill-scan")
|
|
34
|
+
) {
|
|
35
|
+
api.logger.info(`[aight-utils] Skipping hidden session push: ${sk}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
const msgs = event.messages ?? [];
|
|
20
40
|
api.logger.info(
|
|
21
41
|
`[aight-utils] messages count=${msgs.length} roles=${msgs.map((m: any) => m.role).join(",")}`,
|
|
@@ -47,6 +67,14 @@ export function registerPushHook(api: OpenClawPluginApi) {
|
|
|
47
67
|
return;
|
|
48
68
|
}
|
|
49
69
|
|
|
70
|
+
// Skip hidden/internal sessions (aight-config, structured_content, etc.)
|
|
71
|
+
const sessionKey_ = ctx.sessionKey ?? "";
|
|
72
|
+
const HIDDEN_SESSIONS = ["aight-config", "structured_content"];
|
|
73
|
+
if (HIDDEN_SESSIONS.some((h) => sessionKey_.includes(h))) {
|
|
74
|
+
api.logger.info(`[aight-utils] Skipping hidden session: ${sessionKey_}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
50
78
|
// Skip internal/meta responses
|
|
51
79
|
const skip = ["NO_REPLY", "REPLY_SKIP", "ANNOUNCE_SKIP", "HEARTBEAT_OK"];
|
|
52
80
|
if (skip.includes(preview.trim())) {
|