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.
Files changed (97) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +2 -1
  3. package/builtin-skills/_shared/_todo_lib.py +290 -0
  4. package/builtin-skills/even-g2-setup/main.ts +896 -0
  5. package/builtin-skills/even-g2-setup/skill.yaml +133 -0
  6. package/builtin-skills/memo-delete/main.py +28 -107
  7. package/builtin-skills/memo-delete/skill.yaml +10 -21
  8. package/builtin-skills/memo-index/main.py +96 -64
  9. package/builtin-skills/memo-index/skill.yaml +4 -10
  10. package/builtin-skills/memo-list/main.py +179 -0
  11. package/builtin-skills/memo-list/skill.yaml +51 -0
  12. package/builtin-skills/memo-save/main.py +191 -25
  13. package/builtin-skills/memo-save/skill.yaml +29 -5
  14. package/builtin-skills/memo-search/main.py +38 -18
  15. package/builtin-skills/memo-vector-search/main.py +11 -6
  16. package/builtin-skills/nightly-topic-knowledge/_feedback_lib.py +391 -0
  17. package/builtin-skills/nightly-topic-knowledge/_topics_lib.py +415 -0
  18. package/builtin-skills/nightly-topic-knowledge/main.py +403 -0
  19. package/builtin-skills/nightly-topic-knowledge/skill.yaml +88 -0
  20. package/builtin-skills/schedule-add/main.py +26 -0
  21. package/builtin-skills/service-restart/main.ts +249 -0
  22. package/builtin-skills/service-restart/skill.yaml +49 -0
  23. package/builtin-skills/todo-add/main.py +3 -1
  24. package/builtin-skills/todo-delete/main.py +3 -1
  25. package/builtin-skills/todo-done/main.py +3 -1
  26. package/builtin-skills/todo-list/main.py +4 -1
  27. package/builtin-skills/todo-tick/main.py +3 -1
  28. package/builtin-skills/topic-knowledge-read/main.py +118 -0
  29. package/builtin-skills/topic-knowledge-read/skill.yaml +49 -0
  30. package/dist/builder/build-action-classifier.d.ts +18 -0
  31. package/dist/builder/build-action-classifier.js +82 -1
  32. package/dist/builder/build-flow.d.ts +33 -4
  33. package/dist/builder/build-flow.js +251 -89
  34. package/dist/builder/builder-session.d.ts +1 -1
  35. package/dist/builder/builder-session.js +112 -7
  36. package/dist/builder/conversation-router.d.ts +4 -2
  37. package/dist/builder/conversation-router.js +19 -2
  38. package/dist/cli/index.js +323 -20
  39. package/dist/core/ai-provider.d.ts +1 -0
  40. package/dist/core/ai-provider.js +8 -3
  41. package/dist/core/chat-engine.d.ts +10 -3
  42. package/dist/core/chat-engine.js +1563 -197
  43. package/dist/core/config.d.ts +4 -0
  44. package/dist/core/config.js +82 -0
  45. package/dist/core/daily-memory-promotion.d.ts +7 -0
  46. package/dist/core/daily-memory-promotion.js +568 -14
  47. package/dist/core/image-attachments.d.ts +31 -0
  48. package/dist/core/image-attachments.js +237 -0
  49. package/dist/core/logger.d.ts +2 -1
  50. package/dist/core/logger.js +77 -1
  51. package/dist/core/memo-migration.d.ts +3 -0
  52. package/dist/core/memo-migration.js +422 -0
  53. package/dist/core/native-modules.d.ts +24 -0
  54. package/dist/core/native-modules.js +99 -0
  55. package/dist/core/notifier.d.ts +8 -3
  56. package/dist/core/notifier.js +191 -17
  57. package/dist/core/obsidian-vault.d.ts +19 -0
  58. package/dist/core/obsidian-vault.js +477 -0
  59. package/dist/core/operating-model.d.ts +2 -0
  60. package/dist/core/operating-model.js +15 -0
  61. package/dist/core/output-writer.d.ts +3 -2
  62. package/dist/core/output-writer.js +108 -7
  63. package/dist/core/profile-memory.js +22 -1
  64. package/dist/core/runtime.d.ts +2 -0
  65. package/dist/core/runtime.js +9 -1
  66. package/dist/core/secrets.d.ts +4 -0
  67. package/dist/core/secrets.js +34 -0
  68. package/dist/core/skill-history.d.ts +44 -0
  69. package/dist/core/skill-history.js +329 -0
  70. package/dist/core/skill-registry.d.ts +5 -0
  71. package/dist/core/skill-registry.js +11 -0
  72. package/dist/discord/bot.d.ts +13 -0
  73. package/dist/discord/bot.js +542 -10
  74. package/dist/even-g2/gateway.d.ts +15 -0
  75. package/dist/even-g2/gateway.js +868 -0
  76. package/dist/runtimes/codex-app-server.d.ts +5 -1
  77. package/dist/runtimes/codex-app-server.js +147 -8
  78. package/dist/runtimes/python-runner.js +82 -0
  79. package/dist/runtimes/typescript-runner.js +13 -1
  80. package/dist/skills-sdk/types.d.ts +19 -4
  81. package/dist/telegram/bot.d.ts +1 -0
  82. package/dist/telegram/bot.js +122 -31
  83. package/package.json +3 -1
  84. package/templates/even-g2-agent/README.md +83 -0
  85. package/templates/even-g2-agent/app.json +20 -0
  86. package/templates/even-g2-agent/index.html +31 -0
  87. package/templates/even-g2-agent/package-lock.json +1836 -0
  88. package/templates/even-g2-agent/package.json +22 -0
  89. package/templates/even-g2-agent/scripts/qr-auto.mjs +182 -0
  90. package/templates/even-g2-agent/src/embedded-config.ts +4 -0
  91. package/templates/even-g2-agent/src/main.ts +539 -0
  92. package/templates/even-g2-agent/src/style.css +70 -0
  93. package/templates/even-g2-agent/tsconfig.json +11 -0
  94. package/templates/skill-python/main.py +20 -2
  95. package/templates/skill-python/skill.yaml +9 -0
  96. package/templates/skill-typescript/main.ts +40 -5
  97. package/templates/skill-typescript/skill.yaml +9 -0
@@ -2,10 +2,12 @@ import path from "node:path";
2
2
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { loadConfig } from "../core/config.js";
4
4
  import { appendEventLog } from "../core/logger.js";
5
+ import { stripInternalControlBlocks, } from "../core/chat-engine.js";
5
6
  import { createIntentRuntime, renderBuildFooter, shouldShowBuildFooter, } from "../builder/build-flow.js";
6
7
  import { routeConversationMessage, } from "../builder/conversation-router.js";
7
8
  import { cleanProgressText, formatBuildProgress, progressIntervalMs } from "../builder/progress-format.js";
8
9
  import { chunkText, cleanAttachmentText, formatAttachmentLabel, formatBytes, guessImageMimeType, indentAttachmentContent, isImageLikeFile, isTextLikeFile, } from "../core/message-utils.js";
10
+ import { collectLocalFileAttachments, collectLocalImageAttachments, } from "../core/image-attachments.js";
9
11
  import { isEmptyIntentRuntime, loadIntentRuntimeMap, saveIntentRuntimeMap, } from "../builder/intent-runtime-store.js";
10
12
  import { inferLocaleFromText, l, lLines, withLocale } from "../core/i18n.js";
11
13
  import { consumeUpdateBanner, scheduleUpdateCheck } from "../core/update-notifier.js";
@@ -350,20 +352,20 @@ async function handleTelegramMessage(state, message) {
350
352
  draft.update(l("Thinking", "考えています"), { force: true });
351
353
  const prevMode = intentRuntime.mode;
352
354
  try {
353
- const lines = await routeTelegramMessage(state, userText, history, intentRuntime, chatKey, chatId, threadId, message.message_id, draft, userMessage.images);
355
+ const routed = await routeTelegramMessage(state, userText, history, intentRuntime, chatKey, chatId, threadId, message.message_id, draft, userMessage.images);
354
356
  typing.stop();
355
357
  trimHistory(history);
356
358
  void saveTelegramHistories(state);
357
359
  void saveTelegramIntentRuntimes(state);
358
360
  const isBuildEntry = prevMode !== "build" && intentRuntime.mode === "build";
359
- const decorated = withTelegramModeBadge(intentRuntime, lines, { userText, isBuildEntry });
361
+ const decorated = withTelegramModeBadge(intentRuntime, routed.lines, { userText, isBuildEntry });
360
362
  scheduleUpdateCheck(state.config.workspace);
361
363
  const banner = await consumeUpdateBanner(state.config.workspace);
362
364
  const finalLines = banner ? [banner, "", ...decorated] : decorated;
363
365
  const reply = finalLines.filter((line) => line !== undefined && line !== null).join("\n").trim();
364
366
  draft.update(l("Sending reply", "応答を送信しています"), { force: true });
365
367
  await draft.finish();
366
- await sendTelegramMessage(state, chatId, reply || l("(no response)", "(応答なし)"), sendOptions);
368
+ await sendTelegramMessageWithLocalAttachments(state, chatId, reply || l("(no response)", "(応答なし)"), sendOptions, routed.localAttachmentPaths);
367
369
  }
368
370
  catch (error) {
369
371
  typing.stop();
@@ -397,7 +399,8 @@ async function refreshTelegramStateConfig(state) {
397
399
  }
398
400
  }
399
401
  async function routeTelegramMessage(state, text, history, intentRuntime, chatKey, chatId, threadId, replyToMessageId, draft, images = []) {
400
- return routeConversationMessage({
402
+ const localAttachmentPaths = [];
403
+ const lines = await routeConversationMessage({
401
404
  config: state.config,
402
405
  text,
403
406
  history,
@@ -407,7 +410,11 @@ async function routeTelegramMessage(state, text, history, intentRuntime, chatKey
407
410
  createBuildProgress: () => createTelegramBuildProgressReporter(state, chatKey, chatId, threadId, replyToMessageId, draft),
408
411
  onChatProgress: (event) => draft.onChatProgress(event),
409
412
  onAiProgress: (event) => draft.onAiProgress(event),
413
+ onLocalAttachments: (paths) => {
414
+ localAttachmentPaths.push(...paths);
415
+ },
410
416
  });
417
+ return { lines, localAttachmentPaths };
411
418
  }
412
419
  function createTelegramBuildProgressReporter(state, chatKey, chatId, threadId, replyToMessageId, draft) {
413
420
  const minIntervalMs = telegramProgressIntervalMs();
@@ -527,31 +534,9 @@ function helpText() {
527
534
  return lLines([
528
535
  "Welcome to the Agent-Sin Telegram bot.",
529
536
  "It responds in DMs, mentions, and replies to the bot. Registered skills are called automatically when useful.",
530
- "",
531
- "Commands:",
532
- " /help Show this help",
533
- " /reset Reset this chat history",
534
- " /progress quiet|detail Toggle progress messages",
535
- " /back Return from build/edit mode to chat mode",
536
- " /build [skill-id] [request] Create a new skill",
537
- ' /build chat <id> "message" Revise through conversation',
538
- " /build list List drafts",
539
- " /build test <id> Test a draft",
540
- " /build status <id> Show status",
541
537
  ], [
542
538
  "Agent-Sin Telegram bot へようこそ。",
543
539
  "DM、メンション、bot への返信に反応します。登録済みスキルも自動で呼び出されます。",
544
- "",
545
- "コマンド:",
546
- " /help この使い方を表示",
547
- " /reset このチャットの会話履歴をリセット",
548
- " /progress quiet|detail 進捗通知の量を切り替え",
549
- " /back build / edit モードから chat モードに戻る",
550
- " /build [skill-id] [要望] 新規スキルを作成",
551
- ' /build chat <id> "メッセージ" 会話しながら修正',
552
- " /build list 作成中の一覧",
553
- " /build test <id> 動作確認",
554
- " /build status <id> 状態を見る",
555
540
  ]).join("\n");
556
541
  }
557
542
  async function formatTelegramUserMessageForChat(state, message) {
@@ -733,7 +718,7 @@ async function persistTelegramAttachmentBuffer(state, attachment, buffer, mimeTy
733
718
  const HH = String(now.getHours()).padStart(2, "0");
734
719
  const mm = String(now.getMinutes()).padStart(2, "0");
735
720
  const ss = String(now.getSeconds()).padStart(2, "0");
736
- const dir = path.join(state.config.notes_dir, "attachments", yyyy, MM);
721
+ const dir = path.join(state.config.memory_dir, "attachments", yyyy, MM);
737
722
  await mkdir(dir, { recursive: true });
738
723
  const ext = pickAttachmentExtension(attachment.filename, mimeType);
739
724
  const random = Math.random().toString(36).slice(2, 8);
@@ -924,6 +909,12 @@ export function formatTelegramDraftProgress(event) {
924
909
  return null;
925
910
  }
926
911
  }
912
+ export function formatTelegramChatDraftProgress(event) {
913
+ if (event.kind === "message") {
914
+ return l("Preparing reply", "応答を整理しています");
915
+ }
916
+ return formatTelegramDraftProgress(event);
917
+ }
927
918
  function createTelegramDraftStreamer(state, message) {
928
919
  if (!shouldUseTelegramDraftStream(message)) {
929
920
  return noopTelegramDraftStreamer();
@@ -990,9 +981,9 @@ function createTelegramDraftStreamer(state, message) {
990
981
  }
991
982
  },
992
983
  onAiProgress(event) {
993
- const text = formatTelegramDraftProgress(event);
984
+ const text = formatTelegramChatDraftProgress(event);
994
985
  if (text)
995
- enqueue(text, event.kind === "message");
986
+ enqueue(text);
996
987
  },
997
988
  onBuildProgress(event) {
998
989
  const text = formatTelegramDraftProgress(event);
@@ -1024,7 +1015,7 @@ function telegramDraftIntervalMs() {
1024
1015
  return 1500;
1025
1016
  }
1026
1017
  function cleanDraftText(text) {
1027
- const cleaned = text
1018
+ const cleaned = stripInternalControlBlocks(text)
1028
1019
  .replace(/```/g, "")
1029
1020
  .replace(/\r\n/g, "\n")
1030
1021
  .replace(/\r/g, "\n")
@@ -1058,7 +1049,11 @@ function startTypingKeepalive(state, chatId, threadId) {
1058
1049
  };
1059
1050
  }
1060
1051
  async function sendTelegramMessage(state, chatId, content, options = {}) {
1061
- const chunks = chunkTelegramMessage(content);
1052
+ const sanitized = stripInternalControlBlocks(content);
1053
+ if (!sanitized.trim()) {
1054
+ return;
1055
+ }
1056
+ const chunks = chunkTelegramMessage(sanitized);
1062
1057
  for (let index = 0; index < chunks.length; index += 1) {
1063
1058
  const chunk = chunks[index];
1064
1059
  const payload = telegramSendPayload(chatId, chunk, index === 0 ? options : { threadId: options.threadId });
@@ -1088,6 +1083,60 @@ async function sendTelegramMessage(state, chatId, content, options = {}) {
1088
1083
  }
1089
1084
  }
1090
1085
  }
1086
+ async function sendTelegramMessageWithLocalAttachments(state, chatId, content, options = {}, localAttachmentPaths = []) {
1087
+ const sanitized = stripInternalControlBlocks(content);
1088
+ const explicitAttachments = await collectLocalFileAttachments({
1089
+ paths: localAttachmentPaths,
1090
+ cwd: state.config.workspace,
1091
+ allowedRoots: [state.config.workspace, state.config.notes_dir],
1092
+ });
1093
+ const inlineImages = await collectLocalImageAttachments({
1094
+ text: sanitized,
1095
+ cwd: state.config.workspace,
1096
+ allowedRoots: [state.config.workspace, state.config.notes_dir],
1097
+ });
1098
+ const attachments = dedupeLocalAttachments([...explicitAttachments, ...inlineImages]);
1099
+ if (sanitized.trim()) {
1100
+ await sendTelegramMessage(state, chatId, sanitized, options);
1101
+ }
1102
+ for (let index = 0; index < attachments.length; index += 1) {
1103
+ await sendTelegramFileAttachment(state, chatId, attachments[index], index === 0 && !sanitized.trim() ? options : { threadId: options.threadId });
1104
+ }
1105
+ }
1106
+ async function sendTelegramFileAttachment(state, chatId, attachment, options = {}) {
1107
+ const method = shouldSendTelegramAsPhoto(attachment) ? "sendPhoto" : "sendDocument";
1108
+ const fileField = method === "sendPhoto" ? "photo" : "document";
1109
+ const payload = telegramFilePayload(chatId, options);
1110
+ try {
1111
+ const buffer = await readFile(attachment.path);
1112
+ await telegramMultipartApi(state, method, payload, fileField, attachment.filename, attachment.mimeType, buffer);
1113
+ }
1114
+ catch (error) {
1115
+ const message = error instanceof Error ? error.message : String(error);
1116
+ console.error(`agent-sin telegram: file send error: ${message}`);
1117
+ await appendEventLog(state.config, {
1118
+ level: "error",
1119
+ source: "telegram",
1120
+ event: "file_send_error",
1121
+ message,
1122
+ details: { chat_id: chatId, path: attachment.path },
1123
+ });
1124
+ }
1125
+ }
1126
+ function shouldSendTelegramAsPhoto(attachment) {
1127
+ return attachment.isImage && ["image/png", "image/jpeg", "image/webp"].includes(attachment.mimeType.toLowerCase());
1128
+ }
1129
+ function dedupeLocalAttachments(attachments) {
1130
+ const seen = new Set();
1131
+ const out = [];
1132
+ for (const attachment of attachments) {
1133
+ if (seen.has(attachment.path))
1134
+ continue;
1135
+ seen.add(attachment.path);
1136
+ out.push(attachment);
1137
+ }
1138
+ return out;
1139
+ }
1091
1140
  async function sendTelegramChatAction(state, chatId, threadId) {
1092
1141
  try {
1093
1142
  const payload = {
@@ -1103,6 +1152,21 @@ async function sendTelegramChatAction(state, chatId, threadId) {
1103
1152
  // typing indicator is a hint; ignore failures
1104
1153
  }
1105
1154
  }
1155
+ function telegramFilePayload(chatId, options = {}) {
1156
+ const payload = {
1157
+ chat_id: chatId,
1158
+ };
1159
+ if (options.threadId) {
1160
+ payload.message_thread_id = options.threadId;
1161
+ }
1162
+ if (options.replyToMessageId && process.env.AGENT_SIN_TELEGRAM_REPLY_TO_MESSAGE !== "0") {
1163
+ payload.reply_parameters = {
1164
+ message_id: options.replyToMessageId,
1165
+ allow_sending_without_reply: true,
1166
+ };
1167
+ }
1168
+ return payload;
1169
+ }
1106
1170
  async function telegramApi(state, method, payload) {
1107
1171
  const response = await fetch(`${TELEGRAM_API_BASE}/bot${state.token}/${method}`, {
1108
1172
  method: "POST",
@@ -1119,6 +1183,33 @@ async function telegramApi(state, method, payload) {
1119
1183
  }
1120
1184
  return data.result;
1121
1185
  }
1186
+ async function telegramMultipartApi(state, method, payload, fileField, filename, mimeType, buffer) {
1187
+ const form = new FormData();
1188
+ for (const [key, value] of Object.entries(payload)) {
1189
+ if (value === undefined || value === null)
1190
+ continue;
1191
+ form.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
1192
+ }
1193
+ form.append(fileField, blobFromBuffer(buffer, mimeType), filename);
1194
+ const response = await fetch(`${TELEGRAM_API_BASE}/bot${state.token}/${method}`, {
1195
+ method: "POST",
1196
+ body: form,
1197
+ });
1198
+ if (!response.ok) {
1199
+ const detail = await response.text().catch(() => "");
1200
+ throw new Error(`HTTP ${response.status} ${detail.slice(0, 200)}`);
1201
+ }
1202
+ const data = (await response.json());
1203
+ if (!data.ok) {
1204
+ throw new Error(data.description || "Telegram API error");
1205
+ }
1206
+ return data.result;
1207
+ }
1208
+ function blobFromBuffer(buffer, type) {
1209
+ const bytes = new Uint8Array(buffer.length);
1210
+ bytes.set(buffer);
1211
+ return new Blob([bytes.buffer], { type });
1212
+ }
1122
1213
  async function loadTelegramOffset(filePath) {
1123
1214
  try {
1124
1215
  const raw = await readFile(filePath, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sin",
3
- "version": "0.1.11",
3
+ "version": "0.1.15",
4
4
  "description": "Program Skill-first personal AI agent OS CLI.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,12 +44,14 @@
44
44
  "release:check": "npm test && npm run pack:check"
45
45
  },
46
46
  "dependencies": {
47
+ "better-sqlite3": "^12.10.0",
47
48
  "nodemailer": "^8.0.7",
48
49
  "typescript": "^5.9.3",
49
50
  "ws": "^8.20.0",
50
51
  "yaml": "^2.7.0"
51
52
  },
52
53
  "devDependencies": {
54
+ "@types/better-sqlite3": "^7.6.13",
53
55
  "@types/node": "^22.10.0",
54
56
  "@types/nodemailer": "^8.0.0",
55
57
  "@types/ws": "^8.18.1"
@@ -0,0 +1,83 @@
1
+ # Agent-Sin Even G2 Template
2
+
3
+ This is a minimal Even Hub app for the Agent-Sin G2 gateway.
4
+
5
+ > 👉 **End-to-end setup guide for using this on your own G2 glasses:**
6
+ > [English](../../docs/even-g2-setup.md) · [日本語](../../docs/even-g2-setup.ja.md)
7
+ > The Local Flow below is the minimal developer-facing reference.
8
+
9
+ ## Local Flow
10
+
11
+ 1. Start the gateway:
12
+
13
+ ```bash
14
+ agent-sin g2 setup --history-channel discord --discord-thread auto
15
+ agent-sin service restart
16
+ ```
17
+
18
+ Use `--history-channel telegram` or `--history-channel none` if you do not
19
+ want Discord history.
20
+
21
+ 2. Edit `app.json` to add your own gateway and dev-server origins to
22
+ `permissions[0].whitelist`. The committed file only lists `127.0.0.1` so
23
+ personal IPs and Tailscale hostnames never leak into git. Add what you need
24
+ locally, for example:
25
+
26
+ ```json
27
+ "whitelist": [
28
+ "http://127.0.0.1:8765",
29
+ "http://127.0.0.1:5173",
30
+ "http://192.168.1.23:5173",
31
+ "http://192.168.1.23:8765"
32
+ ]
33
+ ```
34
+
35
+ For Tailscale, keep the phone on Tailscale and use the private URL instead
36
+ of any public Funnel URL:
37
+
38
+ ```json
39
+ "whitelist": ["http://your-device.tailnet-name.ts.net:8765"]
40
+ ```
41
+
42
+ Do not commit your edited `app.json` with personal hosts. Revert it to the
43
+ `127.0.0.1`-only baseline before staging, or keep your edits in a working
44
+ copy you do not push.
45
+
46
+ 3. Install and run the app:
47
+
48
+ ```bash
49
+ npm install
50
+ npm run dev
51
+ ```
52
+
53
+ In another terminal:
54
+
55
+ ```bash
56
+ npm run qr:auto
57
+ ```
58
+
59
+ The QR URL includes the app URL, gateway URL, and token. The token is placed
60
+ in the URL hash so it is not sent to the Vite dev server.
61
+
62
+ Override detection when needed:
63
+
64
+ ```bash
65
+ npm run qr:auto -- --host 100.x.y.z
66
+ npm run qr:auto -- --app http://100.x.y.z:5173 --server http://100.x.y.z:8765
67
+ ```
68
+
69
+ 4. Open it from the glasses menu.
70
+
71
+ ## Controls
72
+
73
+ - `Talk`: start voice capture
74
+ - `Talk` again: stop and send
75
+ - `Inbox`: show latest unread gateway notification
76
+ - `Exit`: close the glasses page
77
+
78
+ Voice transcription uses the gateway's `OPENAI_API_KEY` and defaults to
79
+ `gpt-4o-mini-transcribe`. Text and agent replies are mirrored to configured
80
+ Discord / Telegram notification targets only when `AGENT_SIN_G2_HISTORY_CHANNEL`
81
+ is set to `telegram`, `discord`, or `auto`. With
82
+ `AGENT_SIN_G2_DISCORD_THREAD=auto`, the gateway creates one public Discord
83
+ thread in the configured Discord channel and keeps G2 history there.
@@ -0,0 +1,20 @@
1
+ {
2
+ "package_id": "com.example.agentsin",
3
+ "edition": "202601",
4
+ "name": "Agent-Sin",
5
+ "version": "0.1.0",
6
+ "min_app_version": "2.0.0",
7
+ "min_sdk_version": "0.0.10",
8
+ "entrypoint": "index.html",
9
+ "permissions": [
10
+ {
11
+ "name": "network",
12
+ "desc": "Connects to the user's Agent-Sin gateway for private agent messages.",
13
+ "whitelist": [
14
+ "http://127.0.0.1:8765",
15
+ "http://127.0.0.1:5173"
16
+ ]
17
+ }
18
+ ],
19
+ "supported_languages": ["ja", "en"]
20
+ }
@@ -0,0 +1,31 @@
1
+ <!doctype html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Agent-Sin</title>
7
+ </head>
8
+ <body>
9
+ <main id="app">
10
+ <h1>Agent-Sin</h1>
11
+ <form id="settings">
12
+ <label>
13
+ Server URL
14
+ <input id="serverUrl" placeholder="http://192.168.1.10:8765" />
15
+ </label>
16
+ <label>
17
+ Token
18
+ <input id="token" placeholder="AGENT_SIN_G2_TOKEN" />
19
+ </label>
20
+ <button type="submit">Save</button>
21
+ </form>
22
+ <p id="status">Loading...</p>
23
+ <form id="textForm">
24
+ <input id="textInput" placeholder="Test message" />
25
+ <button type="submit">Send</button>
26
+ </form>
27
+ <pre id="log"></pre>
28
+ </main>
29
+ <script type="module" src="/src/main.ts"></script>
30
+ </body>
31
+ </html>