@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.
@@ -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.11",
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": ["private", "rich"],
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": ["ios", "android"]
37
+ "enum": [
38
+ "ios",
39
+ "android"
40
+ ]
35
41
  },
36
42
  "registeredAt": {
37
43
  "type": "string"
38
44
  }
39
45
  },
40
- "required": ["token", "platform"]
46
+ "required": [
47
+ "token",
48
+ "platform"
49
+ ]
41
50
  }
42
51
  },
43
52
  "relaySecret": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aight-cool/aight-utils",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "OpenClaw gateway plugin for Aight App: push notifications, Today items, config RPC, and agent bootstrap",
5
5
  "type": "module",
6
6
  "files": [
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
- // eslint-disable-next-line @typescript-eslint/no-require-imports
155
- const sdk = require("openclaw/plugin-sdk");
156
- if (sdk?.registerPluginHooksFromDir) {
157
- const pluginDir = path.dirname(fileURLToPath(import.meta.url));
158
- const hooksDir = path.join(pluginDir, "..", "hooks");
159
- sdk.registerPluginHooksFromDir(api, hooksDir);
160
- }
161
- } catch {
162
- api.logger.info("[aight-utils] Could not register hooks dir, using inline approach");
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())) {