@0xmaxma/claude-gateway 1.3.16 → 1.3.17

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 (60) hide show
  1. package/config.template.json +8 -4
  2. package/dist/agent/builtin-commands.d.ts +1 -1
  3. package/dist/agent/builtin-commands.d.ts.map +1 -1
  4. package/dist/agent/builtin-commands.js +5 -0
  5. package/dist/agent/builtin-commands.js.map +1 -1
  6. package/dist/agent/line-pure.d.ts +31 -0
  7. package/dist/agent/line-pure.d.ts.map +1 -0
  8. package/dist/agent/line-pure.js +99 -0
  9. package/dist/agent/line-pure.js.map +1 -0
  10. package/dist/agent/line-reply-manager.d.ts +68 -0
  11. package/dist/agent/line-reply-manager.d.ts.map +1 -0
  12. package/dist/agent/line-reply-manager.js +383 -0
  13. package/dist/agent/line-reply-manager.js.map +1 -0
  14. package/dist/agent/runner.d.ts +11 -2
  15. package/dist/agent/runner.d.ts.map +1 -1
  16. package/dist/agent/runner.js +106 -8
  17. package/dist/agent/runner.js.map +1 -1
  18. package/dist/api/gateway-router.d.ts.map +1 -1
  19. package/dist/api/gateway-router.js +4 -0
  20. package/dist/api/gateway-router.js.map +1 -1
  21. package/dist/api/line-access.d.ts +60 -0
  22. package/dist/api/line-access.d.ts.map +1 -0
  23. package/dist/api/line-access.js +69 -0
  24. package/dist/api/line-access.js.map +1 -0
  25. package/dist/api/line-mention.d.ts +35 -0
  26. package/dist/api/line-mention.d.ts.map +1 -0
  27. package/dist/api/line-mention.js +33 -0
  28. package/dist/api/line-mention.js.map +1 -0
  29. package/dist/api/line-pending-senders.d.ts +40 -0
  30. package/dist/api/line-pending-senders.d.ts.map +1 -0
  31. package/dist/api/line-pending-senders.js +107 -0
  32. package/dist/api/line-pending-senders.js.map +1 -0
  33. package/dist/api/line-webhook-router.d.ts +51 -0
  34. package/dist/api/line-webhook-router.d.ts.map +1 -0
  35. package/dist/api/line-webhook-router.js +416 -0
  36. package/dist/api/line-webhook-router.js.map +1 -0
  37. package/dist/api/router.d.ts.map +1 -1
  38. package/dist/api/router.js +244 -7
  39. package/dist/api/router.js.map +1 -1
  40. package/dist/history/types.d.ts +1 -1
  41. package/dist/history/types.d.ts.map +1 -1
  42. package/dist/session/compactor.d.ts +1 -1
  43. package/dist/session/compactor.d.ts.map +1 -1
  44. package/dist/session/compactor.js.map +1 -1
  45. package/dist/session/process.d.ts +2 -2
  46. package/dist/session/process.d.ts.map +1 -1
  47. package/dist/session/process.js +14 -3
  48. package/dist/session/process.js.map +1 -1
  49. package/dist/session/store.d.ts +13 -13
  50. package/dist/session/store.d.ts.map +1 -1
  51. package/dist/session/store.js.map +1 -1
  52. package/dist/types.d.ts +60 -0
  53. package/dist/types.d.ts.map +1 -1
  54. package/mcp/bun.lock +9 -2
  55. package/mcp/package.json +1 -0
  56. package/mcp/server.ts +2 -0
  57. package/mcp/tools/line/module.ts +127 -0
  58. package/mcp/tools/line/pure.ts +62 -0
  59. package/mcp/tools/telegram/receiver-server.ts +8 -5
  60. package/package.json +2 -1
@@ -10,18 +10,18 @@
10
10
  "claude.dangerouslySkipPermissions"
11
11
  ]
12
12
  },
13
- "configVersion": "1.0.9",
13
+ "configVersion": "1.0.10",
14
14
  "gateway": {
15
15
  "logDir": "~/.claude-gateway/logs",
16
16
  "timezone": "Asia/Bangkok",
17
17
  "models": [
18
18
  { "id": "claude-fable-5", "label": "Fable 5", "alias": "fable", "contextWindow": 1000000 },
19
19
  { "id": "claude-opus-4-8[1m]", "label": "Opus 4.8 (1M)", "alias": "opus[1m]", "contextWindow": 1000000 },
20
- { "id": "claude-sonnet-4-6[1m]", "label": "Sonnet 4.6 (1M)", "alias": "sonnet[1m]", "contextWindow": 1000000 },
20
+ { "id": "claude-sonnet-5[1m]", "label": "Sonnet 5 (1M)", "alias": "sonnet[1m]", "contextWindow": 1000000 },
21
21
  { "id": "claude-opus-4-8", "label": "Opus 4.8", "alias": "opus", "contextWindow": 200000 },
22
- { "id": "claude-opus-4-7", "label": "Opus 4.7", "alias": "opus47", "contextWindow": 200000 },
23
22
  { "id": "claude-opus-4-6", "label": "Opus 4.6", "alias": "opus46", "contextWindow": 200000 },
24
- { "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "alias": "sonnet", "contextWindow": 200000 },
23
+ { "id": "claude-sonnet-5", "label": "Sonnet 5", "alias": "sonnet", "contextWindow": 200000 },
24
+ { "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "alias": "sonnet46", "contextWindow": 200000 },
25
25
  { "id": "claude-haiku-4-5-20251001", "label": "Haiku 4.5", "alias": "haiku", "contextWindow": 200000 }
26
26
  ],
27
27
  "api": {
@@ -78,6 +78,10 @@
78
78
  "telegram": {
79
79
  "botToken": "${BAERBEL_BOT_TOKEN}"
80
80
  },
81
+ "line": {
82
+ "channelAccessToken": "${BAERBEL_LINE_CHANNEL_ACCESS_TOKEN}",
83
+ "channelSecret": "${BAERBEL_LINE_CHANNEL_SECRET}"
84
+ },
81
85
  "claude": {
82
86
  "model": "claude-sonnet-4-6",
83
87
  "extraFlags": []
@@ -1,4 +1,4 @@
1
- export type CommandChannel = 'telegram' | 'discord' | 'api';
1
+ export type CommandChannel = 'telegram' | 'discord' | 'line' | 'api';
2
2
  interface CommandDef {
3
3
  channels: CommandChannel[];
4
4
  /** word-boundary check: true (default) = /^\/cmd\b/, false = /^\/cmd(\s|$)/ */
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-commands.d.ts","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,UAAU,UAAU;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAcvD,CAAC;AAsBF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAElF"}
1
+ {"version":3,"file":"builtin-commands.d.ts","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAErE,UAAU,UAAU;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAcvD,CAAC;AA0BF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAElF"}
@@ -22,6 +22,11 @@ function buildRegex(channel) {
22
22
  const parts = Object.entries(exports.BUILTIN_COMMANDS)
23
23
  .filter(([, def]) => def.channels.includes(channel))
24
24
  .map(([cmd, def]) => def.wordBoundary === false ? `^\/${cmd}(\\s|$)` : `^\/${cmd}\\b`);
25
+ // No commands registered for this channel (e.g. 'line') → match nothing.
26
+ // `new RegExp('')` matches EVERY string, which would misroute all messages
27
+ // into the command handler so they'd never reach the agent.
28
+ if (parts.length === 0)
29
+ return /(?!)/;
25
30
  return new RegExp(parts.join('|'));
26
31
  }
27
32
  function getRegex(channel) {
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AA4CA,4CAEC;AAtCY,QAAA,gBAAgB,GAA+B;IAC1D,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,GAAG,EAAO,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACpE,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACzD,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;CACrC,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEjD,SAAS,UAAU,CAAC,OAAuB;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAgB,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAClB,GAAG,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CACjE,CAAC;IACJ,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,OAAuB;IACvC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAe,EAAE,OAAuB;IACvE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AAgDA,4CAEC;AA1CY,QAAA,gBAAgB,GAA+B;IAC1D,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,GAAG,EAAO,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACpE,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACzD,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;CACrC,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEjD,SAAS,UAAU,CAAC,OAAuB;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAgB,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAClB,GAAG,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CACjE,CAAC;IACJ,yEAAyE;IACzE,2EAA2E;IAC3E,4DAA4D;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,OAAuB;IACvC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAe,EAAE,OAAuB;IACvE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pure, dependency-free LINE text helpers used by the gateway-side
3
+ * LineReplyManager (src/agent/line-reply-manager.ts).
4
+ *
5
+ * These mirror the chunking the MCP `line_reply` tool does in
6
+ * mcp/tools/line/pure.ts, but live under src/ because tsc's rootDir is ./src —
7
+ * src cannot import from mcp/. Ported from hermes-agent
8
+ * plugins/platforms/line/adapter.py (strip_markdown_preserving_urls /
9
+ * split_for_line, PR #18153).
10
+ */
11
+ /** LINE hard limit: max message objects per push/reply request. */
12
+ export declare const LINE_MAX_MESSAGES_PER_REQUEST = 5;
13
+ /** Conservative per-bubble char budget for chunking (below the 5000 hard limit). */
14
+ export declare const LINE_SAFE_BUBBLE_CHARS = 4500;
15
+ /**
16
+ * Strip Markdown that LINE can't render, but keep URLs tappable.
17
+ *
18
+ * LINE's text bubble has zero Markdown support; bare URLs auto-link but
19
+ * `[label](url)` does not. So convert links to `label (url)`, keep code-block
20
+ * and inline-code *content* (drop the fences/backticks), and strip bold/italic/
21
+ * heading/bullet markers. Port of hermes `strip_markdown_preserving_urls`.
22
+ */
23
+ export declare function stripMarkdownPreservingUrls(text: string): string;
24
+ /**
25
+ * Split text into LINE-sized bubbles, preferring paragraph/line/space breaks.
26
+ * Returns at most LINE_MAX_MESSAGES_PER_REQUEST chunks; overflow truncates the
27
+ * final chunk with an ellipsis (so the whole reply fits one Reply/Push call).
28
+ * Port of hermes `split_for_line`.
29
+ */
30
+ export declare function splitForLine(text: string, maxChars?: number): string[];
31
+ //# sourceMappingURL=line-pure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-pure.d.ts","sourceRoot":"","sources":["../../src/agent/line-pure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,mEAAmE;AACnE,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAW3C;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAyB,GAAG,MAAM,EAAE,CAiCtF"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ /**
3
+ * Pure, dependency-free LINE text helpers used by the gateway-side
4
+ * LineReplyManager (src/agent/line-reply-manager.ts).
5
+ *
6
+ * These mirror the chunking the MCP `line_reply` tool does in
7
+ * mcp/tools/line/pure.ts, but live under src/ because tsc's rootDir is ./src —
8
+ * src cannot import from mcp/. Ported from hermes-agent
9
+ * plugins/platforms/line/adapter.py (strip_markdown_preserving_urls /
10
+ * split_for_line, PR #18153).
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.LINE_SAFE_BUBBLE_CHARS = exports.LINE_MAX_MESSAGES_PER_REQUEST = void 0;
14
+ exports.stripMarkdownPreservingUrls = stripMarkdownPreservingUrls;
15
+ exports.splitForLine = splitForLine;
16
+ /** LINE hard limit: max message objects per push/reply request. */
17
+ exports.LINE_MAX_MESSAGES_PER_REQUEST = 5;
18
+ /** Conservative per-bubble char budget for chunking (below the 5000 hard limit). */
19
+ exports.LINE_SAFE_BUBBLE_CHARS = 4500;
20
+ // Markdown patterns LINE's text bubble can't render.
21
+ const MD_LINK_RE = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g;
22
+ const MD_BOLD_RE = /\*\*([\s\S]+?)\*\*/g;
23
+ const MD_ITALIC_RE = /(?<!\*)\*(?!\s)([\s\S]+?)(?<!\s)\*(?!\*)/g;
24
+ const MD_CODE_INLINE_RE = /`([^`]+)`/g;
25
+ const MD_CODE_BLOCK_RE = /```[a-zA-Z0-9_+-]*\n?([\s\S]*?)```/g;
26
+ const MD_HEADING_RE = /^#{1,6}\s+/gm;
27
+ const MD_BULLET_RE = /^[ \t]*[-*+]\s+/gm;
28
+ /**
29
+ * Strip Markdown that LINE can't render, but keep URLs tappable.
30
+ *
31
+ * LINE's text bubble has zero Markdown support; bare URLs auto-link but
32
+ * `[label](url)` does not. So convert links to `label (url)`, keep code-block
33
+ * and inline-code *content* (drop the fences/backticks), and strip bold/italic/
34
+ * heading/bullet markers. Port of hermes `strip_markdown_preserving_urls`.
35
+ */
36
+ function stripMarkdownPreservingUrls(text) {
37
+ if (!text)
38
+ return text;
39
+ let t = text;
40
+ // Code blocks first — keep inner content, drop the fences.
41
+ t = t.replace(MD_CODE_BLOCK_RE, (_m, inner) => inner.replace(/\n+$/, ''));
42
+ // Inline code: keep content, drop backticks.
43
+ t = t.replace(MD_CODE_INLINE_RE, '$1');
44
+ // Markdown links → "label (url)".
45
+ t = t.replace(MD_LINK_RE, (_m, label, url) => `${label} (${url})`);
46
+ // Bold/italic markers — strip.
47
+ t = t.replace(MD_BOLD_RE, '$1');
48
+ t = t.replace(MD_ITALIC_RE, '$1');
49
+ // Headings + bullet markers — strip the prefix only.
50
+ t = t.replace(MD_HEADING_RE, '');
51
+ t = t.replace(MD_BULLET_RE, '• ');
52
+ return t;
53
+ }
54
+ /**
55
+ * Split text into LINE-sized bubbles, preferring paragraph/line/space breaks.
56
+ * Returns at most LINE_MAX_MESSAGES_PER_REQUEST chunks; overflow truncates the
57
+ * final chunk with an ellipsis (so the whole reply fits one Reply/Push call).
58
+ * Port of hermes `split_for_line`.
59
+ */
60
+ function splitForLine(text, maxChars = exports.LINE_SAFE_BUBBLE_CHARS) {
61
+ if (!text)
62
+ return [];
63
+ if (text.length <= maxChars)
64
+ return [text];
65
+ const chunks = [];
66
+ let remaining = text;
67
+ const half = Math.floor(maxChars * 0.5);
68
+ while (remaining && chunks.length < exports.LINE_MAX_MESSAGES_PER_REQUEST) {
69
+ if (remaining.length <= maxChars) {
70
+ chunks.push(remaining);
71
+ remaining = '';
72
+ break;
73
+ }
74
+ // Break on the latest paragraph, then newline, then space within budget.
75
+ let cut = remaining.lastIndexOf('\n\n', maxChars);
76
+ if (cut < half)
77
+ cut = remaining.lastIndexOf('\n', maxChars);
78
+ if (cut < half)
79
+ cut = remaining.lastIndexOf(' ', maxChars);
80
+ if (cut <= 0)
81
+ cut = maxChars;
82
+ chunks.push(remaining.slice(0, cut).replace(/\s+$/, ''));
83
+ remaining = remaining.slice(cut).replace(/^\s+/, '');
84
+ }
85
+ if (remaining) {
86
+ // Truncate gracefully — the 5-bubble budget is spent.
87
+ if (chunks.length > 0) {
88
+ let tail = chunks[chunks.length - 1];
89
+ if (tail.length > maxChars - 1)
90
+ tail = tail.slice(0, maxChars - 1);
91
+ chunks[chunks.length - 1] = tail.replace(/\s+$/, '') + '…';
92
+ }
93
+ else {
94
+ chunks.push(remaining.slice(0, maxChars - 1) + '…');
95
+ }
96
+ }
97
+ return chunks;
98
+ }
99
+ //# sourceMappingURL=line-pure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-pure.js","sourceRoot":"","sources":["../../src/agent/line-pure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ export interface LineReplyManagerOptions {
2
+ agentId: string;
3
+ logDir: string;
4
+ accessToken: string;
5
+ /** Seconds before the button fires. Caller guarantees > 0. */
6
+ thresholdSeconds: number;
7
+ buttonLabel?: string;
8
+ pendingText?: string;
9
+ }
10
+ export declare class LineReplyManager {
11
+ private readonly client;
12
+ private readonly logger;
13
+ private readonly thresholdMs;
14
+ private readonly buttonLabel;
15
+ private readonly pendingText;
16
+ private readonly deliveredText;
17
+ private readonly interruptedText;
18
+ private readonly cache;
19
+ private ridSeq;
20
+ private readonly replyTokens;
21
+ private readonly pendingButtons;
22
+ private readonly timers;
23
+ private readonly turns;
24
+ private readonly answeredTurn;
25
+ private readonly pruneTimer;
26
+ constructor(opts: LineReplyManagerOptions);
27
+ /**
28
+ * A user message arrived: stash its reply token and (by default) arm the
29
+ * slow-button timer.
30
+ *
31
+ * `opts.armButton === false` stashes the token + bumps the turn counter but
32
+ * does NOT arm the button — used for group/room turns, where the shared-tap
33
+ * button is disabled but the answer must still be delivered. Crucially the
34
+ * reply token is still stashed so `onAnswer` can reply→push (the subprocess
35
+ * suppresses its own LINE send under LINE_REPLY_REFRESH, so the gateway is the
36
+ * only thing that delivers; skipping the stash would silently drop the answer).
37
+ */
38
+ onInbound(chatId: string, replyToken: string, opts?: {
39
+ armButton?: boolean;
40
+ }): void;
41
+ private fireButton;
42
+ /** The agent produced its reply text for this turn. */
43
+ onAnswer(chatId: string, text: string): Promise<void>;
44
+ private sendChunks;
45
+ /**
46
+ * Handle a tapped postback. Returns true when it is OUR refresh button (so the
47
+ * caller must NOT forward it to the agent); false for any other postback.
48
+ */
49
+ handlePostback(chatId: string, freshToken: string, data: string): Promise<boolean>;
50
+ /** The turn was interrupted/cancelled — surface an error for any pending button. */
51
+ markInterrupted(chatId: string): void;
52
+ disposeChat(chatId: string): void;
53
+ disposeAll(): void;
54
+ private clearTimer;
55
+ /** Clear the chat's pending-button guard only if it still points at `rid`
56
+ * (so delivering/tapping a superseded button can't clear a newer one). */
57
+ private clearPendingButton;
58
+ private consumeReplyToken;
59
+ private safeReply;
60
+ private textMessage;
61
+ private buildButtonMessage;
62
+ private registerPending;
63
+ private setReady;
64
+ private setError;
65
+ private markDelivered;
66
+ private prune;
67
+ }
68
+ //# sourceMappingURL=line-reply-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-reply-manager.d.ts","sourceRoot":"","sources":["../../src/agent/line-reply-manager.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAG5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,MAAM,CAAK;IAGnB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2D;IACvF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAE1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;gBAEhC,IAAI,EAAE,uBAAuB;IAazC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;YA2BrE,UAAU;IA4BxB,uDAAuD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAmB7C,UAAU;IAyBxB;;;OAGG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkDxF,oFAAoF;IACpF,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASrC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQjC,UAAU,IAAI,IAAI;IAOlB,OAAO,CAAC,UAAU;IAQlB;+EAC2E;IAC3E,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,iBAAiB;YAQX,SAAS;IAQvB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,KAAK;CAoBd"}