@aight-cool/aight-utils 0.1.20 → 0.1.22
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/aight-bootstrap/HOOK.md +20 -0
- package/dist/hooks/aight-bootstrap/handler.d.ts +19 -0
- package/dist/hooks/aight-bootstrap/handler.js +16 -266
- package/dist/hooks/aight-bootstrap/handler.js.map +1 -1
- package/dist/index.d.ts +42 -0
- package/dist/index.js +62 -3799
- package/dist/index.js.map +1 -1
- package/dist/src/bootstrap.d.ts +6 -0
- package/dist/src/bootstrap.js +265 -0
- package/dist/src/bootstrap.js.map +1 -0
- package/dist/src/config.d.ts +18 -0
- package/dist/src/config.js +100 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/defaults.d.ts +4 -0
- package/dist/src/defaults.js +5 -0
- package/dist/src/defaults.js.map +1 -0
- package/dist/src/groups.d.ts +10 -0
- package/dist/src/groups.js +59 -0
- package/dist/src/groups.js.map +1 -0
- package/dist/src/health.d.ts +8 -0
- package/dist/src/health.js +58 -0
- package/dist/src/health.js.map +1 -0
- package/dist/src/items.d.ts +51 -0
- package/dist/src/items.js +208 -0
- package/dist/src/items.js.map +1 -0
- package/dist/src/notif-prefs.d.ts +26 -0
- package/dist/src/notif-prefs.js +93 -0
- package/dist/src/notif-prefs.js.map +1 -0
- package/dist/src/push-hook.d.ts +5 -0
- package/dist/src/push-hook.js +117 -0
- package/dist/src/push-hook.js.map +1 -0
- package/dist/src/push-net.d.ts +17 -0
- package/dist/src/push-net.js +61 -0
- package/dist/src/push-net.js.map +1 -0
- package/dist/src/push-store.d.ts +15 -0
- package/dist/src/push-store.js +45 -0
- package/dist/src/push-store.js.map +1 -0
- package/dist/src/push.d.ts +16 -0
- package/dist/src/push.js +86 -0
- package/dist/src/push.js.map +1 -0
- package/dist/src/reminders.d.ts +6 -0
- package/dist/src/reminders.js +75 -0
- package/dist/src/reminders.js.map +1 -0
- package/dist/src/version.d.ts +8 -0
- package/dist/src/version.js +52 -0
- package/dist/src/version.js.map +1 -0
- package/openclaw.plugin.json +7 -1
- package/package.json +2 -2
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Bootstrap — injects AIGHT.md via before_prompt_build hook
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
5
|
+
export declare function registerBootstrap(api: OpenClawPluginApi): void;
|
|
6
|
+
export declare function getBootstrapContent(): string;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Bootstrap — injects AIGHT.md via before_prompt_build hook
|
|
3
|
+
*/
|
|
4
|
+
const AIGHT_MD = `# Aight Integration
|
|
5
|
+
|
|
6
|
+
## ⚠️ Shortcuts Protocol (CRITICAL — follow exactly)
|
|
7
|
+
|
|
8
|
+
When you receive a message starting with "shortcut:", you MUST reply with ONLY a JSON object — no explanation, no markdown fences, no other text:
|
|
9
|
+
{"short_name": "Example Name", "emoji": "🎯"}
|
|
10
|
+
Rules:
|
|
11
|
+
- short_name: 2-4 words, Title Case, describing what the shortcut does
|
|
12
|
+
- emoji: a single relevant emoji
|
|
13
|
+
- Do NOT answer the question in the shortcut text. Just label it.
|
|
14
|
+
- Reply with NOTHING else — just the raw JSON object
|
|
15
|
+
|
|
16
|
+
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.
|
|
17
|
+
|
|
18
|
+
## What You Can Do (via Aight)
|
|
19
|
+
|
|
20
|
+
When the user asks "What can you do?" — here's what to highlight:
|
|
21
|
+
|
|
22
|
+
- **Chat naturally** — Ask anything, get help with tasks, brainstorm ideas
|
|
23
|
+
- **Set reminders & track tasks** — "Remind me to call the dentist tomorrow at 2pm" → creates a reminder in the Today view
|
|
24
|
+
- **Voice mode** — Tap the mic to talk instead of type; you respond with voice too
|
|
25
|
+
- **Manage calendar & email** — Check schedule, draft emails, summarize inbox
|
|
26
|
+
- **Search the web** — Real-time web search, fetch pages, summarize articles
|
|
27
|
+
- **Run shortcuts** — Quick-access saved prompts for things you do often
|
|
28
|
+
- **Browse the Skills marketplace** — 700+ skills to extend capabilities (weather, GitHub, music, finance, etc.)
|
|
29
|
+
- **Create custom agents** — Spin up specialized AI personas for different tasks
|
|
30
|
+
- **Today view** — A personal dashboard with reminders, tasks, deadlines, and background processes
|
|
31
|
+
- **Sub-agents** — Delegate complex tasks to background workers that report back when done
|
|
32
|
+
- **Group chats** — Multi-agent conversations where your agents collaborate
|
|
33
|
+
- **Security built-in** — All data stays on your machine; nothing phones home
|
|
34
|
+
|
|
35
|
+
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.
|
|
36
|
+
|
|
37
|
+
## Audio / Voice (Aight App)
|
|
38
|
+
|
|
39
|
+
The Aight app handles all speech-to-text and text-to-speech on the client side.
|
|
40
|
+
- **Inbound:** The app converts the user's voice to text before sending it to the gateway. You always receive text.
|
|
41
|
+
- **Outbound:** Always respond with plain text only. If the user has voice mode enabled, the app will convert your text response to speech automatically.
|
|
42
|
+
- **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.
|
|
43
|
+
|
|
44
|
+
## When to Use \`aight_item\` (Aight App)
|
|
45
|
+
|
|
46
|
+
- User asks to **set a reminder**: create a trigger with \`scheduledFor\` (ISO 8601)
|
|
47
|
+
- User asks to **create a task**: create an item with labels
|
|
48
|
+
- User mentions a **deadline or event**: create a trigger with appropriate type
|
|
49
|
+
- User wants to **track a PR/issue**: create an item with a URL
|
|
50
|
+
- User says **"done"** or **"cancel"**: update status to "done" or "cancelled"
|
|
51
|
+
|
|
52
|
+
## Item Types (Aight App)
|
|
53
|
+
|
|
54
|
+
| Type | Use For | Examples |
|
|
55
|
+
|------|---------|---------|
|
|
56
|
+
| \`trigger\` | Time-based, fire-once | Reminders, events, deadlines |
|
|
57
|
+
| \`item\` | Stateful, lifecycle | Tasks, PRs, issues, projects |
|
|
58
|
+
| \`process\` | Background work | Subagent runs, builds, deploys |
|
|
59
|
+
|
|
60
|
+
## Rules (Aight App)
|
|
61
|
+
|
|
62
|
+
- Always generate a unique \`id\` (use a short slug like \`remind-groceries-1708012800\`)
|
|
63
|
+
- Parse natural language dates to ISO 8601 before calling the tool
|
|
64
|
+
- Set \`labels\` for categorization (e.g. \`["work", "urgent"]\`)
|
|
65
|
+
- Default status is \`"active"\` — don't set it unless changing state
|
|
66
|
+
- For reminders: set \`type: "trigger"\` and include \`scheduledFor\`
|
|
67
|
+
- For tasks: set \`type: "item"\`
|
|
68
|
+
|
|
69
|
+
## Public Figure Agent Creation (Aight App)
|
|
70
|
+
|
|
71
|
+
When you receive a message starting with "[PUBLIC_FIGURE_AGENT]", **immediately spawn a
|
|
72
|
+
sub-agent** to handle the creation. This ensures a fresh session with no stale context.
|
|
73
|
+
|
|
74
|
+
**Do NOT try to create the agent yourself inline.** Always delegate via \`sessions_spawn\`.
|
|
75
|
+
|
|
76
|
+
\`\`\`
|
|
77
|
+
sessions_spawn({
|
|
78
|
+
task: <the full instructions below, with the person's name filled in>,
|
|
79
|
+
model: "sonnet",
|
|
80
|
+
label: "create-agent-<kebab-name>"
|
|
81
|
+
})
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
The sub-agent task message should contain ALL of the following instructions:
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
Create a new OpenClaw agent based on the public figure: "<Person's Name>"
|
|
89
|
+
|
|
90
|
+
### Step 1: Research
|
|
91
|
+
1. Search the web for: their career, public persona, communication style, notable quotes
|
|
92
|
+
2. Search X/Twitter if relevant for their voice/tone
|
|
93
|
+
3. Identify: communication style, core expertise, personality traits, catchphrases, how they respond to questions
|
|
94
|
+
|
|
95
|
+
### Step 2: Create the Agent
|
|
96
|
+
Use these tools in order:
|
|
97
|
+
|
|
98
|
+
1. **Read the OpenClaw config** to check the agent doesn't already exist:
|
|
99
|
+
\`\`\`
|
|
100
|
+
exec: grep "<agent-id>" ~/.openclaw/openclaw.json
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
2. **Create workspace and agent directories:**
|
|
104
|
+
\`\`\`
|
|
105
|
+
exec: mkdir -p ~/.openclaw/workspace-<agent-id>/memory ~/.openclaw/agents/<agent-id>/agent ~/.openclaw/agents/<agent-id>/sessions
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
3. **Copy model/auth config from an existing agent:**
|
|
109
|
+
\`\`\`
|
|
110
|
+
exec: cp ~/.openclaw/agents/the-strategist/agent/models.json ~/.openclaw/agents/<agent-id>/agent/
|
|
111
|
+
exec: cp ~/.openclaw/agents/the-strategist/agent/auth-profiles.json ~/.openclaw/agents/<agent-id>/agent/
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
4. **Copy standard workspace files from an existing agent:**
|
|
115
|
+
\`\`\`
|
|
116
|
+
exec: for f in AGENTS.md BOOTSTRAP.md HEARTBEAT.md TOOLS.md USER.md; do cp ~/.openclaw/workspace-the-strategist/$f ~/.openclaw/workspace-<agent-id>/$f; done
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
5. **Write SOUL.md** with the researched personality (see template below)
|
|
120
|
+
|
|
121
|
+
6. **Write IDENTITY.md** with name, username, emoji, role, creation date
|
|
122
|
+
|
|
123
|
+
7. **Write MEMORY.md** with a basic header
|
|
124
|
+
|
|
125
|
+
8. **Patch the gateway config** to add the agent to agents.list:
|
|
126
|
+
- Use the \`gateway\` tool with \`action: "config.patch"\`
|
|
127
|
+
- Include ALL existing agents in the list (read them first) plus the new one
|
|
128
|
+
- Set \`note\` to a message confirming creation
|
|
129
|
+
|
|
130
|
+
### SOUL.md Template
|
|
131
|
+
The personality prompt should capture:
|
|
132
|
+
- Who they are and what they're known for
|
|
133
|
+
- Their communication style and tone (with specific examples)
|
|
134
|
+
- How they approach problems and give advice
|
|
135
|
+
- Topics they're passionate about
|
|
136
|
+
- Things they would NOT say or do (stay in character)
|
|
137
|
+
- A note that they are an AI inspired by this person, not the actual person
|
|
138
|
+
- Safety section: they are a roleplay agent, not the real person
|
|
139
|
+
|
|
140
|
+
### Rules
|
|
141
|
+
- Pick a relevant emoji (e.g. 🚀 for Elon, 📺 for Oprah)
|
|
142
|
+
- Agent ID should be kebab-case (e.g. \`elon-musk\`, \`oprah-winfrey\`)
|
|
143
|
+
- Use \`anthropic/claude-sonnet-4-5\` as the model
|
|
144
|
+
- The personality should be detailed (at least 200 words) with specific examples of their voice
|
|
145
|
+
- Always include a disclaimer that this is an AI interpretation
|
|
146
|
+
- If the agent already exists in config, reply saying so — do NOT recreate
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Task Follow-Up Protocol (Watchdog Pattern)
|
|
151
|
+
|
|
152
|
+
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.
|
|
153
|
+
|
|
154
|
+
### Rules
|
|
155
|
+
|
|
156
|
+
1. **Set a watchdog cron when assigning async work.**
|
|
157
|
+
After spawning a sub-agent or assigning a task to another agent, create a one-shot cron job (**5 minutes out**) to check progress:
|
|
158
|
+
\`\`\`
|
|
159
|
+
cron add:
|
|
160
|
+
schedule: { kind: "at", at: "<ISO 8601, 5 min from now>" }
|
|
161
|
+
payload: { kind: "systemEvent", text: "Watchdog: check if <task description> completed. Expected: <files/state>. If not done, check agent status, retry, or do it yourself." }
|
|
162
|
+
sessionTarget: "main"
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
2. **When the watchdog fires:**
|
|
166
|
+
- Check if the expected output exists (files, state changes, messages)
|
|
167
|
+
- If done → great, clean up
|
|
168
|
+
- If not done → check the agent's session (\`sessions_history\`). Is it alive? Stuck? Dead?
|
|
169
|
+
- If stuck/dead → **do the work yourself inline.** No more spawning. No more waiting.
|
|
170
|
+
|
|
171
|
+
3. **Agents must report blockers immediately.**
|
|
172
|
+
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.
|
|
173
|
+
|
|
174
|
+
4. **Fallback ownership.**
|
|
175
|
+
If an agent (or you as coordinator) hasn't made progress in 5 minutes, take over or reassign. No task sits in limbo.
|
|
176
|
+
|
|
177
|
+
5. **Never report failure as a final answer.**
|
|
178
|
+
"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.
|
|
179
|
+
|
|
180
|
+
### When to Use Watchdogs
|
|
181
|
+
- Sub-agent spawns (\`sessions_spawn\`)
|
|
182
|
+
- Multi-step group chat tasks (e.g., "build and test this PR")
|
|
183
|
+
- Any async work where you're waiting on another agent
|
|
184
|
+
- Background processes (builds, deploys, long-running scripts)
|
|
185
|
+
|
|
186
|
+
### When NOT Needed
|
|
187
|
+
- Simple inline tasks you do yourself
|
|
188
|
+
- Quick questions to another agent in a group chat
|
|
189
|
+
- One-shot tool calls that return immediately
|
|
190
|
+
|
|
191
|
+
## Group Chat Message Format
|
|
192
|
+
|
|
193
|
+
When you receive a message prefixed with \`[Group Chat: "Name" — Members: ...]\`, you are in a group chat. The format is:
|
|
194
|
+
|
|
195
|
+
\`\`\`
|
|
196
|
+
[Group Chat: "Name" — Members: emoji Name (@username), ...]
|
|
197
|
+
[Recent messages]
|
|
198
|
+
emoji SenderName: message text
|
|
199
|
+
emoji SenderName: [your message at HH:MM]
|
|
200
|
+
emoji SenderName: message text
|
|
201
|
+
...
|
|
202
|
+
|
|
203
|
+
[Your turn]
|
|
204
|
+
The user's actual message
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
**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.
|
|
208
|
+
|
|
209
|
+
Rules:
|
|
210
|
+
- To address another agent, **@mention them** in your reply text. The app routes automatically.
|
|
211
|
+
- Do **NOT** use \`sessions_send\` — just @mention in your message.
|
|
212
|
+
- Recent messages provide conversational context — the gateway session has full history.
|
|
213
|
+
- \`[Your turn]\` marks the boundary between context and the new message you should respond to.
|
|
214
|
+
- If you need to recall what you said at a specific time, check your own session history — it has the full text.
|
|
215
|
+
|
|
216
|
+
## Group Chat — Task Protocol
|
|
217
|
+
|
|
218
|
+
When a task is posted in any group chat, follow these rules **without exception:**
|
|
219
|
+
|
|
220
|
+
### 1. Claim Immediately
|
|
221
|
+
When you start working on something, say so in the group chat. No silent pickups.
|
|
222
|
+
Example: "Claiming this — looking at the inline code rendering in CodeRenderer.m now."
|
|
223
|
+
|
|
224
|
+
### 2. Report Completion
|
|
225
|
+
When done, post in the group:
|
|
226
|
+
- **Commit hash** (or what you changed)
|
|
227
|
+
- **What changed** (1-2 sentences)
|
|
228
|
+
- **What's needed next** (e.g. "needs native rebuild", "ready for QA", "blocked on X")
|
|
229
|
+
|
|
230
|
+
Don't wait to be asked. Don't go silent after finishing.
|
|
231
|
+
|
|
232
|
+
### 3. Report Blockers Fast (<2 min)
|
|
233
|
+
If you're stuck, say so immediately. Don't spend 10 minutes silently struggling.
|
|
234
|
+
Example: "Blocker: CocoaPods fails with Ruby 4.0 encoding error. Need to downgrade Ruby or find workaround."
|
|
235
|
+
|
|
236
|
+
### 4. No Limbo
|
|
237
|
+
If you've been working on something for 5+ minutes with no progress, escalate or hand it off. Tasks do not sit in limbo.
|
|
238
|
+
|
|
239
|
+
### 5. Silence = Escalation
|
|
240
|
+
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.
|
|
241
|
+
|
|
242
|
+
**This protocol exists because agents repeatedly picked up tasks, worked silently, and never reported back — forcing Bruno to chase every time. That stops now.**
|
|
243
|
+
|
|
244
|
+
## Shortcuts (Aight App)
|
|
245
|
+
|
|
246
|
+
See the Shortcuts Protocol at the top of this document.
|
|
247
|
+
|
|
248
|
+
`;
|
|
249
|
+
export function registerBootstrap(api) {
|
|
250
|
+
try {
|
|
251
|
+
// Register both event names so we work on old (before_agent_start only) and
|
|
252
|
+
// new (before_prompt_build) openclaw. Identical return shape lets the new
|
|
253
|
+
// SDK's `??` merge dedupe the injection.
|
|
254
|
+
const handler = () => ({ systemPrompt: AIGHT_MD });
|
|
255
|
+
api.on("before_prompt_build", handler);
|
|
256
|
+
api.on("before_agent_start", handler);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
api.logger.error(`[aight-utils] Failed to register bootstrap hook: ${err}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
export function getBootstrapContent() {
|
|
263
|
+
return AIGHT_MD;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoPhB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,GAAsB;IACtD,IAAI,CAAC;QACH,4EAA4E;QAC5E,0EAA0E;QAC1E,yCAAyC;QACzC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnD,GAAG,CAAC,EAAE,CAAC,qBAA4B,EAAE,OAAO,CAAC,CAAC;QAC9C,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,oDAAoD,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config RPC module — aight.config.get, aight.config.patch, aight.status
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
5
|
+
export interface AightConfig {
|
|
6
|
+
push?: {
|
|
7
|
+
mode?: "private" | "rich";
|
|
8
|
+
relayUrl?: string;
|
|
9
|
+
relaySecret?: string;
|
|
10
|
+
};
|
|
11
|
+
today?: {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Returns a sanitized copy of the config with secrets redacted */
|
|
16
|
+
export declare function getClientSafeConfig(config: AightConfig): Record<string, unknown>;
|
|
17
|
+
export declare function getPluginConfig(api: OpenClawPluginApi): AightConfig;
|
|
18
|
+
export declare function registerConfig(api: OpenClawPluginApi): void;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config RPC module — aight.config.get, aight.config.patch, aight.status
|
|
3
|
+
*/
|
|
4
|
+
import { DEFAULT_PUSH_MODE } from "./defaults.js";
|
|
5
|
+
/** Strict allowlist of keys this plugin owns — anything else is rejected */
|
|
6
|
+
const PLUGIN_CONFIG_KEYS = new Set(["push", "today"]);
|
|
7
|
+
/** Secret keys that must never be returned to clients via RPC */
|
|
8
|
+
const SECRET_KEYS = ["relaySecret"];
|
|
9
|
+
/** Returns a sanitized copy of the config with secrets redacted */
|
|
10
|
+
export function getClientSafeConfig(config) {
|
|
11
|
+
const safe = JSON.parse(JSON.stringify(config));
|
|
12
|
+
if (safe.push) {
|
|
13
|
+
for (const key of SECRET_KEYS) {
|
|
14
|
+
if (key in safe.push) {
|
|
15
|
+
safe.push[key] = safe.push[key] ? "[REDACTED]" : undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return safe;
|
|
20
|
+
}
|
|
21
|
+
export function getPluginConfig(api) {
|
|
22
|
+
const raw = api.pluginConfig;
|
|
23
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
24
|
+
}
|
|
25
|
+
export function registerConfig(api) {
|
|
26
|
+
api.registerGatewayMethod("aight.config.get", ({ respond }) => {
|
|
27
|
+
respond(true, getClientSafeConfig(getPluginConfig(api)));
|
|
28
|
+
});
|
|
29
|
+
api.registerGatewayMethod("aight.config.patch", async ({ params, respond }) => {
|
|
30
|
+
if (!params || typeof params !== "object") {
|
|
31
|
+
respond(false, { error: "params must be an object" });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// Reject any keys not in the plugin allowlist — never touch root gateway config
|
|
36
|
+
const incoming = params;
|
|
37
|
+
for (const key of Object.keys(incoming)) {
|
|
38
|
+
if (!PLUGIN_CONFIG_KEYS.has(key)) {
|
|
39
|
+
respond(false, { error: `Key "${key}" is not allowed in config.patch` });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Load current config
|
|
44
|
+
const currentConfig = await api.runtime.config.loadConfig();
|
|
45
|
+
const pluginEntry = currentConfig?.plugins?.entries?.["aight-utils"] ?? {};
|
|
46
|
+
const currentPluginConfig = pluginEntry.config ?? {};
|
|
47
|
+
// Deep merge allowed plugin-level keys into plugin config
|
|
48
|
+
const merged = { ...currentPluginConfig };
|
|
49
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
50
|
+
if (value &&
|
|
51
|
+
typeof value === "object" &&
|
|
52
|
+
!Array.isArray(value) &&
|
|
53
|
+
merged[key] &&
|
|
54
|
+
typeof merged[key] === "object") {
|
|
55
|
+
merged[key] = { ...merged[key], ...value };
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
merged[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Build updated config — only the plugin's own config section is modified;
|
|
62
|
+
// root gateway config is preserved as-is and never overwritten by client input.
|
|
63
|
+
const updatedConfig = {
|
|
64
|
+
...currentConfig,
|
|
65
|
+
plugins: {
|
|
66
|
+
...(currentConfig?.plugins ?? {}),
|
|
67
|
+
entries: {
|
|
68
|
+
...(currentConfig?.plugins?.entries ?? {}),
|
|
69
|
+
"aight-utils": {
|
|
70
|
+
...pluginEntry,
|
|
71
|
+
config: merged,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
await api.runtime.config.writeConfigFile(updatedConfig);
|
|
77
|
+
respond(true, { ok: true, config: getClientSafeConfig(merged) });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
81
|
+
api.logger.error(`[aight-utils] config.patch failed: ${msg}`);
|
|
82
|
+
respond(false, { error: msg });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
api.registerGatewayMethod("aight.status", ({ respond }) => {
|
|
86
|
+
const cfg = getPluginConfig(api);
|
|
87
|
+
respond(true, {
|
|
88
|
+
ok: true,
|
|
89
|
+
version: "0.1.0",
|
|
90
|
+
push: {
|
|
91
|
+
mode: cfg.push?.mode ?? DEFAULT_PUSH_MODE,
|
|
92
|
+
relayUrl: cfg.push?.relayUrl ?? "https://push.aight.app",
|
|
93
|
+
},
|
|
94
|
+
today: {
|
|
95
|
+
enabled: cfg.today?.enabled ?? true,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAalD,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtD,iEAAiE;AACjE,MAAM,WAAW,GAAa,CAAC,aAAa,CAAC,CAAC;AAE9C,mEAAmE;AACnE,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAsB;IACpD,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC;IAC7B,OAAO,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAsB;IACnD,GAAG,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,CAAC,EAAE,OAAO,EAAgC,EAAE,EAAE;QAC1F,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,qBAAqB,CACvB,oBAAoB,EACpB,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAgC,EAAE,EAAE;QAC1D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC1C,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,gFAAgF;YAChF,MAAM,QAAQ,GAAG,MAAiC,CAAC;YACnD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjC,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,GAAG,kCAAkC,EAAE,CAAC,CAAC;oBACzE,OAAO;gBACT,CAAC;YACH,CAAC;YAED,sBAAsB;YACtB,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAC5D,MAAM,WAAW,GAAI,aAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YACpF,MAAM,mBAAmB,GAAG,WAAW,CAAC,MAAM,IAAI,EAAE,CAAC;YAErD,0DAA0D;YAC1D,MAAM,MAAM,GAAG,EAAE,GAAG,mBAAmB,EAAE,CAAC;YAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpD,IACE,KAAK;oBACL,OAAO,KAAK,KAAK,QAAQ;oBACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;oBACrB,MAAM,CAAC,GAAG,CAAC;oBACX,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAC/B,CAAC;oBACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACtB,CAAC;YACH,CAAC;YAED,2EAA2E;YAC3E,gFAAgF;YAChF,MAAM,aAAa,GAA4B;gBAC7C,GAAI,aAAyC;gBAC7C,OAAO,EAAE;oBACP,GAAG,CAAE,aAAqB,EAAE,OAAO,IAAI,EAAE,CAAC;oBAC1C,OAAO,EAAE;wBACP,GAAG,CAAE,aAAqB,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;wBACnD,aAAa,EAAE;4BACb,GAAG,WAAW;4BACd,MAAM,EAAE,MAAM;yBACf;qBACF;iBACF;aACF,CAAC;YAEF,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,aAAoB,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAqB,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,GAAG,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,qBAAqB,CAAC,cAAc,EAAE,CAAC,EAAE,OAAO,EAAgC,EAAE,EAAE;QACtF,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,EAAE;YACZ,EAAE,EAAE,IAAI;YACR,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE;gBACJ,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,iBAAiB;gBACzC,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,wBAAwB;aACzD;YACD,KAAK,EAAE;gBACL,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,IAAI;aACpC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/defaults.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAE3D,qCAAqC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAuB,MAAM,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group name store — simple mapping of groupId → display name.
|
|
3
|
+
* The app registers group names via RPC so push notifications
|
|
4
|
+
* can show friendly titles instead of raw IDs.
|
|
5
|
+
*/
|
|
6
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
7
|
+
export declare function loadGroupName(api: OpenClawPluginApi, groupId: string): string | undefined;
|
|
8
|
+
export declare function registerGroupName(api: OpenClawPluginApi, groupId: string, name: string): void;
|
|
9
|
+
export declare function removeGroupName(api: OpenClawPluginApi, groupId: string): void;
|
|
10
|
+
export declare function registerGroupRpc(api: OpenClawPluginApi): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group name store — simple mapping of groupId → display name.
|
|
3
|
+
* The app registers group names via RPC so push notifications
|
|
4
|
+
* can show friendly titles instead of raw IDs.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
const FILENAME = "group-names.json";
|
|
10
|
+
function filePath(api) {
|
|
11
|
+
const dir = api.dataDir ?? join(homedir(), ".openclaw", "plugin-data", "aight-utils");
|
|
12
|
+
mkdirSync(dir, { recursive: true });
|
|
13
|
+
return join(dir, FILENAME);
|
|
14
|
+
}
|
|
15
|
+
function loadAll(api) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(filePath(api), "utf-8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function saveAll(api, data) {
|
|
24
|
+
writeFileSync(filePath(api), JSON.stringify(data), "utf-8");
|
|
25
|
+
}
|
|
26
|
+
export function loadGroupName(api, groupId) {
|
|
27
|
+
return loadAll(api)[groupId];
|
|
28
|
+
}
|
|
29
|
+
export function registerGroupName(api, groupId, name) {
|
|
30
|
+
const data = loadAll(api);
|
|
31
|
+
data[groupId] = name;
|
|
32
|
+
saveAll(api, data);
|
|
33
|
+
}
|
|
34
|
+
export function removeGroupName(api, groupId) {
|
|
35
|
+
const data = loadAll(api);
|
|
36
|
+
delete data[groupId];
|
|
37
|
+
saveAll(api, data);
|
|
38
|
+
}
|
|
39
|
+
export function registerGroupRpc(api) {
|
|
40
|
+
api.registerGatewayMethod("aight.groups.setName", ({ params, respond }) => {
|
|
41
|
+
const { groupId, name } = (params ?? {});
|
|
42
|
+
if (!groupId || !name) {
|
|
43
|
+
respond(false, { error: "groupId and name are required" });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
registerGroupName(api, groupId, name);
|
|
47
|
+
respond(true, { ok: true });
|
|
48
|
+
});
|
|
49
|
+
api.registerGatewayMethod("aight.groups.removeName", ({ params, respond }) => {
|
|
50
|
+
const { groupId } = (params ?? {});
|
|
51
|
+
if (!groupId) {
|
|
52
|
+
respond(false, { error: "groupId is required" });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
removeGroupName(api, groupId);
|
|
56
|
+
respond(true, { ok: true });
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System health RPC — aight.health
|
|
3
|
+
*
|
|
4
|
+
* Returns memory, CPU, disk stats without needing an LLM call.
|
|
5
|
+
* Uses Node built-ins only (no child_process).
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
8
|
+
export declare function registerHealth(api: OpenClawPluginApi): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System health RPC — aight.health
|
|
3
|
+
*
|
|
4
|
+
* Returns memory, CPU, disk stats without needing an LLM call.
|
|
5
|
+
* Uses Node built-ins only (no child_process).
|
|
6
|
+
*/
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
function getStats() {
|
|
10
|
+
let memory = null;
|
|
11
|
+
let cpu = null;
|
|
12
|
+
let disk = null;
|
|
13
|
+
try {
|
|
14
|
+
// Memory — os.totalmem / os.freemem (cross-platform)
|
|
15
|
+
const totalBytes = os.totalmem();
|
|
16
|
+
const freeBytes = os.freemem();
|
|
17
|
+
const usedBytes = totalBytes - freeBytes;
|
|
18
|
+
const totalGB = totalBytes / 1073741824;
|
|
19
|
+
const usedGB = usedBytes / 1073741824;
|
|
20
|
+
memory = {
|
|
21
|
+
usedGB: Math.round(usedGB * 10) / 10,
|
|
22
|
+
totalGB: Math.round(totalGB * 10) / 10,
|
|
23
|
+
percent: Math.round((usedGB / totalGB) * 100),
|
|
24
|
+
};
|
|
25
|
+
// CPU — load average relative to core count (cross-platform)
|
|
26
|
+
const load1m = os.loadavg()[0];
|
|
27
|
+
const cores = os.cpus().length;
|
|
28
|
+
cpu = { percent: Math.round(Math.min((load1m / cores) * 100, 100)) };
|
|
29
|
+
// Disk — fs.statfsSync (Node 18.15+)
|
|
30
|
+
const stat = fs.statfsSync("/");
|
|
31
|
+
const totalDiskBytes = stat.blocks * stat.bsize;
|
|
32
|
+
const freeDiskBytes = stat.bfree * stat.bsize;
|
|
33
|
+
const usedDiskBytes = totalDiskBytes - freeDiskBytes;
|
|
34
|
+
disk = {
|
|
35
|
+
totalGB: Math.round(totalDiskBytes / 1073741824),
|
|
36
|
+
usedGB: Math.round(usedDiskBytes / 1073741824),
|
|
37
|
+
percent: Math.round((usedDiskBytes / totalDiskBytes) * 100),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Best effort — return whatever we got
|
|
42
|
+
}
|
|
43
|
+
return { memory, cpu, disk };
|
|
44
|
+
}
|
|
45
|
+
export function registerHealth(api) {
|
|
46
|
+
api.registerGatewayMethod("aight.health", async ({ respond }) => {
|
|
47
|
+
try {
|
|
48
|
+
const stats = getStats();
|
|
49
|
+
respond(true, stats);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
respond(false, {
|
|
53
|
+
error: err instanceof Error ? err.message : String(err),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/health.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAS9B,SAAS,QAAQ;IACf,IAAI,MAAM,GAA0B,IAAI,CAAC;IACzC,IAAI,GAAG,GAAuB,IAAI,CAAC;IACnC,IAAI,IAAI,GAAwB,IAAI,CAAC;IAErC,IAAI,CAAC;QACH,qDAAqD;QACrD,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;QACxC,MAAM,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;QACtC,MAAM,GAAG;YACP,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE;YACpC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,EAAE;YACtC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC;SAC9C,CAAC;QAEF,6DAA6D;QAC7D,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;QAC/B,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QAErE,qCAAqC;QACrC,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;QAChD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAC9C,MAAM,aAAa,GAAG,cAAc,GAAG,aAAa,CAAC;QACrD,IAAI,GAAG;YACL,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,UAAU,CAAC;YAChD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,UAAU,CAAC;YAC9C,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC;SAC5D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAsB;IACnD,GAAG,CAAC,qBAAqB,CAAC,cAAc,EAAE,KAAK,EAAE,EAAE,OAAO,EAAgC,EAAE,EAAE;QAC5F,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,EAAE;gBACb,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Items Store — aight.items.list, aight.items.upsert, aight.items.delete + aight_item tool
|
|
3
|
+
*/
|
|
4
|
+
import { type Static } from "@sinclair/typebox";
|
|
5
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
6
|
+
export declare const ItemType: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"trigger">, import("@sinclair/typebox").TLiteral<"item">, import("@sinclair/typebox").TLiteral<"process">]>;
|
|
7
|
+
export declare const ItemStatus: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"done">, import("@sinclair/typebox").TLiteral<"fired">, import("@sinclair/typebox").TLiteral<"cancelled">, import("@sinclair/typebox").TLiteral<"deleted">]>;
|
|
8
|
+
export declare const ItemSchema: import("@sinclair/typebox").TObject<{
|
|
9
|
+
id: import("@sinclair/typebox").TString;
|
|
10
|
+
type: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"trigger">, import("@sinclair/typebox").TLiteral<"item">, import("@sinclair/typebox").TLiteral<"process">]>;
|
|
11
|
+
title: import("@sinclair/typebox").TString;
|
|
12
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"done">, import("@sinclair/typebox").TLiteral<"fired">, import("@sinclair/typebox").TLiteral<"cancelled">, import("@sinclair/typebox").TLiteral<"deleted">]>>;
|
|
13
|
+
labels: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
14
|
+
scheduledFor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
15
|
+
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
16
|
+
url: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
17
|
+
metadata: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
18
|
+
createdAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
19
|
+
updatedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
20
|
+
}>;
|
|
21
|
+
export type Item = Static<typeof ItemSchema>;
|
|
22
|
+
export declare function loadItems(): Item[];
|
|
23
|
+
export declare function saveItems(items: Item[]): void;
|
|
24
|
+
export declare function upsertItem(item: Item): Item;
|
|
25
|
+
export declare function deleteItem(id: string): boolean;
|
|
26
|
+
export interface ListFilters {
|
|
27
|
+
type?: string;
|
|
28
|
+
labels?: string[];
|
|
29
|
+
status?: string;
|
|
30
|
+
from?: string;
|
|
31
|
+
to?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function listItems(filters?: ListFilters): Item[];
|
|
34
|
+
export declare const AightItemToolParams: import("@sinclair/typebox").TObject<{
|
|
35
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"update">, import("@sinclair/typebox").TLiteral<"delete">]>;
|
|
36
|
+
item: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
37
|
+
id: import("@sinclair/typebox").TString;
|
|
38
|
+
type: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"trigger">, import("@sinclair/typebox").TLiteral<"item">, import("@sinclair/typebox").TLiteral<"process">]>;
|
|
39
|
+
title: import("@sinclair/typebox").TString;
|
|
40
|
+
status: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"active">, import("@sinclair/typebox").TLiteral<"done">, import("@sinclair/typebox").TLiteral<"fired">, import("@sinclair/typebox").TLiteral<"cancelled">, import("@sinclair/typebox").TLiteral<"deleted">]>>;
|
|
41
|
+
labels: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
42
|
+
scheduledFor: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
43
|
+
description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
44
|
+
url: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
45
|
+
metadata: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
46
|
+
createdAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
47
|
+
updatedAt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
48
|
+
}>>;
|
|
49
|
+
id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
50
|
+
}>;
|
|
51
|
+
export declare function registerItems(api: OpenClawPluginApi): void;
|