agent-sin 0.1.11 → 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.
- package/CHANGELOG.md +79 -0
- package/README.md +2 -1
- package/builtin-skills/_shared/_todo_lib.py +290 -0
- package/builtin-skills/even-g2-setup/main.ts +896 -0
- package/builtin-skills/even-g2-setup/skill.yaml +133 -0
- package/builtin-skills/memo-delete/main.py +28 -107
- package/builtin-skills/memo-delete/skill.yaml +10 -21
- package/builtin-skills/memo-index/main.py +96 -64
- package/builtin-skills/memo-index/skill.yaml +4 -10
- package/builtin-skills/memo-list/main.py +179 -0
- package/builtin-skills/memo-list/skill.yaml +51 -0
- package/builtin-skills/memo-save/main.py +191 -25
- package/builtin-skills/memo-save/skill.yaml +29 -5
- package/builtin-skills/memo-search/main.py +38 -18
- package/builtin-skills/memo-vector-search/main.py +11 -6
- package/builtin-skills/nightly-topic-knowledge/_feedback_lib.py +391 -0
- package/builtin-skills/nightly-topic-knowledge/_topics_lib.py +415 -0
- package/builtin-skills/nightly-topic-knowledge/main.py +403 -0
- package/builtin-skills/nightly-topic-knowledge/skill.yaml +88 -0
- package/builtin-skills/schedule-add/main.py +26 -0
- package/builtin-skills/service-restart/main.ts +249 -0
- package/builtin-skills/service-restart/skill.yaml +49 -0
- package/builtin-skills/todo-add/main.py +3 -1
- package/builtin-skills/todo-delete/main.py +3 -1
- package/builtin-skills/todo-done/main.py +3 -1
- package/builtin-skills/todo-list/main.py +4 -1
- package/builtin-skills/todo-tick/main.py +3 -1
- package/builtin-skills/topic-knowledge-read/main.py +118 -0
- package/builtin-skills/topic-knowledge-read/skill.yaml +49 -0
- package/dist/builder/build-action-classifier.d.ts +18 -0
- package/dist/builder/build-action-classifier.js +82 -1
- package/dist/builder/build-flow.d.ts +33 -4
- package/dist/builder/build-flow.js +251 -89
- package/dist/builder/builder-session.d.ts +1 -1
- package/dist/builder/builder-session.js +112 -7
- package/dist/builder/conversation-router.d.ts +4 -2
- package/dist/builder/conversation-router.js +19 -2
- package/dist/cli/index.js +323 -20
- package/dist/core/ai-provider.d.ts +1 -0
- package/dist/core/ai-provider.js +8 -3
- package/dist/core/chat-engine.d.ts +10 -3
- package/dist/core/chat-engine.js +1563 -197
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +82 -0
- package/dist/core/daily-memory-promotion.d.ts +7 -0
- package/dist/core/daily-memory-promotion.js +568 -14
- package/dist/core/image-attachments.d.ts +31 -0
- package/dist/core/image-attachments.js +237 -0
- package/dist/core/logger.d.ts +2 -1
- package/dist/core/logger.js +77 -1
- package/dist/core/memo-migration.d.ts +3 -0
- package/dist/core/memo-migration.js +422 -0
- package/dist/core/native-modules.d.ts +24 -0
- package/dist/core/native-modules.js +99 -0
- package/dist/core/notifier.d.ts +8 -3
- package/dist/core/notifier.js +191 -17
- package/dist/core/obsidian-vault.d.ts +19 -0
- package/dist/core/obsidian-vault.js +477 -0
- package/dist/core/operating-model.d.ts +2 -0
- package/dist/core/operating-model.js +15 -0
- package/dist/core/output-writer.d.ts +3 -2
- package/dist/core/output-writer.js +108 -7
- package/dist/core/profile-memory.js +22 -1
- package/dist/core/runtime.d.ts +2 -0
- package/dist/core/runtime.js +9 -1
- package/dist/core/secrets.d.ts +4 -0
- package/dist/core/secrets.js +34 -0
- package/dist/core/skill-history.d.ts +44 -0
- package/dist/core/skill-history.js +329 -0
- package/dist/core/skill-registry.d.ts +5 -0
- package/dist/core/skill-registry.js +11 -0
- package/dist/discord/bot.d.ts +13 -0
- package/dist/discord/bot.js +542 -10
- package/dist/even-g2/gateway.d.ts +15 -0
- package/dist/even-g2/gateway.js +868 -0
- package/dist/runtimes/codex-app-server.d.ts +5 -1
- package/dist/runtimes/codex-app-server.js +147 -8
- package/dist/runtimes/python-runner.js +82 -0
- package/dist/runtimes/typescript-runner.js +13 -1
- package/dist/skills-sdk/types.d.ts +19 -4
- package/dist/telegram/bot.d.ts +1 -0
- package/dist/telegram/bot.js +122 -31
- package/package.json +3 -1
- package/templates/even-g2-agent/README.md +83 -0
- package/templates/even-g2-agent/app.json +20 -0
- package/templates/even-g2-agent/index.html +31 -0
- package/templates/even-g2-agent/package-lock.json +1836 -0
- package/templates/even-g2-agent/package.json +22 -0
- package/templates/even-g2-agent/scripts/qr-auto.mjs +182 -0
- package/templates/even-g2-agent/src/embedded-config.ts +4 -0
- package/templates/even-g2-agent/src/main.ts +539 -0
- package/templates/even-g2-agent/src/style.css +70 -0
- package/templates/even-g2-agent/tsconfig.json +11 -0
- package/templates/skill-python/main.py +20 -2
- package/templates/skill-python/skill.yaml +9 -0
- package/templates/skill-typescript/main.ts +40 -5
- package/templates/skill-typescript/skill.yaml +9 -0
package/dist/core/notifier.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { collectLocalFileAttachments, } from "./image-attachments.js";
|
|
2
4
|
import { l } from "./i18n.js";
|
|
3
5
|
const DISCORD_API_BASE = "https://discord.com/api/v10";
|
|
4
6
|
const DISCORD_MESSAGE_LIMIT = 1900;
|
|
5
7
|
const TELEGRAM_API_BASE = "https://api.telegram.org";
|
|
6
8
|
const TELEGRAM_MESSAGE_LIMIT = 3900;
|
|
7
9
|
export async function notify(options) {
|
|
8
|
-
const title = sanitize(options.title);
|
|
9
|
-
const body = sanitize(options.body);
|
|
10
|
+
const title = sanitize(options.title || "");
|
|
11
|
+
const body = sanitize(options.body || "");
|
|
10
12
|
const subtitle = options.subtitle ? sanitize(options.subtitle) : undefined;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const attachmentPaths = normalizeAttachmentPaths(options);
|
|
14
|
+
if (!title && !body && attachmentPaths.length === 0) {
|
|
15
|
+
throw new Error(l("notify: title, body, or filePath is required", "notify: title、body、または filePath が必要です"));
|
|
13
16
|
}
|
|
14
17
|
const requested = options.channel || "auto";
|
|
15
18
|
const channel = requested === "auto" ? resolveAutoChannel() : requested;
|
|
@@ -22,19 +25,30 @@ export async function notify(options) {
|
|
|
22
25
|
case "windows":
|
|
23
26
|
return notifyWindows(title, body, subtitle);
|
|
24
27
|
case "discord":
|
|
25
|
-
return notifyDiscord(title, body, subtitle, options.discordThreadId);
|
|
28
|
+
return notifyDiscord(title, body, subtitle, options.discordThreadId, attachmentPaths, options.cwd);
|
|
26
29
|
case "telegram":
|
|
27
|
-
return notifyTelegram(title, body, subtitle, options.telegramThreadId);
|
|
30
|
+
return notifyTelegram(title, body, subtitle, options.telegramThreadId, attachmentPaths, options.cwd);
|
|
28
31
|
case "slack":
|
|
29
32
|
return notifySlack(title, body, subtitle);
|
|
30
33
|
case "mail":
|
|
31
34
|
return notifyMail(title, body, subtitle, options.to);
|
|
35
|
+
case "g2":
|
|
36
|
+
return notifyG2(title, body, subtitle);
|
|
32
37
|
case "stderr":
|
|
33
38
|
return notifyStderr(title, body, subtitle);
|
|
34
39
|
default:
|
|
35
40
|
return notifyStderr(title, body, subtitle);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
43
|
+
function normalizeAttachmentPaths(options) {
|
|
44
|
+
const paths = [
|
|
45
|
+
options.filePath,
|
|
46
|
+
options.imagePath,
|
|
47
|
+
...(Array.isArray(options.filePaths) ? options.filePaths : []),
|
|
48
|
+
...(Array.isArray(options.imagePaths) ? options.imagePaths : []),
|
|
49
|
+
].filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
50
|
+
return [...new Set(paths)];
|
|
51
|
+
}
|
|
38
52
|
function resolveAutoChannel() {
|
|
39
53
|
if (process.env.AGENT_SIN_NOTIFY_BACKEND === "stderr") {
|
|
40
54
|
return "stderr";
|
|
@@ -105,10 +119,14 @@ async function notifyWindows(title, body, subtitle) {
|
|
|
105
119
|
// Fallback: stderr so the message is not lost on systems without WinRT toast support.
|
|
106
120
|
return notifyStderr(title, body, subtitle);
|
|
107
121
|
}
|
|
108
|
-
async function notifyDiscord(title, body, subtitle, threadIdOverride) {
|
|
122
|
+
async function notifyDiscord(title, body, subtitle, threadIdOverride, attachmentPaths, attachmentCwd) {
|
|
109
123
|
const url = process.env.AGENT_SIN_DISCORD_WEBHOOK_URL;
|
|
110
124
|
const content = formatPlainTextMessage(title, body, subtitle);
|
|
111
|
-
const chunks = splitMessage(content, DISCORD_MESSAGE_LIMIT);
|
|
125
|
+
const chunks = content.trim() ? splitMessage(content, DISCORD_MESSAGE_LIMIT) : [];
|
|
126
|
+
const attachments = await collectLocalFileAttachments({ paths: attachmentPaths, cwd: attachmentCwd });
|
|
127
|
+
if (attachmentPaths.length > 0 && attachments.length === 0) {
|
|
128
|
+
return { channel: "discord", ok: false, detail: "No readable attachment file was found" };
|
|
129
|
+
}
|
|
112
130
|
const rawThreadId = discordNotifyThreadId(threadIdOverride);
|
|
113
131
|
const threadId = normalizeDiscordSnowflake(rawThreadId);
|
|
114
132
|
if (rawThreadId && !threadId) {
|
|
@@ -116,12 +134,18 @@ async function notifyDiscord(title, body, subtitle, threadIdOverride) {
|
|
|
116
134
|
}
|
|
117
135
|
if (url) {
|
|
118
136
|
const webhookUrl = discordWebhookUrl(url, threadId);
|
|
119
|
-
|
|
137
|
+
const textResult = await postDiscordChunks(chunks, (chunk) => postWebhook(webhookUrl, { content: chunk }, "discord"));
|
|
138
|
+
if (!textResult.ok)
|
|
139
|
+
return textResult;
|
|
140
|
+
return postDiscordAttachments(attachments, (attachment) => postDiscordWebhookAttachment(webhookUrl, attachment));
|
|
120
141
|
}
|
|
121
142
|
const token = process.env.AGENT_SIN_DISCORD_BOT_TOKEN;
|
|
122
143
|
const targetId = threadId || discordNotifyChannelId();
|
|
123
144
|
if (token && targetId) {
|
|
124
|
-
|
|
145
|
+
const textResult = await postDiscordChunks(chunks, (chunk) => postDiscordBotMessage(token, targetId, chunk));
|
|
146
|
+
if (!textResult.ok)
|
|
147
|
+
return textResult;
|
|
148
|
+
return postDiscordAttachments(attachments, (attachment) => postDiscordBotAttachment(token, targetId, attachment));
|
|
125
149
|
}
|
|
126
150
|
return {
|
|
127
151
|
channel: "discord",
|
|
@@ -137,7 +161,7 @@ async function notifySlack(title, body, subtitle) {
|
|
|
137
161
|
const text = formatPlainTextMessage(title, body, subtitle);
|
|
138
162
|
return postWebhook(url, { text }, "slack");
|
|
139
163
|
}
|
|
140
|
-
async function notifyTelegram(title, body, subtitle, threadIdOverride) {
|
|
164
|
+
async function notifyTelegram(title, body, subtitle, threadIdOverride, attachmentPaths, attachmentCwd) {
|
|
141
165
|
const token = process.env.AGENT_SIN_TELEGRAM_BOT_TOKEN;
|
|
142
166
|
const chatId = telegramNotifyChatId();
|
|
143
167
|
if (!token) {
|
|
@@ -152,8 +176,15 @@ async function notifyTelegram(title, body, subtitle, threadIdOverride) {
|
|
|
152
176
|
return { channel: "telegram", ok: false, detail: `invalid Telegram thread id: ${rawThreadId}` };
|
|
153
177
|
}
|
|
154
178
|
const content = formatPlainTextMessage(title, body, subtitle);
|
|
155
|
-
const chunks = splitMessage(content, TELEGRAM_MESSAGE_LIMIT);
|
|
156
|
-
|
|
179
|
+
const chunks = content.trim() ? splitMessage(content, TELEGRAM_MESSAGE_LIMIT) : [];
|
|
180
|
+
const attachments = await collectLocalFileAttachments({ paths: attachmentPaths, cwd: attachmentCwd });
|
|
181
|
+
if (attachmentPaths.length > 0 && attachments.length === 0) {
|
|
182
|
+
return { channel: "telegram", ok: false, detail: "No readable attachment file was found" };
|
|
183
|
+
}
|
|
184
|
+
const textResult = await postTelegramChunks(chunks, (chunk) => postTelegramBotMessage(token, chatId, chunk, threadId));
|
|
185
|
+
if (!textResult.ok)
|
|
186
|
+
return textResult;
|
|
187
|
+
return postTelegramAttachments(attachments, (attachment) => postTelegramBotAttachment(token, chatId, attachment, threadId));
|
|
157
188
|
}
|
|
158
189
|
async function notifyMail(title, body, subtitle, toOverride) {
|
|
159
190
|
const host = process.env.AGENT_SIN_SMTP_HOST;
|
|
@@ -211,14 +242,47 @@ async function notifyMail(title, body, subtitle, toOverride) {
|
|
|
211
242
|
};
|
|
212
243
|
}
|
|
213
244
|
}
|
|
245
|
+
async function notifyG2(title, body, subtitle) {
|
|
246
|
+
const url = process.env.AGENT_SIN_G2_NOTIFY_URL || defaultG2NotifyUrl();
|
|
247
|
+
const token = process.env.AGENT_SIN_G2_TOKEN || "";
|
|
248
|
+
const headers = { "content-type": "application/json" };
|
|
249
|
+
if (token) {
|
|
250
|
+
headers.authorization = `Bearer ${token}`;
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
const response = await fetch(url, {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers,
|
|
256
|
+
body: JSON.stringify({ title, body, subtitle }),
|
|
257
|
+
});
|
|
258
|
+
if (!response.ok) {
|
|
259
|
+
return { channel: "g2", ok: false, detail: `HTTP ${response.status} ${response.statusText}`.trim() };
|
|
260
|
+
}
|
|
261
|
+
return { channel: "g2", ok: true };
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
return {
|
|
265
|
+
channel: "g2",
|
|
266
|
+
ok: false,
|
|
267
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function defaultG2NotifyUrl() {
|
|
272
|
+
const port = process.env.AGENT_SIN_G2_PORT || "8765";
|
|
273
|
+
return `http://127.0.0.1:${port}/api/notify`;
|
|
274
|
+
}
|
|
214
275
|
function notifyStderr(title, body, subtitle) {
|
|
215
|
-
const head =
|
|
216
|
-
|
|
276
|
+
const head = [title, subtitle].filter(Boolean).join(" - ");
|
|
277
|
+
const text = head && body ? `${head}: ${body}` : (body || head);
|
|
278
|
+
process.stderr.write(`[notify] ${text}\n`);
|
|
217
279
|
return { channel: "stderr", ok: true };
|
|
218
280
|
}
|
|
219
281
|
function formatPlainTextMessage(title, body, subtitle) {
|
|
220
|
-
const head = subtitle ? `*${title}*
|
|
221
|
-
|
|
282
|
+
const head = title ? (subtitle ? `*${title}* - ${subtitle}` : `*${title}*`) : (subtitle || "");
|
|
283
|
+
if (head && body)
|
|
284
|
+
return `${head}\n${body}`;
|
|
285
|
+
return body || head;
|
|
222
286
|
}
|
|
223
287
|
function hasDiscordBotNotifyConfig() {
|
|
224
288
|
return Boolean(process.env.AGENT_SIN_DISCORD_BOT_TOKEN && (discordNotifyThreadId() || discordNotifyChannelId()));
|
|
@@ -317,6 +381,19 @@ async function postDiscordChunks(chunks, send) {
|
|
|
317
381
|
}
|
|
318
382
|
return { channel: "discord", ok: true, detail: chunks.length > 1 ? `${chunks.length} messages` : undefined };
|
|
319
383
|
}
|
|
384
|
+
async function postDiscordAttachments(attachments, send) {
|
|
385
|
+
let sent = 0;
|
|
386
|
+
for (const attachment of attachments) {
|
|
387
|
+
const result = await send(attachment);
|
|
388
|
+
if (!result.ok) {
|
|
389
|
+
return sent > 0
|
|
390
|
+
? { channel: "discord", ok: false, detail: `sent ${sent}/${attachments.length} attachments: ${result.detail || "failed"}` }
|
|
391
|
+
: result;
|
|
392
|
+
}
|
|
393
|
+
sent += 1;
|
|
394
|
+
}
|
|
395
|
+
return { channel: "discord", ok: true, detail: attachments.length > 1 ? `${attachments.length} attachments` : undefined };
|
|
396
|
+
}
|
|
320
397
|
async function postDiscordBotMessage(token, channelId, content) {
|
|
321
398
|
try {
|
|
322
399
|
const response = await fetch(`${DISCORD_API_BASE}/channels/${channelId}/messages`, {
|
|
@@ -341,6 +418,53 @@ async function postDiscordBotMessage(token, channelId, content) {
|
|
|
341
418
|
};
|
|
342
419
|
}
|
|
343
420
|
}
|
|
421
|
+
async function postDiscordBotAttachment(token, channelId, attachment) {
|
|
422
|
+
try {
|
|
423
|
+
const form = new FormData();
|
|
424
|
+
form.append("payload_json", JSON.stringify({ content: "" }));
|
|
425
|
+
form.append("files[0]", await blobFromLocalAttachment(attachment), attachment.filename);
|
|
426
|
+
const response = await fetch(`${DISCORD_API_BASE}/channels/${channelId}/messages`, {
|
|
427
|
+
method: "POST",
|
|
428
|
+
headers: { authorization: `Bot ${token}` },
|
|
429
|
+
body: form,
|
|
430
|
+
});
|
|
431
|
+
if (!response.ok) {
|
|
432
|
+
const detail = `HTTP ${response.status} ${response.statusText}`.trim();
|
|
433
|
+
return { channel: "discord", ok: false, detail };
|
|
434
|
+
}
|
|
435
|
+
return { channel: "discord", ok: true };
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
return {
|
|
439
|
+
channel: "discord",
|
|
440
|
+
ok: false,
|
|
441
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async function postDiscordWebhookAttachment(url, attachment) {
|
|
446
|
+
try {
|
|
447
|
+
const form = new FormData();
|
|
448
|
+
form.append("payload_json", JSON.stringify({ content: "" }));
|
|
449
|
+
form.append("files[0]", await blobFromLocalAttachment(attachment), attachment.filename);
|
|
450
|
+
const response = await fetch(url, {
|
|
451
|
+
method: "POST",
|
|
452
|
+
body: form,
|
|
453
|
+
});
|
|
454
|
+
if (!response.ok) {
|
|
455
|
+
const detail = `HTTP ${response.status} ${response.statusText}`.trim();
|
|
456
|
+
return { channel: "discord", ok: false, detail };
|
|
457
|
+
}
|
|
458
|
+
return { channel: "discord", ok: true };
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
return {
|
|
462
|
+
channel: "discord",
|
|
463
|
+
ok: false,
|
|
464
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
344
468
|
async function postTelegramChunks(chunks, send) {
|
|
345
469
|
let sent = 0;
|
|
346
470
|
for (const chunk of chunks) {
|
|
@@ -354,6 +478,19 @@ async function postTelegramChunks(chunks, send) {
|
|
|
354
478
|
}
|
|
355
479
|
return { channel: "telegram", ok: true, detail: chunks.length > 1 ? `${chunks.length} messages` : undefined };
|
|
356
480
|
}
|
|
481
|
+
async function postTelegramAttachments(attachments, send) {
|
|
482
|
+
let sent = 0;
|
|
483
|
+
for (const attachment of attachments) {
|
|
484
|
+
const result = await send(attachment);
|
|
485
|
+
if (!result.ok) {
|
|
486
|
+
return sent > 0
|
|
487
|
+
? { channel: "telegram", ok: false, detail: `sent ${sent}/${attachments.length} attachments: ${result.detail || "failed"}` }
|
|
488
|
+
: result;
|
|
489
|
+
}
|
|
490
|
+
sent += 1;
|
|
491
|
+
}
|
|
492
|
+
return { channel: "telegram", ok: true, detail: attachments.length > 1 ? `${attachments.length} attachments` : undefined };
|
|
493
|
+
}
|
|
357
494
|
async function postTelegramBotMessage(token, chatId, text, threadId) {
|
|
358
495
|
try {
|
|
359
496
|
const payload = {
|
|
@@ -383,6 +520,43 @@ async function postTelegramBotMessage(token, chatId, text, threadId) {
|
|
|
383
520
|
};
|
|
384
521
|
}
|
|
385
522
|
}
|
|
523
|
+
async function postTelegramBotAttachment(token, chatId, attachment, threadId) {
|
|
524
|
+
const method = shouldSendTelegramAsPhoto(attachment) ? "sendPhoto" : "sendDocument";
|
|
525
|
+
const fileField = method === "sendPhoto" ? "photo" : "document";
|
|
526
|
+
try {
|
|
527
|
+
const form = new FormData();
|
|
528
|
+
form.append("chat_id", chatId);
|
|
529
|
+
if (threadId) {
|
|
530
|
+
form.append("message_thread_id", threadId);
|
|
531
|
+
}
|
|
532
|
+
form.append(fileField, await blobFromLocalAttachment(attachment), attachment.filename);
|
|
533
|
+
const response = await fetch(`${TELEGRAM_API_BASE}/bot${token}/${method}`, {
|
|
534
|
+
method: "POST",
|
|
535
|
+
body: form,
|
|
536
|
+
});
|
|
537
|
+
if (!response.ok) {
|
|
538
|
+
const detail = `HTTP ${response.status} ${response.statusText}`.trim();
|
|
539
|
+
return { channel: "telegram", ok: false, detail };
|
|
540
|
+
}
|
|
541
|
+
return { channel: "telegram", ok: true };
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
return {
|
|
545
|
+
channel: "telegram",
|
|
546
|
+
ok: false,
|
|
547
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function shouldSendTelegramAsPhoto(attachment) {
|
|
552
|
+
return attachment.isImage && ["image/png", "image/jpeg", "image/webp"].includes(attachment.mimeType.toLowerCase());
|
|
553
|
+
}
|
|
554
|
+
async function blobFromLocalAttachment(attachment) {
|
|
555
|
+
const buffer = await readFile(attachment.path);
|
|
556
|
+
const bytes = new Uint8Array(buffer.length);
|
|
557
|
+
bytes.set(buffer);
|
|
558
|
+
return new Blob([bytes.buffer], { type: attachment.mimeType });
|
|
559
|
+
}
|
|
386
560
|
async function postWebhook(url, payload, channel) {
|
|
387
561
|
try {
|
|
388
562
|
const response = await fetch(url, {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AppConfig } from "./config.js";
|
|
2
|
+
export interface ObsidianVaultLink {
|
|
3
|
+
name: string;
|
|
4
|
+
target: string;
|
|
5
|
+
created: boolean;
|
|
6
|
+
ok: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ObsidianVaultSetupResult {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
vaultDir: string;
|
|
11
|
+
created: boolean;
|
|
12
|
+
links: ObsidianVaultLink[];
|
|
13
|
+
homeCreated: boolean;
|
|
14
|
+
configCreated: boolean;
|
|
15
|
+
symlinkError?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function defaultObsidianVaultDir(): string;
|
|
18
|
+
export declare function resolvedObsidianVaultDir(config: AppConfig): string;
|
|
19
|
+
export declare function ensureObsidianVault(config: AppConfig): Promise<ObsidianVaultSetupResult>;
|