niahere 0.3.3 → 0.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niahere",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "A personal AI assistant daemon — chat, scheduled jobs, persona system, extensible via skills.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -135,7 +135,10 @@ export class SlackAttachmentCache {
135
135
  }
136
136
 
137
137
  private async download(url: string): Promise<Buffer> {
138
- const resp = await fetch(url, { headers: { Authorization: `Bearer ${this.botToken}` } });
138
+ const resp = await fetch(url, {
139
+ headers: { Authorization: `Bearer ${this.botToken}` },
140
+ signal: AbortSignal.timeout(30_000),
141
+ });
139
142
  if (!resp.ok) throw new Error(`Slack file download failed: ${resp.status}`);
140
143
  return Buffer.from(await resp.arrayBuffer());
141
144
  }
@@ -184,11 +184,7 @@ class TelegramChannel implements Channel {
184
184
  const { result, messageId } = await state.engine.send(text, {}, attachments);
185
185
  const reply = result.trim() || "(no response)";
186
186
  try {
187
- try {
188
- await bot.api.sendMessage(chatId, reply, { parse_mode: "MarkdownV2" });
189
- } catch {
190
- await bot.api.sendMessage(chatId, reply);
191
- }
187
+ await bot.api.sendMessage(chatId, reply);
192
188
  if (messageId) await Message.updateDeliveryStatus(messageId, "sent").catch(() => {});
193
189
  log.info({ chatId, chars: result.length }, "telegram reply sent");
194
190
  } catch (sendErr) {
@@ -266,7 +262,7 @@ class TelegramChannel implements Channel {
266
262
  const file = await this.bot.api.getFile(fileId);
267
263
  const token = getConfig().channels.telegram.bot_token!;
268
264
  const url = `https://api.telegram.org/file/bot${token}/${file.file_path}`;
269
- const resp = await fetch(url);
265
+ const resp = await fetch(url, { signal: AbortSignal.timeout(30_000) });
270
266
  if (!resp.ok) throw new Error(`Download failed: ${resp.status}`);
271
267
  return Buffer.from(await resp.arrayBuffer());
272
268
  }
@@ -33,6 +33,7 @@ async function twilioPost<T = unknown>(creds: TwilioCreds, suffix: string, body:
33
33
  method: "POST",
34
34
  headers: { Authorization: basicAuth(creds), "Content-Type": "application/x-www-form-urlencoded" },
35
35
  body: body.toString(),
36
+ signal: AbortSignal.timeout(15_000),
36
37
  });
37
38
  if (!resp.ok) {
38
39
  const text = await resp.text().catch(() => "");
package/src/core/alive.ts CHANGED
@@ -107,6 +107,7 @@ async function notifyUser(message: string): Promise<void> {
107
107
  method: "POST",
108
108
  headers: { Authorization: `Bearer ${slToken}`, "Content-Type": "application/json" },
109
109
  body: JSON.stringify({ channel: slRecipient, text: message }),
110
+ signal: AbortSignal.timeout(10_000),
110
111
  });
111
112
  if (resp.ok) {
112
113
  log.info("alive: notified user via slack");
@@ -98,7 +98,10 @@ export async function setSummary(id: string, summary: string): Promise<void> {
98
98
  await sql`UPDATE sessions SET summary = ${summary} WHERE id = ${id}`;
99
99
  }
100
100
 
101
- export async function getRecentSummaries(room: string, limit = 3): Promise<Array<{ summary: string; updatedAt: string }>> {
101
+ export async function getRecentSummaries(
102
+ room: string,
103
+ limit = 3,
104
+ ): Promise<Array<{ summary: string; updatedAt: string }>> {
102
105
  const sql = getSql();
103
106
  // Match summaries from sessions in the same channel (e.g. slack-dm-U...-*)
104
107
  // by extracting the room prefix (everything before the last -N index)
@@ -171,17 +174,16 @@ export async function accumulateMetadata(id: string, resultMeta: Record<string,
171
174
  `;
172
175
  }
173
176
 
177
+ /** Max numeric suffix among rooms matching `${prefix}-N`. Used by rotateRoom() to allocate idx+1 without collisions. */
174
178
  export async function getLatestRoomIndex(prefix: string): Promise<number> {
175
179
  const sql = getSql();
176
180
  const pattern = `^${escapeRegex(prefix)}-\\d+$`;
177
- const rows = await sql`
178
- SELECT room FROM sessions
179
- WHERE room ~ ${pattern}
180
- ORDER BY updated_at DESC
181
- LIMIT 1
182
- `;
183
- if (rows.length === 0) return 0;
184
- const parts = rows[0].room.split("-");
185
- const idx = parseInt(parts[parts.length - 1], 10);
186
- return isNaN(idx) ? 0 : idx;
181
+ const rows = await sql`SELECT room FROM sessions WHERE room ~ ${pattern}`;
182
+ let max = 0;
183
+ for (const row of rows) {
184
+ const parts = (row.room as string).split("-");
185
+ const idx = parseInt(parts[parts.length - 1], 10);
186
+ if (!isNaN(idx) && idx > max) max = idx;
187
+ }
188
+ return max;
187
189
  }