@aight-cool/aight-utils 0.1.19 → 0.1.21

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.
Files changed (48) hide show
  1. package/dist/hooks/aight-bootstrap/HOOK.md +20 -0
  2. package/dist/hooks/aight-bootstrap/handler.d.ts +19 -0
  3. package/dist/hooks/aight-bootstrap/handler.js +16 -266
  4. package/dist/hooks/aight-bootstrap/handler.js.map +1 -1
  5. package/dist/index.d.ts +42 -0
  6. package/dist/index.js +63 -3798
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/bootstrap.d.ts +6 -0
  9. package/dist/src/bootstrap.js +267 -0
  10. package/dist/src/bootstrap.js.map +1 -0
  11. package/dist/src/config.d.ts +18 -0
  12. package/dist/src/config.js +100 -0
  13. package/dist/src/config.js.map +1 -0
  14. package/dist/src/defaults.d.ts +4 -0
  15. package/dist/src/defaults.js +5 -0
  16. package/dist/src/defaults.js.map +1 -0
  17. package/dist/src/groups.d.ts +10 -0
  18. package/dist/src/groups.js +61 -0
  19. package/dist/src/groups.js.map +1 -0
  20. package/dist/src/health.d.ts +8 -0
  21. package/dist/src/health.js +58 -0
  22. package/dist/src/health.js.map +1 -0
  23. package/dist/src/items.d.ts +51 -0
  24. package/dist/src/items.js +208 -0
  25. package/dist/src/items.js.map +1 -0
  26. package/dist/src/notif-prefs.d.ts +26 -0
  27. package/dist/src/notif-prefs.js +96 -0
  28. package/dist/src/notif-prefs.js.map +1 -0
  29. package/dist/src/push-hook.d.ts +5 -0
  30. package/dist/src/push-hook.js +131 -0
  31. package/dist/src/push-hook.js.map +1 -0
  32. package/dist/src/push-net.d.ts +17 -0
  33. package/dist/src/push-net.js +58 -0
  34. package/dist/src/push-net.js.map +1 -0
  35. package/dist/src/push-store.d.ts +15 -0
  36. package/dist/src/push-store.js +45 -0
  37. package/dist/src/push-store.js.map +1 -0
  38. package/dist/src/push.d.ts +16 -0
  39. package/dist/src/push.js +86 -0
  40. package/dist/src/push.js.map +1 -0
  41. package/dist/src/reminders.d.ts +6 -0
  42. package/dist/src/reminders.js +66 -0
  43. package/dist/src/reminders.js.map +1 -0
  44. package/dist/src/version.d.ts +8 -0
  45. package/dist/src/version.js +52 -0
  46. package/dist/src/version.js.map +1 -0
  47. package/openclaw.plugin.json +1 -1
  48. package/package.json +2 -2
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Items Store — aight.items.list, aight.items.upsert, aight.items.delete + aight_item tool
3
+ */
4
+ import { Type } from "@sinclair/typebox";
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+ import * as os from "node:os";
8
+ // ── Types ──
9
+ export const ItemType = Type.Union([
10
+ Type.Literal("trigger"),
11
+ Type.Literal("item"),
12
+ Type.Literal("process"),
13
+ ]);
14
+ export const ItemStatus = Type.Union([
15
+ Type.Literal("active"),
16
+ Type.Literal("done"),
17
+ Type.Literal("fired"),
18
+ Type.Literal("cancelled"),
19
+ Type.Literal("deleted"),
20
+ ]);
21
+ export const ItemSchema = Type.Object({
22
+ id: Type.String({ description: "Unique item ID" }),
23
+ type: ItemType,
24
+ title: Type.String({ description: "Display title" }),
25
+ status: Type.Optional(ItemStatus),
26
+ labels: Type.Optional(Type.Array(Type.String())),
27
+ scheduledFor: Type.Optional(Type.String({ description: "ISO 8601 datetime for triggers" })),
28
+ description: Type.Optional(Type.String()),
29
+ url: Type.Optional(Type.String({ description: "Related URL (PR, issue, etc.)" })),
30
+ metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
31
+ createdAt: Type.Optional(Type.String()),
32
+ updatedAt: Type.Optional(Type.String()),
33
+ });
34
+ // ── Store ──
35
+ const STORE_DIR = path.join(os.homedir(), ".openclaw", "aight");
36
+ const STORE_FILE = path.join(STORE_DIR, "items.json");
37
+ export function loadItems() {
38
+ try {
39
+ if (!fs.existsSync(STORE_FILE))
40
+ return [];
41
+ const raw = fs.readFileSync(STORE_FILE, "utf-8");
42
+ const parsed = JSON.parse(raw);
43
+ return Array.isArray(parsed) ? parsed : [];
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ export function saveItems(items) {
50
+ fs.mkdirSync(STORE_DIR, { recursive: true });
51
+ fs.writeFileSync(STORE_FILE, JSON.stringify(items, null, 2), { encoding: "utf-8", mode: 0o600 });
52
+ }
53
+ const MAX_TITLE_LEN = 500;
54
+ const MAX_DESC_LEN = 5000;
55
+ const MAX_ITEMS = 10000;
56
+ export function upsertItem(item) {
57
+ if (item.title && item.title.length > MAX_TITLE_LEN) {
58
+ throw new Error(`title exceeds max length of ${MAX_TITLE_LEN}`);
59
+ }
60
+ if (item.description && item.description.length > MAX_DESC_LEN) {
61
+ throw new Error(`description exceeds max length of ${MAX_DESC_LEN}`);
62
+ }
63
+ const items = loadItems();
64
+ const now = new Date().toISOString();
65
+ const idx = items.findIndex((i) => i.id === item.id);
66
+ if (idx < 0 && items.length >= MAX_ITEMS) {
67
+ throw new Error(`item store full (max ${MAX_ITEMS})`);
68
+ }
69
+ const merged = {
70
+ ...item,
71
+ status: item.status ?? "active",
72
+ updatedAt: now,
73
+ createdAt: idx >= 0 ? items[idx].createdAt : now,
74
+ };
75
+ if (idx >= 0) {
76
+ items[idx] = merged;
77
+ }
78
+ else {
79
+ items.push(merged);
80
+ }
81
+ saveItems(items);
82
+ return merged;
83
+ }
84
+ export function deleteItem(id) {
85
+ const items = loadItems();
86
+ const idx = items.findIndex((i) => i.id === id);
87
+ if (idx < 0)
88
+ return false;
89
+ items[idx] = { ...items[idx], status: "deleted", updatedAt: new Date().toISOString() };
90
+ saveItems(items);
91
+ return true;
92
+ }
93
+ export function listItems(filters = {}) {
94
+ let items = loadItems().filter((i) => i.status !== "deleted");
95
+ if (filters.type) {
96
+ items = items.filter((i) => i.type === filters.type);
97
+ }
98
+ if (filters.status) {
99
+ items = items.filter((i) => i.status === filters.status);
100
+ }
101
+ if (filters.labels && filters.labels.length > 0) {
102
+ items = items.filter((i) => filters.labels.some((l) => i.labels?.includes(l)));
103
+ }
104
+ if (filters.from) {
105
+ const fromTs = new Date(filters.from).getTime();
106
+ items = items.filter((i) => {
107
+ if (!i.scheduledFor)
108
+ return true;
109
+ return new Date(i.scheduledFor).getTime() >= fromTs;
110
+ });
111
+ }
112
+ if (filters.to) {
113
+ const toTs = new Date(filters.to).getTime();
114
+ items = items.filter((i) => {
115
+ if (!i.scheduledFor)
116
+ return true;
117
+ return new Date(i.scheduledFor).getTime() <= toTs;
118
+ });
119
+ }
120
+ return items;
121
+ }
122
+ // ── Tool schema ──
123
+ export const AightItemToolParams = Type.Object({
124
+ action: Type.Union([Type.Literal("create"), Type.Literal("update"), Type.Literal("delete")]),
125
+ item: Type.Optional(ItemSchema),
126
+ id: Type.Optional(Type.String({ description: "Item ID (for delete)" })),
127
+ });
128
+ // ── Registration ──
129
+ /** Strip heavy fields for list responses — detail is fetched via aight.items.get */
130
+ function toLightItem(item) {
131
+ const { description: _d, metadata: _m, url: _u, ...light } = item;
132
+ return light;
133
+ }
134
+ export function registerItems(api) {
135
+ api.registerGatewayMethod("aight.items.list", ({ params, respond }) => {
136
+ const filters = params && typeof params === "object" ? params : {};
137
+ respond(true, { items: listItems(filters).map(toLightItem) });
138
+ });
139
+ api.registerGatewayMethod("aight.items.get", ({ params, respond }) => {
140
+ const id = typeof params?.id === "string" ? params.id : "";
141
+ if (!id) {
142
+ respond(false, { error: "id required" });
143
+ return;
144
+ }
145
+ const all = loadItems();
146
+ const item = all.find((i) => i.id === id);
147
+ if (!item || item.status === "deleted") {
148
+ respond(false, { error: "item not found" });
149
+ return;
150
+ }
151
+ respond(true, { item });
152
+ });
153
+ api.registerGatewayMethod("aight.items.upsert", ({ params, respond }) => {
154
+ if (!params ||
155
+ typeof params !== "object" ||
156
+ !("id" in params) ||
157
+ !("type" in params) ||
158
+ !("title" in params)) {
159
+ respond(false, { error: "item must have id, type, and title" });
160
+ return;
161
+ }
162
+ const item = upsertItem(params);
163
+ respond(true, { item });
164
+ });
165
+ api.registerGatewayMethod("aight.items.delete", ({ params, respond }) => {
166
+ const id = typeof params?.id === "string" ? params.id : "";
167
+ if (!id) {
168
+ respond(false, { error: "id required" });
169
+ return;
170
+ }
171
+ const ok = deleteItem(id);
172
+ respond(true, { ok, id });
173
+ });
174
+ api.registerTool({
175
+ name: "aight_item",
176
+ label: "Aight Item",
177
+ description: "Create, update, or delete a structured item in the Aight Today view. " +
178
+ "Use for reminders, tasks, events, deadlines, and process tracking. " +
179
+ "Parse natural language dates/times before calling (e.g. 'tomorrow at 3pm' → ISO 8601).",
180
+ parameters: AightItemToolParams,
181
+ async execute(_toolCallId, params) {
182
+ const json = (payload) => ({
183
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
184
+ details: payload,
185
+ });
186
+ try {
187
+ if (params.action === "delete") {
188
+ const id = params.id ?? params.item?.id;
189
+ if (!id)
190
+ throw new Error("id required for delete");
191
+ const ok = deleteItem(id);
192
+ return json({ ok, id });
193
+ }
194
+ if (!params.item)
195
+ throw new Error("item required for create/update");
196
+ if (!params.item.id || !params.item.type || !params.item.title) {
197
+ throw new Error("item must have id, type, and title");
198
+ }
199
+ const item = upsertItem(params.item);
200
+ return json({ action: params.action, item });
201
+ }
202
+ catch (err) {
203
+ return json({ error: err instanceof Error ? err.message : String(err) });
204
+ }
205
+ },
206
+ });
207
+ }
208
+ //# sourceMappingURL=items.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"items.js","sourceRoot":"","sources":["../../src/items.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Notification Preferences — gateway-side storage for push suppression.
3
+ *
4
+ * The app syncs notification preferences here via RPC. The push hook
5
+ * checks these prefs before sending to the relay — if a category is
6
+ * muted, the push never leaves the user's machine.
7
+ *
8
+ * RPC methods:
9
+ * aight.notif.setPrefs — update preferences
10
+ * aight.notif.getPrefs — read current preferences
11
+ */
12
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
13
+ export interface NotifPrefs {
14
+ globalMute: boolean;
15
+ muteUntil: string | null;
16
+ agentReplies: boolean;
17
+ groupChat: boolean;
18
+ cron: boolean;
19
+ }
20
+ export declare function loadNotifPrefs(): NotifPrefs;
21
+ export declare function classifySessionKey(sessionKey: string): "agentReplies" | "groupChat" | "cron";
22
+ /**
23
+ * Check if a push for this sessionKey should be sent.
24
+ */
25
+ export declare function shouldSendPush(sessionKey: string): boolean;
26
+ export declare function registerNotifPrefsRPC(api: OpenClawPluginApi): void;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Notification Preferences — gateway-side storage for push suppression.
3
+ *
4
+ * The app syncs notification preferences here via RPC. The push hook
5
+ * checks these prefs before sending to the relay — if a category is
6
+ * muted, the push never leaves the user's machine.
7
+ *
8
+ * RPC methods:
9
+ * aight.notif.setPrefs — update preferences
10
+ * aight.notif.getPrefs — read current preferences
11
+ */
12
+ import * as fs from "node:fs";
13
+ import * as path from "node:path";
14
+ import * as os from "node:os";
15
+ const DEFAULTS = {
16
+ globalMute: false,
17
+ muteUntil: null,
18
+ agentReplies: true,
19
+ groupChat: true,
20
+ cron: false,
21
+ };
22
+ // ── Storage ──
23
+ const PREFS_DIR = path.join(os.homedir(), ".openclaw", "aight");
24
+ const PREFS_FILE = path.join(PREFS_DIR, "notif-prefs.json");
25
+ export function loadNotifPrefs() {
26
+ try {
27
+ if (!fs.existsSync(PREFS_FILE))
28
+ return { ...DEFAULTS };
29
+ const raw = fs.readFileSync(PREFS_FILE, "utf-8");
30
+ const parsed = JSON.parse(raw);
31
+ return { ...DEFAULTS, ...parsed };
32
+ }
33
+ catch {
34
+ return { ...DEFAULTS };
35
+ }
36
+ }
37
+ function saveNotifPrefs(prefs) {
38
+ fs.mkdirSync(PREFS_DIR, { recursive: true, mode: 0o700 });
39
+ fs.writeFileSync(PREFS_FILE, JSON.stringify(prefs, null, 2), "utf-8");
40
+ }
41
+ // ── Classification (matches app-side logic) ──
42
+ export function classifySessionKey(sessionKey) {
43
+ if (sessionKey.includes(":cron:"))
44
+ return "cron";
45
+ if (sessionKey.includes(":group-chat:"))
46
+ return "groupChat";
47
+ return "agentReplies";
48
+ }
49
+ /**
50
+ * Check if a push for this sessionKey should be sent.
51
+ */
52
+ export function shouldSendPush(sessionKey) {
53
+ if (!sessionKey)
54
+ return true; // fail open
55
+ const prefs = loadNotifPrefs();
56
+ // Global mute
57
+ if (prefs.globalMute) {
58
+ if (!prefs.muteUntil)
59
+ return false; // indefinite
60
+ const expiry = new Date(prefs.muteUntil).getTime();
61
+ if (Date.now() < expiry)
62
+ return false;
63
+ // Mute expired — clear it
64
+ prefs.globalMute = false;
65
+ prefs.muteUntil = null;
66
+ saveNotifPrefs(prefs);
67
+ }
68
+ // Category check
69
+ const category = classifySessionKey(sessionKey);
70
+ return prefs[category];
71
+ }
72
+ // ── RPC Registration ──
73
+ export function registerNotifPrefsRPC(api) {
74
+ api.registerGatewayMethod("aight.notif.getPrefs", ({ respond }) => {
75
+ respond(true, loadNotifPrefs());
76
+ });
77
+ api.registerGatewayMethod("aight.notif.setPrefs", ({ params, respond }) => {
78
+ const update = (params ?? {});
79
+ const current = loadNotifPrefs();
80
+ if (typeof update.globalMute === "boolean")
81
+ current.globalMute = update.globalMute;
82
+ if (typeof update.agentReplies === "boolean")
83
+ current.agentReplies = update.agentReplies;
84
+ if (typeof update.groupChat === "boolean")
85
+ current.groupChat = update.groupChat;
86
+ if (typeof update.cron === "boolean")
87
+ current.cron = update.cron;
88
+ if (update.muteUntil !== undefined)
89
+ current.muteUntil = update.muteUntil;
90
+ saveNotifPrefs(current);
91
+ api.logger.info(`[aight-utils] Notification prefs updated: ${JSON.stringify(current)}`);
92
+ respond(true, current);
93
+ });
94
+ api.logger.info("[aight-utils] Notification prefs RPC registered");
95
+ }
96
+ //# sourceMappingURL=notif-prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notif-prefs.js","sourceRoot":"","sources":["../../src/notif-prefs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Push notification hook — sends push on agent_end.
3
+ */
4
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
5
+ export declare function registerPushHook(api: OpenClawPluginApi): void;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Push notification hook — sends push on agent_end.
3
+ */
4
+ import { getPluginConfig } from "./config.js";
5
+ import { loadTokens, unregisterToken } from "./push-store.js";
6
+ import { sendPush } from "./push-net.js";
7
+ import { loadGroupName } from "./groups.js";
8
+ import { shouldSendPush } from "./notif-prefs.js";
9
+ export function registerPushHook(api) {
10
+ try {
11
+ api.on("agent_end", async (event, ctx) => {
12
+ api.logger.info(`[aight-utils] agent_end fired session=${ctx.sessionKey} agent=${ctx.agentId}`);
13
+ const tokens = loadTokens();
14
+ if (tokens.length === 0)
15
+ return;
16
+ // Skip hidden/internal sessions — no push notifications for config,
17
+ // security, voice, sub-agent, or other background sessions.
18
+ const sk = ctx.sessionKey ?? "";
19
+ if (sk.endsWith(":aight-config") ||
20
+ sk.endsWith(":aight-pentest") ||
21
+ sk.endsWith(":speak") ||
22
+ sk.endsWith(":structured_content") ||
23
+ sk.endsWith(":main") ||
24
+ sk.includes("subagent") ||
25
+ sk.includes("security-audit") ||
26
+ sk.includes("_skill-audit-") ||
27
+ sk.includes("_ensure-skill-defender") ||
28
+ sk.endsWith("security-fix") ||
29
+ sk.endsWith("skill-scan")) {
30
+ api.logger.info(`[aight-utils] Skipping hidden session push: ${sk}`);
31
+ return;
32
+ }
33
+ const msgs = event.messages ?? [];
34
+ api.logger.info(`[aight-utils] messages count=${msgs.length} roles=${msgs.map((m) => m.role).join(",")}`);
35
+ // Extract last assistant message - try string and array content formats
36
+ let preview = "";
37
+ for (let i = msgs.length - 1; i >= 0; i--) {
38
+ const m = msgs[i];
39
+ if (m.role === "assistant") {
40
+ if (typeof m.content === "string" && m.content.trim()) {
41
+ preview = m.content.slice(0, 200);
42
+ break;
43
+ }
44
+ if (Array.isArray(m.content)) {
45
+ const textBlock = m.content.find((b) => b.type === "text" && typeof b.text === "string");
46
+ if (textBlock) {
47
+ preview = textBlock.text.slice(0, 200);
48
+ break;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ if (!preview) {
54
+ api.logger.info(`[aight-utils] No preview found, skipping push`);
55
+ return;
56
+ }
57
+ // Skip hidden/internal sessions (aight-config, structured_content, etc.)
58
+ const sessionKey_ = ctx.sessionKey ?? "";
59
+ const HIDDEN_SESSIONS = ["aight-config", "structured_content"];
60
+ if (HIDDEN_SESSIONS.some((h) => sessionKey_.includes(h))) {
61
+ api.logger.info(`[aight-utils] Skipping hidden session: ${sessionKey_}`);
62
+ return;
63
+ }
64
+ // Skip internal/meta responses
65
+ const skip = ["NO_REPLY", "REPLY_SKIP", "ANNOUNCE_SKIP", "HEARTBEAT_OK"];
66
+ if (skip.includes(preview.trim())) {
67
+ api.logger.info(`[aight-utils] Skipping meta response: ${preview.trim()}`);
68
+ return;
69
+ }
70
+ const freshConfig = getPluginConfig(api);
71
+ // Resolve display name from gateway config agent list
72
+ const agentId = ctx.agentId ?? "agent";
73
+ const agents = api.config?.agents?.list ?? [];
74
+ const agent = agents.find((a) => a.id === agentId);
75
+ const displayName = agent?.name ?? agent?.identity?.name ?? agentId;
76
+ // Resolve group chat name for push subtitle (WhatsApp-style layout)
77
+ const pushTitle = displayName;
78
+ let pushSubtitle;
79
+ const sessionKey = ctx.sessionKey ?? "";
80
+ if (sessionKey.includes(":group-chat:")) {
81
+ const groupId = sessionKey.split(":group-chat:")[1];
82
+ if (groupId) {
83
+ const groupName = loadGroupName(api, groupId);
84
+ if (groupName) {
85
+ pushSubtitle = groupName;
86
+ }
87
+ }
88
+ }
89
+ const cleanBody = preview.trim().replace(/\n+/g, " ").trim();
90
+ // ── Notification preference gate ──
91
+ // Check if this category is muted — if so, don't send the push at all.
92
+ const sk_ = ctx.sessionKey ?? "";
93
+ if (!shouldSendPush(sk_)) {
94
+ api.logger.info(`[aight-utils] Push suppressed by notification prefs: ${sk_}`);
95
+ return;
96
+ }
97
+ for (const device of tokens) {
98
+ if (!device.sendKey)
99
+ continue;
100
+ try {
101
+ const pushResult = await sendPush(device, {
102
+ title: pushTitle.trim(),
103
+ subtitle: pushSubtitle,
104
+ body: cleanBody,
105
+ data: { sessionKey: ctx.sessionKey, agentId },
106
+ }, freshConfig);
107
+ api.logger.info(`[aight-utils] Push sent: session=${ctx.sessionKey} device=${device.deviceId} ok=${pushResult.ok}${pushResult.error ? ` error=${pushResult.error}` : ""}`);
108
+ // Auto-prune stale tokens — if the relay rejects the token, remove it
109
+ if (!pushResult.ok && pushResult.error) {
110
+ const err = pushResult.error.toLowerCase();
111
+ if (err.includes("baddevicetoken") ||
112
+ err.includes("unregistered") ||
113
+ err.includes("devicetokennotfortopic") ||
114
+ err.includes("expired")) {
115
+ api.logger.info(`[aight-utils] Pruning stale device token: ${device.deviceId}`);
116
+ unregisterToken(device.deviceId);
117
+ }
118
+ }
119
+ }
120
+ catch (err) {
121
+ api.logger.warn(`[aight-utils] Push failed: ${err instanceof Error ? err.message : String(err)}`);
122
+ }
123
+ }
124
+ });
125
+ api.logger.info("[aight-utils] Push hook registered (agent_end)");
126
+ }
127
+ catch (err) {
128
+ api.logger.error(`[aight-utils] Failed to register push hook: ${err instanceof Error ? err.message : String(err)}`);
129
+ }
130
+ }
131
+ //# sourceMappingURL=push-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-hook.js","sourceRoot":"","sources":["../../src/push-hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Push relay network calls — fetch only, no filesystem access.
3
+ */
4
+ import type { DeviceToken } from "./push-store.js";
5
+ import type { AightConfig } from "./config.js";
6
+ export declare function obtainSendKey(relayUrl: string, pushToken: string): Promise<string>;
7
+ export interface PushPayload {
8
+ title?: string;
9
+ subtitle?: string;
10
+ body?: string;
11
+ data?: Record<string, unknown>;
12
+ silent?: boolean;
13
+ }
14
+ export declare function sendPush(device: DeviceToken, payload: PushPayload, config: AightConfig): Promise<{
15
+ ok: boolean;
16
+ error?: string;
17
+ }>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Push relay network calls — fetch only, no filesystem access.
3
+ */
4
+ import { DEFAULT_RELAY_URL, DEFAULT_PUSH_MODE } from "./defaults.js";
5
+ // ── Relay Registration (get sendKey) ──
6
+ export async function obtainSendKey(relayUrl, pushToken) {
7
+ const res = await fetch(`${relayUrl}/register`, {
8
+ method: "POST",
9
+ headers: { "Content-Type": "application/json" },
10
+ body: JSON.stringify({ token: pushToken }),
11
+ });
12
+ if (!res.ok) {
13
+ const text = await res.text();
14
+ throw new Error(`Relay /register returned ${res.status}: ${text}`);
15
+ }
16
+ const data = (await res.json());
17
+ if (!data.sendKey)
18
+ throw new Error("Relay did not return a sendKey");
19
+ return data.sendKey;
20
+ }
21
+ export async function sendPush(device, payload, config) {
22
+ if (!device.sendKey) {
23
+ return { ok: false, error: `No sendKey for device ${device.deviceId} — re-register to obtain one` };
24
+ }
25
+ const relayUrl = config.push?.relayUrl ?? DEFAULT_RELAY_URL;
26
+ const mode = config.push?.mode ?? DEFAULT_PUSH_MODE;
27
+ const pushBody = {
28
+ token: device.pushToken,
29
+ sendKey: device.sendKey,
30
+ platform: device.platform,
31
+ sandbox: device.sandbox ?? false,
32
+ };
33
+ if (mode === "rich" && !payload.silent) {
34
+ pushBody.title = payload.title;
35
+ if (payload.subtitle)
36
+ pushBody.subtitle = payload.subtitle;
37
+ pushBody.body = payload.body;
38
+ }
39
+ if (payload.data) {
40
+ pushBody.data = payload.data;
41
+ }
42
+ try {
43
+ const res = await fetch(`${relayUrl}/send`, {
44
+ method: "POST",
45
+ headers: { "Content-Type": "application/json" },
46
+ body: JSON.stringify(pushBody),
47
+ });
48
+ if (!res.ok) {
49
+ const text = await res.text();
50
+ return { ok: false, error: `Relay returned ${res.status}: ${text}` };
51
+ }
52
+ return { ok: true };
53
+ }
54
+ catch (err) {
55
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
56
+ }
57
+ }
58
+ //# sourceMappingURL=push-net.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-net.js","sourceRoot":"","sources":["../../src/push-net.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Push device token persistence — file-based storage only, no network.
3
+ */
4
+ export interface DeviceToken {
5
+ deviceId: string;
6
+ pushToken: string;
7
+ platform: "ios" | "android";
8
+ sandbox?: boolean;
9
+ sendKey?: string;
10
+ registeredAt: string;
11
+ }
12
+ export declare function loadTokens(): DeviceToken[];
13
+ export declare function saveTokens(tokens: DeviceToken[]): void;
14
+ export declare function registerToken(token: DeviceToken): void;
15
+ export declare function unregisterToken(deviceId: string): boolean;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Push device token persistence — file-based storage only, no network.
3
+ */
4
+ import * as fs from "node:fs";
5
+ import * as path from "node:path";
6
+ import * as os from "node:os";
7
+ // ── Store ──
8
+ const TOKEN_DIR = path.join(os.homedir(), ".openclaw", "aight");
9
+ const TOKEN_FILE = path.join(TOKEN_DIR, "devices.json");
10
+ export function loadTokens() {
11
+ try {
12
+ if (!fs.existsSync(TOKEN_FILE))
13
+ return [];
14
+ const raw = fs.readFileSync(TOKEN_FILE, "utf-8");
15
+ const parsed = JSON.parse(raw);
16
+ return Array.isArray(parsed) ? parsed : [];
17
+ }
18
+ catch {
19
+ return [];
20
+ }
21
+ }
22
+ export function saveTokens(tokens) {
23
+ fs.mkdirSync(TOKEN_DIR, { recursive: true, mode: 0o700 });
24
+ fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokens, null, 2), { encoding: "utf-8", mode: 0o600 });
25
+ }
26
+ export function registerToken(token) {
27
+ const tokens = loadTokens();
28
+ const idx = tokens.findIndex((t) => t.deviceId === token.deviceId);
29
+ if (idx >= 0) {
30
+ tokens[idx] = token;
31
+ }
32
+ else {
33
+ tokens.push(token);
34
+ }
35
+ saveTokens(tokens);
36
+ }
37
+ export function unregisterToken(deviceId) {
38
+ const tokens = loadTokens();
39
+ const filtered = tokens.filter((t) => t.deviceId !== deviceId);
40
+ if (filtered.length === tokens.length)
41
+ return false;
42
+ saveTokens(filtered);
43
+ return true;
44
+ }
45
+ //# sourceMappingURL=push-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-store.js","sourceRoot":"","sources":["../../src/push-store.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAa9B,cAAc;AAEd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAChE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAExD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAqB;IAC9C,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC;IACnE,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpD,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC;AACd,CAAC"}