piclaw 0.0.4 → 0.0.6

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 (185) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/dist-D51xeTP2.js +12 -0
  3. package/.output/public/assets/index-B3x2_en6.css +1 -0
  4. package/.output/public/assets/index-SfjxJZSD.js +38 -0
  5. package/.output/public/assets/md4x-CNLJ57xO.wasm +0 -0
  6. package/.output/public/assets/md4x-CyfQToGJ.js +1 -0
  7. package/.output/public/assets/wasm-Cm7RZrwg.js +1 -0
  8. package/.output/public/icon.svg +25 -0
  9. package/.output/public/index.html +3 -2
  10. package/.output/public/manifest.json +1 -1
  11. package/.output/server/_chunks/bun.mjs +49 -0
  12. package/.output/server/_chunks/commands.mjs +280 -0
  13. package/.output/server/_chunks/config.mjs +2 -4
  14. package/.output/server/_chunks/db.mjs +11 -5
  15. package/.output/server/_chunks/logger.mjs +1 -1
  16. package/.output/server/_chunks/node.mjs +31 -0
  17. package/.output/server/_chunks/ntfy.mjs +45 -0
  18. package/.output/server/_chunks/pi.mjs +33 -1
  19. package/.output/server/_chunks/renderer-template.mjs +1 -1
  20. package/.output/server/_chunks/{bootstrap.mjs → server.mjs} +203 -205
  21. package/.output/server/_chunks/session.mjs +249 -40
  22. package/.output/server/_chunks/settings.mjs +1 -1
  23. package/.output/server/_chunks/terminal.mjs +35 -20
  24. package/.output/server/_chunks/virtual.mjs +129 -0
  25. package/.output/server/_jid_.delete.mjs +2 -2
  26. package/.output/server/_jid_.patch.mjs +30 -3
  27. package/.output/server/_jid_2.delete.mjs +2 -2
  28. package/.output/server/_libs/@aws-sdk/client-bedrock-runtime+[...].mjs +13148 -13149
  29. package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +1 -1
  30. package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +2 -2
  31. package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +1 -1
  32. package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +1 -1
  33. package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +1 -1
  34. package/.output/server/_libs/@google/genai.mjs +2 -2
  35. package/.output/server/_libs/@mariozechner/pi-agent-core+[...].mjs +40 -74
  36. package/.output/server/_libs/@mariozechner/pi-coding-agent+[...].mjs +1315 -1210
  37. package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +3 -3
  38. package/.output/server/_libs/_.mjs +3 -2
  39. package/.output/server/_libs/_100.mjs +3 -0
  40. package/.output/server/_libs/_101.mjs +2 -0
  41. package/.output/server/_libs/_102.mjs +3 -0
  42. package/.output/server/_libs/_103.mjs +2 -0
  43. package/.output/server/_libs/_16.mjs +2 -5
  44. package/.output/server/_libs/_17.mjs +2 -3
  45. package/.output/server/_libs/_18.mjs +2 -3
  46. package/.output/server/_libs/_19.mjs +2 -4
  47. package/.output/server/_libs/_2.mjs +2 -3
  48. package/.output/server/_libs/_20.mjs +2 -2
  49. package/.output/server/_libs/_21.mjs +2 -0
  50. package/.output/server/_libs/_22.mjs +2 -0
  51. package/.output/server/_libs/_23.mjs +2 -0
  52. package/.output/server/_libs/_24.mjs +2 -0
  53. package/.output/server/_libs/_25.mjs +2 -0
  54. package/.output/server/_libs/_26.mjs +2 -0
  55. package/.output/server/_libs/_27.mjs +2 -0
  56. package/.output/server/_libs/_28.mjs +2 -0
  57. package/.output/server/_libs/_29.mjs +2 -0
  58. package/.output/server/_libs/_30.mjs +2 -0
  59. package/.output/server/_libs/_31.mjs +2 -0
  60. package/.output/server/_libs/_32.mjs +2 -0
  61. package/.output/server/_libs/_33.mjs +2 -0
  62. package/.output/server/_libs/_34.mjs +2 -0
  63. package/.output/server/_libs/_35.mjs +2 -0
  64. package/.output/server/_libs/_36.mjs +2 -0
  65. package/.output/server/_libs/_37.mjs +2 -0
  66. package/.output/server/_libs/_38.mjs +2 -0
  67. package/.output/server/_libs/_39.mjs +2 -0
  68. package/.output/server/_libs/_40.mjs +2 -0
  69. package/.output/server/_libs/_41.mjs +2 -0
  70. package/.output/server/_libs/_42.mjs +2 -0
  71. package/.output/server/_libs/_43.mjs +2 -0
  72. package/.output/server/_libs/_44.mjs +2 -0
  73. package/.output/server/_libs/_45.mjs +2 -0
  74. package/.output/server/_libs/_46.mjs +2 -0
  75. package/.output/server/_libs/_47.mjs +2 -0
  76. package/.output/server/_libs/_48.mjs +2 -0
  77. package/.output/server/_libs/_49.mjs +2 -0
  78. package/.output/server/_libs/_50.mjs +2 -0
  79. package/.output/server/_libs/_51.mjs +2 -0
  80. package/.output/server/_libs/_52.mjs +2 -0
  81. package/.output/server/_libs/_53.mjs +2 -0
  82. package/.output/server/_libs/_54.mjs +2 -0
  83. package/.output/server/_libs/_55.mjs +2 -0
  84. package/.output/server/_libs/_56.mjs +2 -0
  85. package/.output/server/_libs/_57.mjs +2 -0
  86. package/.output/server/_libs/_58.mjs +2 -0
  87. package/.output/server/_libs/_59.mjs +2 -0
  88. package/.output/server/_libs/_60.mjs +2 -0
  89. package/.output/server/_libs/_61.mjs +2 -0
  90. package/.output/server/_libs/_62.mjs +2 -0
  91. package/.output/server/_libs/_63.mjs +2 -0
  92. package/.output/server/_libs/_64.mjs +2 -0
  93. package/.output/server/_libs/_65.mjs +2 -0
  94. package/.output/server/_libs/_66.mjs +2 -0
  95. package/.output/server/_libs/_67.mjs +2 -0
  96. package/.output/server/_libs/_68.mjs +2 -0
  97. package/.output/server/_libs/_69.mjs +2 -0
  98. package/.output/server/_libs/_70.mjs +2 -0
  99. package/.output/server/_libs/_71.mjs +2 -0
  100. package/.output/server/_libs/_72.mjs +2 -0
  101. package/.output/server/_libs/_73.mjs +2 -0
  102. package/.output/server/_libs/_74.mjs +2 -0
  103. package/.output/server/_libs/_75.mjs +2 -0
  104. package/.output/server/_libs/_76.mjs +2 -0
  105. package/.output/server/_libs/_77.mjs +2 -0
  106. package/.output/server/_libs/_78.mjs +2 -0
  107. package/.output/server/_libs/_79.mjs +2 -0
  108. package/.output/server/_libs/_80.mjs +2 -0
  109. package/.output/server/_libs/_81.mjs +2 -0
  110. package/.output/server/_libs/_82.mjs +2 -0
  111. package/.output/server/_libs/_83.mjs +2 -0
  112. package/.output/server/_libs/_84.mjs +2 -0
  113. package/.output/server/_libs/_85.mjs +2 -0
  114. package/.output/server/_libs/_86.mjs +2 -0
  115. package/.output/server/_libs/_87.mjs +2 -0
  116. package/.output/server/_libs/_88.mjs +2 -0
  117. package/.output/server/_libs/_89.mjs +2 -0
  118. package/.output/server/_libs/_90.mjs +2 -0
  119. package/.output/server/_libs/_91.mjs +2 -0
  120. package/.output/server/_libs/_92.mjs +2 -0
  121. package/.output/server/_libs/_93.mjs +2 -0
  122. package/.output/server/_libs/_94.mjs +2 -0
  123. package/.output/server/_libs/_95.mjs +2 -0
  124. package/.output/server/_libs/_96.mjs +2 -0
  125. package/.output/server/_libs/_97.mjs +2 -0
  126. package/.output/server/_libs/_98.mjs +2 -0
  127. package/.output/server/_libs/_99.mjs +5 -0
  128. package/.output/server/_libs/amdefine.mjs +188 -0
  129. package/.output/server/_libs/aws-sdk__nested-clients.mjs +1 -1
  130. package/.output/server/_libs/compressjs.mjs +50 -0
  131. package/.output/server/_libs/diff.mjs +137 -0
  132. package/.output/server/_libs/get-uri.mjs +1 -1
  133. package/.output/server/_libs/http-proxy-agent.mjs +1 -1
  134. package/.output/server/_libs/https-proxy-agent.mjs +1 -1
  135. package/.output/server/_libs/just-bash+[...].mjs +80359 -0
  136. package/.output/server/_libs/md4x.mjs +73 -0
  137. package/.output/server/_libs/mixmark-io__domino.mjs +14801 -0
  138. package/.output/server/_libs/node-fetch.mjs +1 -1
  139. package/.output/server/_libs/node-liblzma.mjs +1107 -0
  140. package/.output/server/_libs/pac-proxy-agent+[...].mjs +1 -1
  141. package/.output/server/_libs/proxy-agent+proxy-from-env.mjs +1 -1
  142. package/.output/server/_libs/smithy__core.mjs +1 -1
  143. package/.output/server/_routes/api/files/delete.mjs +2 -2
  144. package/.output/server/_routes/api/files/groups.mjs +14 -0
  145. package/.output/server/_routes/api/files/raw.mjs +1 -1
  146. package/.output/server/_routes/api/files/read.mjs +1 -1
  147. package/.output/server/_routes/api/files/watch.mjs +1 -1
  148. package/.output/server/_routes/api/files/write.mjs +3 -2
  149. package/.output/server/_routes/api/files.mjs +1 -1
  150. package/.output/server/_routes/api/groups.mjs +2 -2
  151. package/.output/server/_routes/api/groups2.mjs +3 -2
  152. package/.output/server/_routes/api/health.mjs +2 -2
  153. package/.output/server/_routes/api/logs.mjs +4 -2
  154. package/.output/server/_routes/api/ntfy/setup.mjs +54 -0
  155. package/.output/server/_routes/api/ntfy/status.mjs +12 -0
  156. package/.output/server/_routes/api/pi/apikey.mjs +1 -1
  157. package/.output/server/_routes/api/pi/apikey_providers.mjs +1 -1
  158. package/.output/server/_routes/api/pi/commands.mjs +6 -0
  159. package/.output/server/_routes/api/pi/login/events.mjs +1 -1
  160. package/.output/server/_routes/api/pi/login/respond.mjs +1 -1
  161. package/.output/server/_routes/api/pi/login.mjs +1 -1
  162. package/.output/server/_routes/api/pi/logout.mjs +1 -1
  163. package/.output/server/_routes/api/pi/models.mjs +1 -1
  164. package/.output/server/_routes/api/pi/status.mjs +1 -1
  165. package/.output/server/_routes/api/send.mjs +22 -3
  166. package/.output/server/_routes/api/status.mjs +9 -7
  167. package/.output/server/_routes/api/tasks2.mjs +2 -2
  168. package/.output/server/_routes/api/telegram/setup.mjs +2 -2
  169. package/.output/server/_routes/api/telegram/status.mjs +2 -2
  170. package/.output/server/_routes/api/terminal2.mjs +3 -2
  171. package/.output/server/_utils.mjs +12 -4
  172. package/.output/server/build/md4x.wasm +0 -0
  173. package/.output/server/index.mjs +223 -149
  174. package/.output/server/node_modules/@mongodb-js/zstd/lib/index.js +55 -0
  175. package/.output/server/node_modules/@mongodb-js/zstd/package.json +51 -0
  176. package/.output/server/package.json +1 -0
  177. package/README.md +118 -24
  178. package/bin/piclaw.mjs +39 -1
  179. package/package.json +16 -13
  180. package/.output/public/assets/client-TIs-Ghqj.js +0 -9
  181. package/.output/public/assets/dist-BVjfG3ok.js +0 -12
  182. package/.output/public/assets/dist-DJh8l6yS.js +0 -1
  183. package/.output/public/assets/index-BNNEMkNV.js +0 -39
  184. package/.output/public/assets/index-CdWBxO5V.css +0 -1
  185. package/.output/public/assets/react-DFP7nCmh.js +0 -1
@@ -1,160 +1,28 @@
1
1
  import { a as MAX_CONCURRENT_AGENTS, c as POLL_INTERVAL$1, f as TELEGRAM_BOT_TOKEN, i as MAIN_GROUP_FOLDER, l as SCHEDULER_POLL_INTERVAL, m as TRIGGER_PATTERN, n as ASSISTANT_NAME, p as TIMEZONE, r as GROUPS_DIR, u as SESSIONS_DIR } from "./config.mjs";
2
2
  import { t as createLogger } from "./logger.mjs";
3
3
  import { t as streamBus } from "./stream.mjs";
4
- import { i as resolveGroupModel, o as sessions, r as modelRegistry } from "./session.mjs";
4
+ import { C as setSession, D as updateTaskAfterRun, S as setRouterState, T as storeMessage, _ as removeRegisteredGroup, b as setConfig, d as getMessagesSince, f as getNewMessages, g as logTaskRun, h as initDatabase, i as deleteConfig, l as getConfig, m as getTaskById, o as getAllRegisteredGroups, p as getRouterState, r as deleteChat, s as getAllSessions, u as getDueTasks, v as removeSession, w as storeChatMetadata, x as setRegisteredGroup, y as removeTasksByChat } from "./db.mjs";
5
5
  import { n as pi_exports } from "./pi.mjs";
6
- import { C as setSession, D as updateTaskAfterRun, S as setRouterState, T as storeMessage, _ as removeRegisteredGroup, b as setConfig, d as getMessagesSince, f as getNewMessages, g as logTaskRun, h as initDatabase, i as deleteConfig, l as getConfig, m as getTaskById, o as getAllRegisteredGroups, p as getRouterState, r as deleteChat, s as getAllSessions, t as clearMessages, u as getDueTasks, v as removeSession, w as storeChatMetadata, x as setRegisteredGroup, y as removeTasksByChat } from "./db.mjs";
6
+ import { i as tryPriorityCommand, n as tryBashCommand, r as tryCommand, t as commandDescriptions } from "./commands.mjs";
7
+ import { a as renderToAnsi, i as parseAST, r as init } from "../_libs/md4x.mjs";
7
8
  import { t as terminalManager } from "./terminal.mjs";
8
9
  import crypto from "node:crypto";
9
10
  import fs from "node:fs";
10
11
  import path from "node:path";
11
12
  import path$1 from "path";
12
13
  import fs$1 from "fs";
13
- var commands = {
14
- help: handleHelp,
15
- info: handleInfo,
16
- new: handleNew,
17
- model: handleModel
18
- };
19
- /**
20
- * Try to handle a message as a `/command`. Returns true if handled.
21
- */
22
- function tryCommand(ctx, text) {
23
- if (!text.startsWith("/")) return false;
24
- const spaceIdx = text.indexOf(" ");
25
- const name = (spaceIdx > 0 ? text.slice(1, spaceIdx) : text.slice(1)).toLowerCase();
26
- const arg = spaceIdx > 0 ? text.slice(spaceIdx + 1).trim() : "";
27
- const handler = commands[name];
28
- if (handler) {
29
- handler(ctx, arg);
30
- return true;
31
- }
32
- ctx.server.sendBotMessage(ctx.chatJid, `Unknown command \`/${name}\`. Use /help for available commands.`);
33
- return true;
34
- }
35
- function handleHelp(ctx) {
36
- ctx.server.sendBotMessage(ctx.chatJid, [
37
- "Available commands:",
38
- " /info — Show session info (model, context, status)",
39
- " /new — Reset session and start a fresh conversation",
40
- " /model — List available models and show current",
41
- " /model <query> — Set model (fuzzy search)",
42
- " /model default — Reset to global default model",
43
- " /help — Show this help"
44
- ].join("\n"));
45
- }
46
- function handleInfo(ctx) {
47
- const resolved = resolveGroupModel(ctx.group);
48
- const modelLabel = resolved ? `${resolved.provider}/${resolved.id}` : "none";
49
- const modelSource = ctx.group.model ? `group (${ctx.group.model})` : "default";
50
- const managed = sessions.get(ctx.chatJid);
51
- const lines = [
52
- `Group: ${ctx.group.name} (${ctx.group.folder})`,
53
- `Model: ${modelLabel} [${modelSource}]`,
54
- `Trigger: ${ctx.group.requiresTrigger ? "required" : "not required"}`
55
- ];
56
- if (managed) {
57
- const s = managed.session;
58
- const actualModel = s.model;
59
- const actualLabel = actualModel ? `${actualModel.provider}/${actualModel.id}` : "none";
60
- const ctx$ = s.getContextUsage();
61
- lines.push("", `Session: ${s.sessionId}`, actualLabel !== modelLabel ? `Session model: ${actualLabel} (MISMATCH with resolved)` : `Session model: ${actualLabel}`, `Messages: ${s.messages.length}`, `Streaming: ${s.isStreaming ? "yes" : "no"}`, `Idle: ${formatDuration(Date.now() - managed.lastActivity)}`);
62
- if (ctx$?.tokens != null && ctx$.percent != null) {
63
- const pct = Math.round(ctx$.percent);
64
- lines.push(`Context: ${ctx$.tokens.toLocaleString()} / ${ctx$.contextWindow.toLocaleString()} tokens (${pct}%)`);
65
- }
66
- } else lines.push("", "No active session");
67
- ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
68
- }
69
- function formatDuration(ms) {
70
- const s = Math.floor(ms / 1e3);
71
- if (s < 60) return `${s}s`;
72
- const m = Math.floor(s / 60);
73
- if (m < 60) return `${m}m ${s % 60}s`;
74
- return `${Math.floor(m / 60)}h ${m % 60}m`;
75
- }
76
- function handleNew(ctx) {
77
- ctx.server.pi.kill(ctx.chatJid);
78
- removeSession(ctx.group.folder);
79
- clearMessages(ctx.chatJid);
80
- ctx.server.sendBotMessage(ctx.chatJid, "Session reset. Next message starts a fresh conversation.");
81
- }
82
- function handleModel(ctx, arg) {
83
- if (!arg) return listModels(ctx);
84
- if (arg === "default" || arg === "reset") return resetModel(ctx);
85
- return setModel(ctx, arg);
86
- }
87
- function listModels(ctx) {
88
- const available = modelRegistry.getAvailable();
89
- const resolved = resolveGroupModel(ctx.group);
90
- const lines = [
91
- `Current: ${ctx.group.model || "default (global)"} → ${resolved ? `${resolved.provider}/${resolved.id}` : "none"}`,
92
- "",
93
- "Available models:"
94
- ];
95
- const byProvider = /* @__PURE__ */ new Map();
96
- for (const m of available) {
97
- let list = byProvider.get(m.provider);
98
- if (!list) {
99
- list = [];
100
- byProvider.set(m.provider, list);
101
- }
102
- const marker = resolved && m.provider === resolved.provider && m.id === resolved.id ? " ←" : "";
103
- list.push(` ${m.provider}/${m.id}${marker}`);
104
- }
105
- for (const [provider, models] of byProvider) {
106
- lines.push(`[${provider}]`);
107
- lines.push(...models);
108
- }
109
- lines.push("", "Usage: /model <query> | /model default");
110
- ctx.server.sendBotMessage(ctx.chatJid, lines.join("\n"));
111
- }
112
- function resetModel(ctx) {
113
- const had = ctx.group.model;
114
- updateGroupModel(ctx, void 0);
115
- ctx.server.sendBotMessage(ctx.chatJid, had ? `Model reset to default (was: ${had}).` : "Already using default model.");
116
- }
117
- function setModel(ctx, query) {
118
- const match = findModel(query);
119
- if (!match) {
120
- ctx.server.sendBotMessage(ctx.chatJid, `No model matching "${query}". Use /model to list available models.`);
121
- return;
122
- }
123
- const modelStr = `${match.provider}/${match.id}`;
124
- updateGroupModel(ctx, modelStr);
125
- ctx.server.sendBotMessage(ctx.chatJid, `Model set to: ${modelStr}`);
126
- }
127
- function updateGroupModel(ctx, model) {
128
- const old = ctx.group.model;
129
- ctx.group.model = model;
130
- ctx.server.setRegisteredGroup(ctx.chatJid, ctx.group);
131
- if (old !== model) ctx.server.pi.kill(ctx.chatJid);
132
- }
133
- function findModel(query) {
134
- const available = modelRegistry.getAvailable();
135
- if (available.length === 0) return void 0;
136
- const q = query.toLowerCase();
137
- const exact = available.filter((m) => `${m.provider}/${m.id}`.toLowerCase() === q);
138
- if (exact.length === 1) return exact[0];
139
- const byId = available.filter((m) => m.id.toLowerCase() === q);
140
- if (byId.length === 1) return byId[0];
141
- const tokens = q.split(/[\s/]+/).filter(Boolean);
142
- const fuzzy = available.filter((m) => {
143
- const label = `${m.provider}/${m.id}`.toLowerCase();
144
- return tokens.every((t) => label.includes(t));
145
- });
146
- const matches = exact.length > 1 ? exact : byId.length > 1 ? byId : fuzzy;
147
- if (matches.length === 0) return void 0;
148
- matches.sort((a, b) => a.id.length - b.id.length || b.id.localeCompare(a.id, void 0, { numeric: true }));
149
- return matches[0];
150
- }
14
+ await init();
15
+ console.log(renderToAnsi("`md4x` initialized for Telegram channel!"));
151
16
  var logger$3 = createLogger("telegram");
152
17
  var JID_PREFIX = "tg:";
153
18
  var POLL_INTERVAL = 1e3;
154
19
  var POLL_TIMEOUT = 30;
155
20
  var API_BASE = "https://api.telegram.org/bot";
156
- var STREAM_THROTTLE = 1500;
157
- var STREAM_INITIAL_DELAY = 500;
21
+ var STREAM_THROTTLE_MIN = 700;
22
+ var STREAM_THROTTLE_MAX = 1500;
23
+ var STREAM_THROTTLE_STEP = 200;
24
+ var STREAM_THROTTLE_JITTER = 120;
25
+ var STREAM_INITIAL_DELAY = 100;
158
26
  var TG_MAX_TEXT = 4096;
159
27
  var TelegramChannel = class {
160
28
  name = "telegram";
@@ -178,6 +46,7 @@ var TelegramChannel = class {
178
46
  this.botId = me.id;
179
47
  this.botUsername = me.username || me.first_name;
180
48
  await this.api("deleteWebhook", { drop_pending_updates: false });
49
+ await this.api("setMyCommands", { commands: commandDescriptions });
181
50
  this.connected = true;
182
51
  this.startPolling();
183
52
  this.streamUnsub = streamBus.subscribeAll((e) => this.onStreamEvent(e));
@@ -189,6 +58,8 @@ var TelegramChannel = class {
189
58
  async sendMessage(jid, text) {
190
59
  const chatId = jid.slice(3);
191
60
  const state = this.streamState.get(jid);
61
+ const { text: formatted, parse_mode } = formatForTelegram(text);
62
+ const parseMode = { parse_mode };
192
63
  if (state) {
193
64
  this.streamState.delete(jid);
194
65
  if (state.editTimer) clearTimeout(state.editTimer);
@@ -197,14 +68,16 @@ var TelegramChannel = class {
197
68
  await this.api("editMessageText", {
198
69
  chat_id: chatId,
199
70
  message_id: state.messageId,
200
- text: text.slice(0, TG_MAX_TEXT)
71
+ text: formatted.slice(0, TG_MAX_TEXT),
72
+ ...parseMode
201
73
  });
202
74
  return;
203
75
  } catch {}
204
76
  }
205
77
  await this.api("sendMessage", {
206
78
  chat_id: chatId,
207
- text
79
+ text: formatted,
80
+ ...parseMode
208
81
  });
209
82
  }
210
83
  isConnected() {
@@ -237,19 +110,14 @@ var TelegramChannel = class {
237
110
  if (!this.ownsJid(event.chatJid)) return;
238
111
  const jid = event.chatJid;
239
112
  switch (event.type) {
113
+ case "thinking_delta": {
114
+ const state = this.getOrCreateStreamState(jid);
115
+ state.thinkingText += event.delta || "";
116
+ this.scheduleStreamEdit(jid, state);
117
+ break;
118
+ }
240
119
  case "text_delta": {
241
- let state = this.streamState.get(jid);
242
- if (!state) {
243
- state = {
244
- chatId: jid.slice(3),
245
- text: "",
246
- messageId: null,
247
- sendPromise: null,
248
- lastEdit: 0,
249
- editTimer: null
250
- };
251
- this.streamState.set(jid, state);
252
- }
120
+ const state = this.getOrCreateStreamState(jid);
253
121
  state.text += event.delta || "";
254
122
  this.scheduleStreamEdit(jid, state);
255
123
  break;
@@ -265,40 +133,70 @@ var TelegramChannel = class {
265
133
  }
266
134
  }
267
135
  }
136
+ getOrCreateStreamState(jid) {
137
+ let state = this.streamState.get(jid);
138
+ if (!state) {
139
+ state = {
140
+ chatId: jid.slice(3),
141
+ text: "",
142
+ thinkingText: "",
143
+ messageId: null,
144
+ sendPromise: null,
145
+ lastEdit: 0,
146
+ editTimer: null,
147
+ throttleMs: STREAM_THROTTLE_MIN
148
+ };
149
+ this.streamState.set(jid, state);
150
+ }
151
+ return state;
152
+ }
268
153
  scheduleStreamEdit(jid, state) {
269
154
  if (state.editTimer) return;
270
155
  const elapsed = Date.now() - state.lastEdit;
271
- const delay = state.messageId === null ? STREAM_INITIAL_DELAY : Math.max(0, STREAM_THROTTLE - elapsed);
156
+ const jitter = randomJitter(STREAM_THROTTLE_JITTER);
157
+ const delay = state.messageId === null ? STREAM_INITIAL_DELAY : Math.max(0, state.throttleMs + jitter - elapsed);
272
158
  state.editTimer = setTimeout(() => {
273
159
  state.editTimer = null;
274
160
  this.flushStreamEdit(jid, state);
275
161
  }, delay);
276
162
  }
277
- async flushStreamEdit(_jid, state) {
278
- const display = stripStreamingInternal(state.text);
163
+ async flushStreamEdit(jid, state) {
164
+ if (state.sendPromise) {
165
+ await state.sendPromise.catch(() => {});
166
+ state.sendPromise = null;
167
+ }
168
+ const display = state.text.trim() || (state.thinkingText.trim() ? `💭 ${state.thinkingText.trim()}` : "");
279
169
  if (!display) return;
280
- const truncated = display.length > TG_MAX_TEXT ? display.slice(0, TG_MAX_TEXT - 1) + "…" : display;
170
+ const { text: formatted, parse_mode } = formatForTelegram(display.length > TG_MAX_TEXT ? display.slice(0, TG_MAX_TEXT - 1) + "…" : display);
171
+ const snapshotLen = display.length;
281
172
  try {
282
- if (state.messageId === null && !state.sendPromise) {
173
+ if (state.messageId === null) {
283
174
  state.sendPromise = this.api("sendMessage", {
284
175
  chat_id: state.chatId,
285
- text: truncated
176
+ text: formatted,
177
+ parse_mode
286
178
  }).then((msg) => {
287
179
  state.messageId = msg.message_id;
288
- state.lastEdit = Date.now();
180
+ state.sendPromise = null;
289
181
  });
290
182
  await state.sendPromise;
291
- } else if (state.messageId !== null) {
292
- await this.api("editMessageText", {
293
- chat_id: state.chatId,
294
- message_id: state.messageId,
295
- text: truncated
296
- });
297
- state.lastEdit = Date.now();
298
- }
183
+ } else await this.api("editMessageText", {
184
+ chat_id: state.chatId,
185
+ message_id: state.messageId,
186
+ text: formatted,
187
+ parse_mode
188
+ });
189
+ state.lastEdit = Date.now();
190
+ state.throttleMs = Math.max(STREAM_THROTTLE_MIN, state.throttleMs - 50);
299
191
  } catch (err) {
300
- logger$3.debug({ err }, "Stream edit failed");
192
+ const retryAfterMs = getRetryAfterMs(err);
193
+ if (retryAfterMs > 0) state.throttleMs = Math.min(STREAM_THROTTLE_MAX, Math.max(state.throttleMs + STREAM_THROTTLE_STEP, retryAfterMs));
194
+ logger$3.debug({
195
+ err,
196
+ throttleMs: state.throttleMs
197
+ }, "Stream edit failed");
301
198
  }
199
+ if ((state.text.trim() || (state.thinkingText.trim() ? `💭 ${state.thinkingText.trim()}` : "")).length > snapshotLen && this.streamState.has(jid)) this.scheduleStreamEdit(jid, state);
302
200
  }
303
201
  startPolling() {
304
202
  this.stopPolling();
@@ -352,12 +250,13 @@ var TelegramChannel = class {
352
250
  this.pollAbort = null;
353
251
  }
354
252
  async api(method, body) {
355
- const data = await (await fetch(`${API_BASE}${this.config.botToken}/${method}`, {
253
+ const res = await fetch(`${API_BASE}${this.config.botToken}/${method}`, {
356
254
  method: "POST",
357
255
  headers: { "content-type": "application/json" },
358
256
  body: body ? JSON.stringify(body) : void 0
359
- })).json();
360
- if (!data.ok) throw new Error(`Telegram API ${method} failed: ${data.description || "unknown error"}`);
257
+ });
258
+ const data = await res.json();
259
+ if (!data.ok) throw new TelegramApiError(method, data.description || "unknown error", res.status, data);
361
260
  return data.result;
362
261
  }
363
262
  handleUpdate(update) {
@@ -383,12 +282,101 @@ var TelegramChannel = class {
383
282
  this.opts.onChatMetadata(jid, now, senderName, "telegram", isGroup);
384
283
  }
385
284
  };
386
- /** Strip <internal> tags, including incomplete ones mid-stream */
387
- function stripStreamingInternal(text) {
388
- let result = text.replace(/<internal>[\s\S]*?<\/internal>/g, "");
389
- const idx = result.lastIndexOf("<internal>");
390
- if (idx !== -1 && result.indexOf("</internal>", idx) === -1) result = result.slice(0, idx);
391
- return result.trim();
285
+ var TelegramApiError = class extends Error {
286
+ constructor(method, message, status, response) {
287
+ super(`Telegram API ${method} failed: ${message}`);
288
+ this.method = method;
289
+ this.status = status;
290
+ this.response = response;
291
+ }
292
+ };
293
+ /** Format message text as Telegram MarkdownV2 — parse with md4x, render AST to TG format */
294
+ function formatForTelegram(text) {
295
+ let remaining = text.replace(/<\/?internal>/g, (t) => t.replace("internal", "thinking"));
296
+ const parts = [];
297
+ const thinkingRe = /<thinking>([\s\S]*?)<\/thinking>/g;
298
+ let lastIdx = 0;
299
+ let m;
300
+ while ((m = thinkingRe.exec(remaining)) !== null) {
301
+ if (m.index > lastIdx) parts.push(mdToTgV2(remaining.slice(lastIdx, m.index)));
302
+ const trimmed = (m[1] || "").trim();
303
+ if (trimmed) {
304
+ const quoted = escTgV2(trimmed).split("\n").map((l) => `>${l}`).join("\n");
305
+ parts.push(quoted);
306
+ }
307
+ lastIdx = m.index + m[0].length;
308
+ }
309
+ if (lastIdx < remaining.length) parts.push(mdToTgV2(remaining.slice(lastIdx)));
310
+ return {
311
+ text: parts.join("").replace(/\n{3,}/g, "\n\n").trim(),
312
+ parse_mode: "MarkdownV2"
313
+ };
314
+ }
315
+ /** Parse markdown with md4x and render AST nodes to Telegram MarkdownV2 */
316
+ function mdToTgV2(text) {
317
+ return parseAST(text).nodes.map((node) => renderNode(node, true)).join("\n\n");
318
+ }
319
+ /** Collect raw text from children (for code content that must not be escaped) */
320
+ function collectText(children) {
321
+ return children.map((c) => typeof c === "string" ? c : "").join("");
322
+ }
323
+ /** Render a single AST node to Telegram MarkdownV2 */
324
+ function renderNode(node, topLevel = false) {
325
+ if (typeof node === "string") return escTgV2(node);
326
+ const [tag, attrs, ...children] = node;
327
+ const inner = () => children.map((c) => renderNode(c)).join("");
328
+ switch (tag) {
329
+ case "p": return inner();
330
+ case "h1":
331
+ case "h2":
332
+ case "h3":
333
+ case "h4":
334
+ case "h5":
335
+ case "h6": return `*${inner()}*`;
336
+ case "strong": return `*${inner()}*`;
337
+ case "em": return `_${inner()}_`;
338
+ case "u": return `__${inner()}__`;
339
+ case "del": return `~${inner()}~`;
340
+ case "code":
341
+ if (!topLevel) return collectText(children);
342
+ return `\`${collectText(children)}\``;
343
+ case "pre": {
344
+ const codeNode = children.find((c) => typeof c !== "string" && c[0] === "code");
345
+ return `\`\`\`${String(attrs.language || "")}\n${(codeNode ? collectText(codeNode.slice(2)) : inner()).replace(/\n$/, "")}\n\`\`\``;
346
+ }
347
+ case "a": {
348
+ const href = String(attrs.href || "");
349
+ return `[${inner()}](${escTgUrl(href)})`;
350
+ }
351
+ case "img": return escTgV2(String(attrs.alt || "image"));
352
+ case "blockquote": return inner().split("\n").map((l) => `>${l}`).join("\n");
353
+ case "ul":
354
+ case "ol": return children.map((c, i) => {
355
+ if (typeof c === "string") return escTgV2(c);
356
+ return (tag === "ol" ? `${escTgV2(`${i + 1}.`)} ` : `${escTgV2("•")} `) + renderNode(c);
357
+ }).filter((l) => l.trim()).join("\n");
358
+ case "li": return inner();
359
+ case "hr": return escTgV2("---");
360
+ case "br": return "\n";
361
+ default: return inner();
362
+ }
363
+ }
364
+ /** Escape special characters for Telegram MarkdownV2 outside code spans */
365
+ function escTgV2(s) {
366
+ return s.replace(/([_*[\]()~`>#+=|{}.!\\-])/g, "\\$1");
367
+ }
368
+ /** Escape only ) and \ inside MarkdownV2 link URLs */
369
+ function escTgUrl(s) {
370
+ return s.replace(/([)\\])/g, "\\$1");
371
+ }
372
+ function getRetryAfterMs(err) {
373
+ if (!(err instanceof TelegramApiError)) return 0;
374
+ const retryAfterSec = Number(err.response?.parameters?.retry_after || 0);
375
+ if (!Number.isFinite(retryAfterSec) || retryAfterSec <= 0) return 0;
376
+ return retryAfterSec * 1e3;
377
+ }
378
+ function randomJitter(maxAbs) {
379
+ return Math.round((Math.random() * 2 - 1) * maxAbs);
392
380
  }
393
381
  function sleep(ms, signal) {
394
382
  return new Promise((resolve) => {
@@ -424,8 +412,6 @@ function ensureGlobalMemory() {
424
412
  function initGroupMemory(folder) {
425
413
  ensureGlobalMemory();
426
414
  ensureGroupMemory(folder);
427
- const logsDir = path$1.join(GROUPS_DIR, folder, "logs");
428
- fs$1.mkdirSync(logsDir, { recursive: true });
429
415
  }
430
416
  /** Initialize the main group */
431
417
  function initMainMemory() {
@@ -515,13 +501,9 @@ function escapeXml(s) {
515
501
  function formatMessages(messages) {
516
502
  return `<messages>\n${messages.map((m) => `<message sender="${escapeXml(m.sender_name)}" time="${m.timestamp}">${escapeXml(m.content)}</message>`).join("\n")}\n</messages>`;
517
503
  }
518
- /** Strip <internal>...</internal> blocks from agent output */
519
- function stripInternalTags(text) {
520
- return text.replace(/<internal>[\s\S]*?<\/internal>/g, "").trim();
521
- }
522
- /** Format outbound text (strip internal reasoning) */
504
+ /** Format outbound text */
523
505
  function formatOutbound(rawText) {
524
- return stripInternalTags(rawText);
506
+ return rawText.trim();
525
507
  }
526
508
  /** Check if messages need a trigger and whether any message matches */
527
509
  function needsProcessing(group, messages) {
@@ -689,8 +671,9 @@ var PiClawServer = class {
689
671
  if (text) this.sendBotMessage(jid, text);
690
672
  }
691
673
  });
692
- this.queue.setProcessMessagesFn((chatJid) => this.processGroupMessages(chatJid));
674
+ await this.pi.warmUp(this.registeredGroups, this.sessions, ASSISTANT_NAME);
693
675
  this.recoverPendingMessages();
676
+ this.queue.setProcessMessagesFn((chatJid) => this.processGroupMessages(chatJid));
694
677
  this.startMessageLoop();
695
678
  const elapsed = (performance.now() - startTime).toFixed(0);
696
679
  logger.info(`PiClaw server started in ${elapsed}ms`);
@@ -783,7 +766,7 @@ var PiClawServer = class {
783
766
  if (this.unregisteredNotified.has(jid)) return;
784
767
  this.unregisteredNotified.add(jid);
785
768
  setTimeout(() => this.unregisteredNotified.delete(jid), 3600 * 1e3);
786
- this.sendBotMessage(jid, `This chat is not registered. Ask an admin to approve it ("${jid}").`);
769
+ this.sendBotMessage(jid, `This chat is not registered. Ask an admin to approve it from chats window (${jid}).`);
787
770
  }
788
771
  /** For DM chats, auto-disable trigger requirement so every message is processed */
789
772
  autoSetTriggerForDM(jid, isGroup) {
@@ -864,11 +847,15 @@ var PiClawServer = class {
864
847
  const group = this.registeredGroups[chatJid];
865
848
  if (!group) return messages;
866
849
  const remaining = [];
867
- for (const msg of messages) if (!tryCommand({
868
- chatJid,
869
- group,
870
- server: this
871
- }, msg.content.trim())) remaining.push(msg);
850
+ for (const msg of messages) {
851
+ const text = msg.content.trim();
852
+ const ctx = {
853
+ chatJid,
854
+ group,
855
+ server: this
856
+ };
857
+ if (!(tryBashCommand(ctx, text) || tryCommand(ctx, text))) remaining.push(msg);
858
+ }
872
859
  return remaining;
873
860
  }
874
861
  async processGroupMessages(chatJid) {
@@ -885,9 +872,7 @@ var PiClawServer = class {
885
872
  }
886
873
  if (!needsProcessing(group, agentMessages)) return true;
887
874
  const prompt = formatMessages(agentMessages);
888
- const previousCursor = this.lastAgentTimestamp[chatJid] || "";
889
- this.lastAgentTimestamp[chatJid] = missedMessages[missedMessages.length - 1].timestamp;
890
- this.saveState();
875
+ const lastMessageTimestamp = missedMessages[missedMessages.length - 1].timestamp;
891
876
  logger.info({
892
877
  group: group.name,
893
878
  messageCount: missedMessages.length
@@ -919,6 +904,7 @@ var PiClawServer = class {
919
904
  });
920
905
  } catch (err) {
921
906
  hadError = true;
907
+ console.error(err);
922
908
  logger.error({
923
909
  group: group.name,
924
910
  err
@@ -926,11 +912,11 @@ var PiClawServer = class {
926
912
  }
927
913
  clearInterval(typingInterval);
928
914
  if (hadError && !outputSentToUser) {
929
- this.lastAgentTimestamp[chatJid] = previousCursor;
930
- this.saveState();
931
- logger.warn({ group: group.name }, "Agent error, rolled back cursor for retry");
915
+ logger.warn({ group: group.name }, "Agent error, cursor not advanced for retry");
932
916
  return false;
933
917
  }
918
+ this.lastAgentTimestamp[chatJid] = lastMessageTimestamp;
919
+ this.saveState();
934
920
  return true;
935
921
  }
936
922
  /** Send repeating typing indicator to the channel owning the JID */
@@ -959,7 +945,17 @@ var PiClawServer = class {
959
945
  }
960
946
  for (const [chatJid, groupMessages] of byGroup) {
961
947
  const group = this.registeredGroups[chatJid];
962
- if (!group || !needsProcessing(group, groupMessages)) continue;
948
+ if (!group) continue;
949
+ for (const msg of groupMessages) {
950
+ const ctx = {
951
+ chatJid,
952
+ group,
953
+ server: this
954
+ };
955
+ tryBashCommand(ctx, msg.content.trim());
956
+ tryPriorityCommand(ctx, msg.content.trim());
957
+ }
958
+ if (!needsProcessing(group, groupMessages)) continue;
963
959
  this.queue.enqueueMessageCheck(chatJid);
964
960
  }
965
961
  }
@@ -999,6 +995,7 @@ var PiClawServer = class {
999
995
  folder: MAIN_GROUP_FOLDER,
1000
996
  trigger: `@${ASSISTANT_NAME}`,
1001
997
  requiresTrigger: false,
998
+ thinkingLevel: "medium",
1002
999
  added_at: (/* @__PURE__ */ new Date()).toISOString()
1003
1000
  };
1004
1001
  this.setRegisteredGroup(defaultJid, group, {
@@ -1011,7 +1008,8 @@ var PiClawServer = class {
1011
1008
  /**
1012
1009
  * Shared PiClawServer singleton — imported by route handlers.
1013
1010
  */
1014
- const startTime = Date.now();
1011
+ const startTime = globalThis.__piclaw_start_time__ || performance.now();
1015
1012
  const server = new PiClawServer();
1016
1013
  await server.start();
1017
- export { startTime as n, server as t };
1014
+ var server_default = () => {};
1015
+ export { server_default as n, startTime as r, server as t };