@aight-cool/aight-utils 0.1.13 → 0.1.15

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.13",
5
+ "version": "0.1.15",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
@@ -13,10 +13,7 @@
13
13
  "properties": {
14
14
  "mode": {
15
15
  "type": "string",
16
- "enum": [
17
- "private",
18
- "rich"
19
- ],
16
+ "enum": ["private", "rich"],
20
17
  "default": "rich"
21
18
  },
22
19
  "relayUrl": {
@@ -34,19 +31,13 @@
34
31
  },
35
32
  "platform": {
36
33
  "type": "string",
37
- "enum": [
38
- "ios",
39
- "android"
40
- ]
34
+ "enum": ["ios", "android"]
41
35
  },
42
36
  "registeredAt": {
43
37
  "type": "string"
44
38
  }
45
39
  },
46
- "required": [
47
- "token",
48
- "platform"
49
- ]
40
+ "required": ["token", "platform"]
50
41
  }
51
42
  },
52
43
  "relaySecret": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aight-cool/aight-utils",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
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
@@ -6,6 +6,16 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
6
6
 
7
7
  const AIGHT_MD = `# Aight Integration
8
8
 
9
+ ## ⚠️ Shortcuts Protocol (CRITICAL — follow exactly)
10
+
11
+ When you receive a message starting with "shortcut:", you MUST reply with ONLY a JSON object — no explanation, no markdown fences, no other text:
12
+ {"short_name": "Example Name", "emoji": "🎯"}
13
+ Rules:
14
+ - short_name: 2-4 words, Title Case, describing what the shortcut does
15
+ - emoji: a single relevant emoji
16
+ - Do NOT answer the question in the shortcut text. Just label it.
17
+ - Reply with NOTHING else — just the raw JSON object
18
+
9
19
  Aight is the iOS app the user is chatting through. It connects to the OpenClaw gateway running on their machine, giving them a native mobile interface for their AI agent.
10
20
 
11
21
  ## What You Can Do (via Aight)
@@ -181,9 +191,34 @@ When delegating work to sub-agents or coordinating multi-agent tasks, **never fi
181
191
  - Quick questions to another agent in a group chat
182
192
  - One-shot tool calls that return immediately
183
193
 
184
- ## BUGS Group Chat Task Protocol
194
+ ## Group Chat Message Format
195
+
196
+ When you receive a message prefixed with \`[Group Chat: "Name" — Members: ...]\`, you are in a group chat. The format is:
197
+
198
+ \`\`\`
199
+ [Group Chat: "Name" — Members: emoji Name (@username), ...]
200
+ [Recent messages]
201
+ emoji SenderName: message text
202
+ emoji SenderName: [your message at HH:MM]
203
+ emoji SenderName: message text
204
+ ...
205
+
206
+ [Your turn]
207
+ The user's actual message
208
+ \`\`\`
209
+
210
+ **Your own messages are stubbed.** To save tokens, the app replaces the body of your own messages in the recent messages block with \`[your message at HH:MM]\`. You already have the full text in your session history, so no information is lost. Other agents' and the user's messages are shown in full.
211
+
212
+ Rules:
213
+ - To address another agent, **@mention them** in your reply text. The app routes automatically.
214
+ - Do **NOT** use \`sessions_send\` — just @mention in your message.
215
+ - Recent messages provide conversational context — the gateway session has full history.
216
+ - \`[Your turn]\` marks the boundary between context and the new message you should respond to.
217
+ - If you need to recall what you said at a specific time, check your own session history — it has the full text.
185
218
 
186
- When a task is posted in the BUGS group chat, follow these rules **without exception:**
219
+ ## Group Chat Task Protocol
220
+
221
+ When a task is posted in any group chat, follow these rules **without exception:**
187
222
 
188
223
  ### 1. Claim Immediately
189
224
  When you start working on something, say so in the group chat. No silent pickups.
@@ -211,15 +246,7 @@ If an agent goes silent for 5+ minutes during an active task, any other agent (o
211
246
 
212
247
  ## Shortcuts (Aight App)
213
248
 
214
- When you receive a message starting with "shortcut:", extract a short name and emoji for it.
215
- Reply with ONLY a JSON object — no markdown, no explanation:
216
- \`\`\`
217
- {"short_name": "Example Name", "emoji": "🎯"}
218
- \`\`\`
219
- Rules:
220
- - short_name: 2-4 words, Title Case, describing what the shortcut does
221
- - emoji: a single relevant emoji
222
- - Reply with NOTHING else — just the JSON object
249
+ See the Shortcuts Protocol at the top of this document.
223
250
 
224
251
  `;
225
252
 
package/src/config.ts CHANGED
@@ -16,7 +16,7 @@ export interface AightConfig {
16
16
  };
17
17
  }
18
18
 
19
- /** Keys that belong in the plugin config section (everything else routes to root gateway config) */
19
+ /** Strict allowlist of keys this plugin owns anything else is rejected */
20
20
  const PLUGIN_CONFIG_KEYS = new Set(["push", "today"]);
21
21
 
22
22
  /** Secret keys that must never be returned to clients via RPC */
@@ -53,25 +53,23 @@ export function registerConfig(api: OpenClawPluginApi) {
53
53
  return;
54
54
  }
55
55
  try {
56
+ // Reject any keys not in the plugin allowlist — never touch root gateway config
57
+ const incoming = params as Record<string, unknown>;
58
+ for (const key of Object.keys(incoming)) {
59
+ if (!PLUGIN_CONFIG_KEYS.has(key)) {
60
+ respond(false, { error: `Key "${key}" is not allowed in config.patch` });
61
+ return;
62
+ }
63
+ }
64
+
56
65
  // Load current config
57
66
  const currentConfig = await api.runtime.config.loadConfig();
58
67
  const pluginEntry = (currentConfig as any)?.plugins?.entries?.["aight-utils"] ?? {};
59
68
  const currentPluginConfig = pluginEntry.config ?? {};
60
69
 
61
- // Separate plugin-level keys from gateway root-level keys
62
- const pluginPatch: Record<string, unknown> = {};
63
- const rootPatch: Record<string, unknown> = {};
64
- for (const [key, value] of Object.entries(params as Record<string, unknown>)) {
65
- if (PLUGIN_CONFIG_KEYS.has(key)) {
66
- pluginPatch[key] = value;
67
- } else {
68
- rootPatch[key] = value;
69
- }
70
- }
71
-
72
- // Deep merge plugin-level keys into plugin config
70
+ // Deep merge allowed plugin-level keys into plugin config
73
71
  const merged = { ...currentPluginConfig };
74
- for (const [key, value] of Object.entries(pluginPatch)) {
72
+ for (const [key, value] of Object.entries(incoming)) {
75
73
  if (
76
74
  value &&
77
75
  typeof value === "object" &&
@@ -85,8 +83,9 @@ export function registerConfig(api: OpenClawPluginApi) {
85
83
  }
86
84
  }
87
85
 
88
- // Build updated config: plugin config + root-level overrides
89
- let updatedConfig: Record<string, unknown> = {
86
+ // Build updated config — only the plugin's own config section is modified;
87
+ // root gateway config is preserved as-is and never overwritten by client input.
88
+ const updatedConfig: Record<string, unknown> = {
90
89
  ...(currentConfig as Record<string, unknown>),
91
90
  plugins: {
92
91
  ...((currentConfig as any)?.plugins ?? {}),
@@ -100,21 +99,6 @@ export function registerConfig(api: OpenClawPluginApi) {
100
99
  },
101
100
  };
102
101
 
103
- // Deep merge root-level keys into the gateway config
104
- for (const [key, value] of Object.entries(rootPatch)) {
105
- if (
106
- value &&
107
- typeof value === "object" &&
108
- !Array.isArray(value) &&
109
- updatedConfig[key] &&
110
- typeof updatedConfig[key] === "object"
111
- ) {
112
- updatedConfig[key] = { ...(updatedConfig[key] as Record<string, unknown>), ...value };
113
- } else {
114
- updatedConfig[key] = value;
115
- }
116
- }
117
-
118
102
  await api.runtime.config.writeConfigFile(updatedConfig as any);
119
103
  respond(true, { ok: true, config: getClientSafeConfig(merged as AightConfig) });
120
104
  } catch (err) {
package/src/items.ts CHANGED
@@ -150,13 +150,37 @@ export const AightItemToolParams = Type.Object({
150
150
 
151
151
  // ── Registration ──
152
152
 
153
+ /** Strip heavy fields for list responses — detail is fetched via aight.items.get */
154
+ function toLightItem(item: Item): Omit<Item, "description" | "metadata" | "url"> {
155
+ const { description: _d, metadata: _m, url: _u, ...light } = item;
156
+ return light;
157
+ }
158
+
153
159
  export function registerItems(api: OpenClawPluginApi) {
154
160
  api.registerGatewayMethod(
155
161
  "aight.items.list",
156
162
  ({ params, respond }: GatewayRequestHandlerOptions) => {
157
163
  const filters: ListFilters =
158
164
  params && typeof params === "object" ? (params as ListFilters) : {};
159
- respond(true, { items: listItems(filters) });
165
+ respond(true, { items: listItems(filters).map(toLightItem) });
166
+ },
167
+ );
168
+
169
+ api.registerGatewayMethod(
170
+ "aight.items.get",
171
+ ({ params, respond }: GatewayRequestHandlerOptions) => {
172
+ const id = typeof params?.id === "string" ? params.id : "";
173
+ if (!id) {
174
+ respond(false, { error: "id required" });
175
+ return;
176
+ }
177
+ const all = loadItems();
178
+ const item = all.find((i) => i.id === id);
179
+ if (!item || item.status === "deleted") {
180
+ respond(false, { error: "item not found" });
181
+ return;
182
+ }
183
+ respond(true, { item });
160
184
  },
161
185
  );
162
186