appback-remoteagent 0.13.14 → 0.13.16

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/bot.js CHANGED
@@ -886,14 +886,6 @@ ${bridge.formatStatus(mapping)}`);
886
886
  if (!text) {
887
887
  return;
888
888
  }
889
- if (mapping) {
890
- const localStatus = await memoryService.formatLocalStatusQuestion(mapping.session, text);
891
- if (localStatus) {
892
- await bridge.logSystem(botId, chatId, "Answered local session status without provider execution.");
893
- await reply(ctx, localStatus);
894
- return;
895
- }
896
- }
897
889
  if (isRemoteShellMessage(text)) {
898
890
  const shellRequest = parseRemoteShellRequest(text);
899
891
  if (!shellRequest) {
@@ -1383,7 +1375,7 @@ function renderTelegramHtml(text) {
1383
1375
  for (const line of lines) {
1384
1376
  if (/^```\w*\s*$/.test(line.trim())) {
1385
1377
  if (codeFence) {
1386
- rendered.push(`<pre>${escapeTelegramHtml(codeFence.join("\n"))}</pre>`);
1378
+ rendered.push(renderTelegramCodeFenceHtml(codeFence.join("\n")));
1387
1379
  codeFence = undefined;
1388
1380
  }
1389
1381
  else {
@@ -1398,25 +1390,45 @@ function renderTelegramHtml(text) {
1398
1390
  rendered.push(renderTelegramInlineHtml(line));
1399
1391
  }
1400
1392
  if (codeFence) {
1401
- rendered.push(`<pre>${escapeTelegramHtml(codeFence.join("\n"))}</pre>`);
1393
+ rendered.push(renderTelegramCodeFenceHtml(codeFence.join("\n")));
1402
1394
  }
1403
1395
  return rendered.join("\n");
1404
1396
  }
1397
+ function renderTelegramCodeFenceHtml(content) {
1398
+ if (containsUrl(content)) {
1399
+ return content.split(/\r?\n/).map((line) => renderTelegramInlineHtml(line)).join("\n");
1400
+ }
1401
+ return `<pre>${escapeTelegramHtml(content)}</pre>`;
1402
+ }
1405
1403
  function renderTelegramInlineHtml(line) {
1406
1404
  const parts = line.split(/(`[^`\n]+`)/g);
1407
1405
  return parts.map((part) => {
1408
1406
  if (part.startsWith("`") && part.endsWith("`") && part.length >= 2) {
1409
1407
  return `<code>${escapeTelegramHtml(part.slice(1, -1))}</code>`;
1410
1408
  }
1411
- return escapeTelegramHtml(part);
1409
+ return renderTelegramTextLinks(part);
1412
1410
  }).join("");
1413
1411
  }
1412
+ function renderTelegramTextLinks(value) {
1413
+ return value.replace(/https?:\/\/[^\s<>"']+/g, (url) => {
1414
+ const trailingMatch = /[),.;!?]+$/.exec(url);
1415
+ const trailing = trailingMatch?.[0] ?? "";
1416
+ const cleanUrl = trailing ? url.slice(0, -trailing.length) : url;
1417
+ return `<a href="${escapeTelegramHtmlAttribute(cleanUrl)}">${escapeTelegramHtml(cleanUrl)}</a>${escapeTelegramHtml(trailing)}`;
1418
+ });
1419
+ }
1420
+ function containsUrl(value) {
1421
+ return /https?:\/\/[^\s<>"']+/.test(value);
1422
+ }
1414
1423
  function escapeTelegramHtml(value) {
1415
1424
  return value
1416
1425
  .replace(/&/g, "&amp;")
1417
1426
  .replace(/</g, "&lt;")
1418
1427
  .replace(/>/g, "&gt;");
1419
1428
  }
1429
+ function escapeTelegramHtmlAttribute(value) {
1430
+ return escapeTelegramHtml(value).replace(/"/g, "&quot;");
1431
+ }
1420
1432
  function looksLikeUntaggedIntentOnlyResponse(text) {
1421
1433
  const normalized = text.trim();
1422
1434
  if (!normalized) {
@@ -71,53 +71,6 @@ export class AgentMemoryService {
71
71
  history.length > 0 ? ["Recent history:", ...history.map((entry) => `- ${entry}`)].join("\n") : undefined,
72
72
  ].filter(Boolean).join("\n");
73
73
  }
74
- async formatLocalStatusQuestion(session, question) {
75
- if (!this.looksLikeLocalStatusQuestion(question)) {
76
- return undefined;
77
- }
78
- const current = await this.currentTaskText(session);
79
- const todo = await this.readTodo(session);
80
- const active = this.activeTodoItems(todo);
81
- const history = await this.readRecentHistory(session, 8);
82
- const workHistory = await this.readRecentWorkHistory(session, 6);
83
- const latestInstruction = this.extractLatestInstructionFromCurrent(current);
84
- const currentIsStatusOnly = latestInstruction ? this.looksLikeLocalStatusQuestion(latestInstruction) : false;
85
- const hasCurrentWork = Boolean(current.trim()) && !currentIsStatusOnly;
86
- const lines = [
87
- `Session ${session.publicId} local state`,
88
- "",
89
- `workspace: ${session.workspace}`,
90
- `memory: ${this.sessionDir(session)}`,
91
- "",
92
- ];
93
- if (!hasCurrentWork && active.length === 0 && workHistory.length === 0) {
94
- lines.push("현재 하네스 기준으로 진행 중이거나 완료된 작업 기록이 없습니다.", "이 세션은 깨끗한 상태로 보입니다.");
95
- }
96
- else {
97
- if (hasCurrentWork) {
98
- lines.push("Current note:", this.summarizeCurrentTask(current), "");
99
- }
100
- else {
101
- lines.push("Current note: none", "");
102
- }
103
- if (active.length > 0) {
104
- lines.push("Active TODO:", this.formatTodoSummary(todo, false), "");
105
- }
106
- else {
107
- lines.push("Active TODO: none", "");
108
- }
109
- if (workHistory.length > 0) {
110
- lines.push("Recent work history:", ...workHistory.map((entry) => `- ${entry}`));
111
- }
112
- else {
113
- lines.push("Recent work history: none");
114
- }
115
- }
116
- if (history.length > 0) {
117
- lines.push("", "Recent raw history:", ...history.map((entry) => `- ${entry}`));
118
- }
119
- return lines.join("\n");
120
- }
121
74
  async clearSessionState(session, summary) {
122
75
  const dir = this.sessionDir(session);
123
76
  const currentPath = path.join(dir, "current.md");
@@ -627,27 +580,6 @@ export class AgentMemoryService {
627
580
  const match = /## Latest User Instruction\s*\n([\s\S]*?)(?:\n## |\s*$)/.exec(current);
628
581
  return match?.[1]?.trim() || undefined;
629
582
  }
630
- looksLikeLocalStatusQuestion(text) {
631
- const normalized = text.trim();
632
- if (!normalized) {
633
- return false;
634
- }
635
- if (normalized.length > 80 || /[\r\n]/.test(normalized)) {
636
- return false;
637
- }
638
- if (/(진행|정리|구현|수정|제거|삭제|추가|작성|테스트|검증|커밋|푸시|배포|문서로|완료되면|필수|전담|담당|작업\s*폴더)/.test(normalized)) {
639
- return false;
640
- }
641
- return [
642
- /최근\s*(작업|진행|히스토리|기록)/,
643
- /현재\s*(작업|진행|상태|세션)/,
644
- /(뭐|무엇)\s*(하고|하는)\s*(있어|중|거야)?/,
645
- /작업\s*(상태|히스토리|기록|있어|없어)/,
646
- /세션\s*(상태|히스토리|기록)/,
647
- /진행\s*(상태|중인\s*작업)/,
648
- /\b(status|current work|recent work|what are you doing|session state)\b/i,
649
- ].some((pattern) => pattern.test(normalized));
650
- }
651
583
  formatTodoSummary(todo, includeDone = false, detailed = false) {
652
584
  const items = includeDone ? todo.items : todo.items.filter((item) => item.status !== "done");
653
585
  if (items.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appback-remoteagent",
3
- "version": "0.13.14",
3
+ "version": "0.13.16",
4
4
  "description": "Personal installable session server for continuing local AI work across PC and Telegram",
5
5
  "license": "MIT",
6
6
  "type": "module",