@suzuke/agend 0.0.1 → 1.0.2

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 (157) hide show
  1. package/README.md +78 -0
  2. package/README.zh-TW.md +79 -0
  3. package/dist/access-path.d.ts +7 -0
  4. package/dist/access-path.js +12 -0
  5. package/dist/access-path.js.map +1 -0
  6. package/dist/backend/claude-code.d.ts +13 -0
  7. package/dist/backend/claude-code.js +114 -0
  8. package/dist/backend/claude-code.js.map +1 -0
  9. package/dist/backend/codex.d.ts +10 -0
  10. package/dist/backend/codex.js +58 -0
  11. package/dist/backend/codex.js.map +1 -0
  12. package/dist/backend/factory.d.ts +2 -0
  13. package/dist/backend/factory.js +19 -0
  14. package/dist/backend/factory.js.map +1 -0
  15. package/dist/backend/gemini-cli.d.ts +10 -0
  16. package/dist/backend/gemini-cli.js +68 -0
  17. package/dist/backend/gemini-cli.js.map +1 -0
  18. package/dist/backend/index.d.ts +6 -0
  19. package/dist/backend/index.js +6 -0
  20. package/dist/backend/index.js.map +1 -0
  21. package/dist/backend/opencode.d.ts +10 -0
  22. package/dist/backend/opencode.js +63 -0
  23. package/dist/backend/opencode.js.map +1 -0
  24. package/dist/backend/types.d.ts +26 -0
  25. package/dist/backend/types.js +2 -0
  26. package/dist/backend/types.js.map +1 -0
  27. package/dist/channel/access-manager.d.ts +18 -0
  28. package/dist/channel/access-manager.js +149 -0
  29. package/dist/channel/access-manager.js.map +1 -0
  30. package/dist/channel/adapters/discord.d.ts +45 -0
  31. package/dist/channel/adapters/discord.js +366 -0
  32. package/dist/channel/adapters/discord.js.map +1 -0
  33. package/dist/channel/adapters/telegram.d.ts +58 -0
  34. package/dist/channel/adapters/telegram.js +569 -0
  35. package/dist/channel/adapters/telegram.js.map +1 -0
  36. package/dist/channel/attachment-handler.d.ts +15 -0
  37. package/dist/channel/attachment-handler.js +55 -0
  38. package/dist/channel/attachment-handler.js.map +1 -0
  39. package/dist/channel/factory.d.ts +12 -0
  40. package/dist/channel/factory.js +38 -0
  41. package/dist/channel/factory.js.map +1 -0
  42. package/dist/channel/ipc-bridge.d.ts +26 -0
  43. package/dist/channel/ipc-bridge.js +170 -0
  44. package/dist/channel/ipc-bridge.js.map +1 -0
  45. package/dist/channel/mcp-server.d.ts +10 -0
  46. package/dist/channel/mcp-server.js +196 -0
  47. package/dist/channel/mcp-server.js.map +1 -0
  48. package/dist/channel/mcp-tools.d.ts +909 -0
  49. package/dist/channel/mcp-tools.js +346 -0
  50. package/dist/channel/mcp-tools.js.map +1 -0
  51. package/dist/channel/message-bus.d.ts +17 -0
  52. package/dist/channel/message-bus.js +86 -0
  53. package/dist/channel/message-bus.js.map +1 -0
  54. package/dist/channel/message-queue.d.ts +39 -0
  55. package/dist/channel/message-queue.js +248 -0
  56. package/dist/channel/message-queue.js.map +1 -0
  57. package/dist/channel/tool-router.d.ts +6 -0
  58. package/dist/channel/tool-router.js +69 -0
  59. package/dist/channel/tool-router.js.map +1 -0
  60. package/dist/channel/tool-tracker.d.ts +13 -0
  61. package/dist/channel/tool-tracker.js +58 -0
  62. package/dist/channel/tool-tracker.js.map +1 -0
  63. package/dist/channel/types.d.ts +116 -0
  64. package/dist/channel/types.js +2 -0
  65. package/dist/channel/types.js.map +1 -0
  66. package/dist/cli.d.ts +2 -0
  67. package/dist/cli.js +782 -0
  68. package/dist/cli.js.map +1 -0
  69. package/dist/config.d.ts +8 -0
  70. package/dist/config.js +85 -0
  71. package/dist/config.js.map +1 -0
  72. package/dist/context-guardian.d.ts +29 -0
  73. package/dist/context-guardian.js +123 -0
  74. package/dist/context-guardian.js.map +1 -0
  75. package/dist/cost-guard.d.ts +21 -0
  76. package/dist/cost-guard.js +113 -0
  77. package/dist/cost-guard.js.map +1 -0
  78. package/dist/daemon-entry.d.ts +1 -0
  79. package/dist/daemon-entry.js +29 -0
  80. package/dist/daemon-entry.js.map +1 -0
  81. package/dist/daemon.d.ts +88 -0
  82. package/dist/daemon.js +821 -0
  83. package/dist/daemon.js.map +1 -0
  84. package/dist/daily-summary.d.ts +13 -0
  85. package/dist/daily-summary.js +55 -0
  86. package/dist/daily-summary.js.map +1 -0
  87. package/dist/event-log.d.ts +22 -0
  88. package/dist/event-log.js +66 -0
  89. package/dist/event-log.js.map +1 -0
  90. package/dist/export-import.d.ts +2 -0
  91. package/dist/export-import.js +110 -0
  92. package/dist/export-import.js.map +1 -0
  93. package/dist/fleet-context.d.ts +36 -0
  94. package/dist/fleet-context.js +4 -0
  95. package/dist/fleet-context.js.map +1 -0
  96. package/dist/fleet-manager.d.ts +115 -0
  97. package/dist/fleet-manager.js +1739 -0
  98. package/dist/fleet-manager.js.map +1 -0
  99. package/dist/fleet-system-prompt.d.ts +11 -0
  100. package/dist/fleet-system-prompt.js +60 -0
  101. package/dist/fleet-system-prompt.js.map +1 -0
  102. package/dist/hang-detector.d.ts +16 -0
  103. package/dist/hang-detector.js +53 -0
  104. package/dist/hang-detector.js.map +1 -0
  105. package/dist/index.d.ts +8 -0
  106. package/dist/index.js +6 -0
  107. package/dist/index.js.map +1 -0
  108. package/dist/logger.d.ts +3 -0
  109. package/dist/logger.js +63 -0
  110. package/dist/logger.js.map +1 -0
  111. package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
  112. package/dist/scheduler/db.d.ts +16 -0
  113. package/dist/scheduler/db.js +132 -0
  114. package/dist/scheduler/db.js.map +1 -0
  115. package/dist/scheduler/db.test.d.ts +1 -0
  116. package/dist/scheduler/db.test.js +92 -0
  117. package/dist/scheduler/db.test.js.map +1 -0
  118. package/dist/scheduler/index.d.ts +4 -0
  119. package/dist/scheduler/index.js +4 -0
  120. package/dist/scheduler/index.js.map +1 -0
  121. package/dist/scheduler/scheduler.d.ts +25 -0
  122. package/dist/scheduler/scheduler.js +119 -0
  123. package/dist/scheduler/scheduler.js.map +1 -0
  124. package/dist/scheduler/scheduler.test.d.ts +1 -0
  125. package/dist/scheduler/scheduler.test.js +119 -0
  126. package/dist/scheduler/scheduler.test.js.map +1 -0
  127. package/dist/scheduler/types.d.ts +47 -0
  128. package/dist/scheduler/types.js +7 -0
  129. package/dist/scheduler/types.js.map +1 -0
  130. package/dist/service-installer.d.ts +14 -0
  131. package/dist/service-installer.js +91 -0
  132. package/dist/service-installer.js.map +1 -0
  133. package/dist/setup-wizard.d.ts +14 -0
  134. package/dist/setup-wizard.js +517 -0
  135. package/dist/setup-wizard.js.map +1 -0
  136. package/dist/stt.d.ts +10 -0
  137. package/dist/stt.js +33 -0
  138. package/dist/stt.js.map +1 -0
  139. package/dist/tmux-manager.d.ts +22 -0
  140. package/dist/tmux-manager.js +132 -0
  141. package/dist/tmux-manager.js.map +1 -0
  142. package/dist/topic-commands.d.ts +22 -0
  143. package/dist/topic-commands.js +176 -0
  144. package/dist/topic-commands.js.map +1 -0
  145. package/dist/transcript-monitor.d.ts +21 -0
  146. package/dist/transcript-monitor.js +149 -0
  147. package/dist/transcript-monitor.js.map +1 -0
  148. package/dist/types.d.ts +153 -0
  149. package/dist/types.js +2 -0
  150. package/dist/types.js.map +1 -0
  151. package/dist/webhook-emitter.d.ts +15 -0
  152. package/dist/webhook-emitter.js +41 -0
  153. package/dist/webhook-emitter.js.map +1 -0
  154. package/package.json +58 -4
  155. package/templates/launchd.plist.ejs +29 -0
  156. package/templates/systemd.service.ejs +15 -0
  157. package/index.js +0 -1
@@ -0,0 +1,248 @@
1
+ const MAX_MESSAGE_LENGTH = 4096;
2
+ const WORKER_IDLE_WAIT_MS = 200;
3
+ const WORKER_BETWEEN_MS = 50;
4
+ const MAX_BACKOFF_MS = 30_000;
5
+ const FLOOD_CONTROL_THRESHOLD_MS = 10_000;
6
+ const INITIAL_BACKOFF_MS = 1_000;
7
+ function is429Error(err) {
8
+ if (err instanceof Error) {
9
+ const e = err;
10
+ if (e.status === 429)
11
+ return true;
12
+ if (e.code === 429)
13
+ return true;
14
+ if (e.response?.status === 429)
15
+ return true;
16
+ if (e.message.includes("429") || e.message.toLowerCase().includes("too many requests"))
17
+ return true;
18
+ }
19
+ return false;
20
+ }
21
+ function splitText(text) {
22
+ const chunks = [];
23
+ let offset = 0;
24
+ while (offset < text.length) {
25
+ chunks.push(text.slice(offset, offset + MAX_MESSAGE_LENGTH));
26
+ offset += MAX_MESSAGE_LENGTH;
27
+ }
28
+ return chunks;
29
+ }
30
+ export class MessageQueue {
31
+ sender;
32
+ queues = new Map();
33
+ stopped = true;
34
+ logger;
35
+ constructor(sender, logger) {
36
+ this.sender = sender;
37
+ this.logger = logger;
38
+ }
39
+ queueKey(chatId, threadId) {
40
+ return threadId != null ? `${chatId}:${threadId}` : `${chatId}:`;
41
+ }
42
+ getOrCreateQueue(chatId, threadId) {
43
+ const key = this.queueKey(chatId, threadId);
44
+ let state = this.queues.get(key);
45
+ if (!state) {
46
+ state = {
47
+ key: { chatId, threadId },
48
+ items: [],
49
+ backoffMs: INITIAL_BACKOFF_MS,
50
+ backoffUntil: 0,
51
+ running: false,
52
+ };
53
+ this.queues.set(key, state);
54
+ }
55
+ return state;
56
+ }
57
+ enqueue(chatId, threadId, msg) {
58
+ const state = this.getOrCreateQueue(chatId, threadId);
59
+ state.items.push(msg);
60
+ // If worker is already running, it will pick this up automatically.
61
+ // If queue was started and worker is not running, restart it.
62
+ if (!this.stopped && !state.running) {
63
+ this.runWorker(state);
64
+ }
65
+ }
66
+ start() {
67
+ this.stopped = false;
68
+ // Start workers for any queues that already have items
69
+ for (const state of this.queues.values()) {
70
+ if (!state.running && state.items.length > 0) {
71
+ this.runWorker(state);
72
+ }
73
+ }
74
+ }
75
+ stop() {
76
+ this.stopped = true;
77
+ // Clear all queues
78
+ for (const state of this.queues.values()) {
79
+ state.items = [];
80
+ }
81
+ }
82
+ async runWorker(state) {
83
+ if (state.running)
84
+ return;
85
+ state.running = true;
86
+ while (!this.stopped) {
87
+ // Apply backoff if needed
88
+ const now = Date.now();
89
+ if (state.backoffUntil > now) {
90
+ const waitMs = state.backoffUntil - now;
91
+ await this.sleep(Math.min(waitMs, 100));
92
+ continue;
93
+ }
94
+ // Apply flood control: drop status_update items if backoff > threshold
95
+ if (state.backoffMs > FLOOD_CONTROL_THRESHOLD_MS) {
96
+ const before = state.items.length;
97
+ state.items = state.items.filter(item => item.type !== "status_update");
98
+ if (before !== state.items.length) {
99
+ // Items were dropped; reset backoff now that we've cleaned up
100
+ }
101
+ }
102
+ if (state.items.length === 0) {
103
+ await this.sleep(WORKER_IDLE_WAIT_MS);
104
+ continue;
105
+ }
106
+ // Pop and process next item(s)
107
+ const { items: pendingItems, work } = this.prepareNext(state);
108
+ if (!work) {
109
+ await this.sleep(WORKER_IDLE_WAIT_MS);
110
+ continue;
111
+ }
112
+ try {
113
+ await work();
114
+ // Reset backoff on success
115
+ state.backoffMs = INITIAL_BACKOFF_MS;
116
+ state.backoffUntil = 0;
117
+ await this.sleep(WORKER_BETWEEN_MS);
118
+ }
119
+ catch (err) {
120
+ if (is429Error(err)) {
121
+ // Re-insert the consumed items back at the front of the queue
122
+ state.items.unshift(...pendingItems);
123
+ // Exponential backoff, cap at MAX_BACKOFF_MS
124
+ state.backoffUntil = Date.now() + state.backoffMs;
125
+ state.backoffMs = Math.min(state.backoffMs * 2, MAX_BACKOFF_MS);
126
+ }
127
+ else {
128
+ // Non-rate-limit error: drop the item to avoid infinite loops
129
+ this.logger?.warn({ err, chatId: state.key.chatId }, "Message dropped due to non-retryable error");
130
+ state.backoffMs = INITIAL_BACKOFF_MS;
131
+ state.backoffUntil = 0;
132
+ await this.sleep(WORKER_BETWEEN_MS);
133
+ }
134
+ }
135
+ }
136
+ state.running = false;
137
+ }
138
+ /**
139
+ * Synchronously extracts items from the queue and returns the extracted items
140
+ * plus an async work function. The work function does the actual sending.
141
+ * This split allows us to know which items to re-queue if the work fails.
142
+ */
143
+ prepareNext(state) {
144
+ const { chatId, threadId } = state.key;
145
+ const first = state.items[0];
146
+ if (!first)
147
+ return { items: [], work: null };
148
+ if (first.type === "content") {
149
+ const { merged, consumed } = this.mergeContentMessages(state);
150
+ const work = async () => {
151
+ for (const chunk of merged) {
152
+ if (chunk.filePath) {
153
+ await this.sender.sendFile(chatId, threadId, chunk.filePath);
154
+ }
155
+ else if (chunk.text) {
156
+ const parts = splitText(chunk.text);
157
+ for (const part of parts) {
158
+ await this.sender.send(chatId, threadId, part);
159
+ }
160
+ }
161
+ }
162
+ };
163
+ return { items: consumed, work };
164
+ }
165
+ else if (first.type === "status_update") {
166
+ state.items.shift();
167
+ const item = first;
168
+ const work = async () => {
169
+ if (item.editMessageId) {
170
+ await this.sender.edit(chatId, item.editMessageId, item.text ?? "");
171
+ }
172
+ else {
173
+ await this.sender.send(chatId, threadId, item.text ?? "");
174
+ }
175
+ };
176
+ return { items: [item], work };
177
+ }
178
+ else if (first.type === "status_clear") {
179
+ state.items.shift();
180
+ return { items: [first], work: async () => { } };
181
+ }
182
+ return { items: [], work: null };
183
+ }
184
+ /**
185
+ * Merges all adjacent content messages at the front of the queue.
186
+ * Respects the 4096 char limit per chunk.
187
+ * Returns merged chunks plus the original consumed items (for re-queuing on error).
188
+ */
189
+ mergeContentMessages(state) {
190
+ // Collect all leading content items
191
+ const consumed = [];
192
+ while (state.items.length > 0 && state.items[0].type === "content") {
193
+ consumed.push(state.items.shift());
194
+ }
195
+ const merged = [];
196
+ let currentText = "";
197
+ for (const item of consumed) {
198
+ if (item.filePath) {
199
+ // Flush any pending text first
200
+ if (currentText.length > 0) {
201
+ const parts = splitText(currentText);
202
+ for (const part of parts) {
203
+ merged.push({ text: part });
204
+ }
205
+ currentText = "";
206
+ }
207
+ merged.push({ filePath: item.filePath });
208
+ }
209
+ else if (item.text) {
210
+ // Try to append to current text, splitting if necessary
211
+ const combined = currentText + item.text;
212
+ if (combined.length <= MAX_MESSAGE_LENGTH) {
213
+ currentText = combined;
214
+ }
215
+ else {
216
+ // Flush current accumulated text first
217
+ if (currentText.length > 0) {
218
+ const parts = splitText(currentText);
219
+ for (const part of parts) {
220
+ merged.push({ text: part });
221
+ }
222
+ currentText = "";
223
+ }
224
+ // Now handle item.text which might itself be long
225
+ if (item.text.length <= MAX_MESSAGE_LENGTH) {
226
+ currentText = item.text;
227
+ }
228
+ else {
229
+ const parts = splitText(item.text);
230
+ const lastPart = parts.pop();
231
+ for (const part of parts) {
232
+ merged.push({ text: part });
233
+ }
234
+ currentText = lastPart;
235
+ }
236
+ }
237
+ }
238
+ }
239
+ if (currentText.length > 0) {
240
+ merged.push({ text: currentText });
241
+ }
242
+ return { merged, consumed };
243
+ }
244
+ sleep(ms) {
245
+ return new Promise(resolve => setTimeout(resolve, ms));
246
+ }
247
+ }
248
+ //# sourceMappingURL=message-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../src/channel/message-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ChannelAdapter } from "./types.js";
2
+ /**
3
+ * Route a channel tool call (reply, react, edit_message, download_attachment)
4
+ * to the adapter. Returns true if handled, false if unknown tool.
5
+ */
6
+ export declare function routeToolCall(adapter: ChannelAdapter, tool: string, args: Record<string, unknown>, threadId: string | undefined, respond: (result: unknown, error?: string) => void): boolean;
@@ -0,0 +1,69 @@
1
+ import { homedir } from "node:os";
2
+ import { resolve, sep } from "node:path";
3
+ import { realpathSync, existsSync } from "node:fs";
4
+ const STATE_DIR = resolve(homedir(), ".agend") + sep;
5
+ const INBOX_SEG = sep + "inbox" + sep;
6
+ /** Block files inside the state dir (except inbox/) from being sent out. */
7
+ function assertSendable(filePath) {
8
+ let resolved;
9
+ try {
10
+ resolved = realpathSync(filePath);
11
+ }
12
+ catch {
13
+ if (!existsSync(filePath))
14
+ return; // truly missing — let adapter handle
15
+ throw new Error(`Blocked: cannot resolve path ${filePath}`);
16
+ }
17
+ if (resolved.startsWith(STATE_DIR) && !resolved.includes(INBOX_SEG)) {
18
+ throw new Error(`Blocked: refusing to send state file ${filePath}`);
19
+ }
20
+ }
21
+ /**
22
+ * Route a channel tool call (reply, react, edit_message, download_attachment)
23
+ * to the adapter. Returns true if handled, false if unknown tool.
24
+ */
25
+ export function routeToolCall(adapter, tool, args, threadId, respond) {
26
+ const chatId = args.chat_id ?? "";
27
+ switch (tool) {
28
+ case "reply": {
29
+ const files = Array.isArray(args.files) ? args.files : [];
30
+ try {
31
+ for (const f of files)
32
+ assertSendable(f);
33
+ }
34
+ catch (e) {
35
+ respond(null, e.message);
36
+ return true;
37
+ }
38
+ const replyThreadId = args.thread_id ?? threadId;
39
+ adapter.sendText(chatId, args.text ?? "", {
40
+ threadId: replyThreadId,
41
+ replyTo: args.reply_to,
42
+ }).then(async (sent) => {
43
+ for (const filePath of files) {
44
+ await adapter.sendFile(chatId, filePath, { threadId: replyThreadId });
45
+ }
46
+ respond(sent);
47
+ }).catch(e => respond(null, e.message));
48
+ return true;
49
+ }
50
+ case "react":
51
+ adapter.react(chatId, args.message_id ?? "", args.emoji ?? "")
52
+ .then(() => respond("ok"))
53
+ .catch(e => respond(null, e.message));
54
+ return true;
55
+ case "edit_message":
56
+ adapter.editMessage(chatId, args.message_id ?? "", args.text ?? "")
57
+ .then(() => respond("ok"))
58
+ .catch(e => respond(null, e.message));
59
+ return true;
60
+ case "download_attachment":
61
+ adapter.downloadAttachment(args.file_id ?? "")
62
+ .then(path => respond(path))
63
+ .catch(e => respond(null, e.message));
64
+ return true;
65
+ default:
66
+ return false;
67
+ }
68
+ }
69
+ //# sourceMappingURL=tool-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-router.js","sourceRoot":"","sources":["../../src/channel/tool-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ChannelAdapter } from "./types.js";
2
+ export declare class ToolTracker {
3
+ private adapter;
4
+ private chatId;
5
+ private threadId?;
6
+ private statusMessageId;
7
+ private lines;
8
+ constructor(adapter: ChannelAdapter, chatId: string, threadId?: string | undefined);
9
+ onToolUse(toolName: string, input: unknown): Promise<void>;
10
+ onToolResult(toolName: string, _output: unknown): Promise<void>;
11
+ reset(): void;
12
+ private summarizeTool;
13
+ }
@@ -0,0 +1,58 @@
1
+ export class ToolTracker {
2
+ adapter;
3
+ chatId;
4
+ threadId;
5
+ statusMessageId = null;
6
+ lines = [];
7
+ constructor(adapter, chatId, threadId) {
8
+ this.adapter = adapter;
9
+ this.chatId = chatId;
10
+ this.threadId = threadId;
11
+ }
12
+ async onToolUse(toolName, input) {
13
+ const summary = this.summarizeTool(toolName, input);
14
+ this.lines.push(`🔧 ${summary}`);
15
+ if (!this.statusMessageId) {
16
+ // First tool — send new message
17
+ const sent = await this.adapter.sendText(this.chatId, this.lines.join("\n"), { threadId: this.threadId });
18
+ this.statusMessageId = sent.messageId;
19
+ }
20
+ else {
21
+ // Subsequent — edit existing
22
+ await this.adapter.editMessage(this.chatId, this.statusMessageId, this.lines.join("\n"));
23
+ }
24
+ }
25
+ async onToolResult(toolName, _output) {
26
+ // Find the last line matching this tool and mark it done
27
+ for (let i = this.lines.length - 1; i >= 0; i--) {
28
+ if (this.lines[i].includes(toolName) && this.lines[i].startsWith("🔧")) {
29
+ this.lines[i] = this.lines[i].replace("🔧", "✅");
30
+ break;
31
+ }
32
+ }
33
+ if (this.statusMessageId) {
34
+ await this.adapter.editMessage(this.chatId, this.statusMessageId, this.lines.join("\n"));
35
+ }
36
+ }
37
+ reset() {
38
+ this.statusMessageId = null;
39
+ this.lines = [];
40
+ }
41
+ summarizeTool(name, input) {
42
+ const inp = input;
43
+ if (name === "Read")
44
+ return `Read: ${inp.file_path ?? ""}`;
45
+ if (name === "Edit")
46
+ return `Edit: ${inp.file_path ?? ""}`;
47
+ if (name === "Write")
48
+ return `Write: ${inp.file_path ?? ""}`;
49
+ if (name === "Bash")
50
+ return `Bash: ${String(inp.command ?? "").slice(0, 60)}`;
51
+ if (name === "Glob")
52
+ return `Glob: ${inp.pattern ?? ""}`;
53
+ if (name === "Grep")
54
+ return `Grep: ${inp.pattern ?? ""}`;
55
+ return name;
56
+ }
57
+ }
58
+ //# sourceMappingURL=tool-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-tracker.js","sourceRoot":"","sources":["../../src/channel/tool-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import { EventEmitter } from "node:events";
2
+ export interface Choice {
3
+ id: string;
4
+ label: string;
5
+ }
6
+ export interface InstanceStatusData {
7
+ name: string;
8
+ status: "running" | "stopped" | "crashed" | "paused";
9
+ contextPct: number | null;
10
+ costCents: number;
11
+ }
12
+ export interface AlertData {
13
+ type: "hang" | "cost_warn" | "cost_limit" | "schedule_deferred" | "rotation";
14
+ instanceName: string;
15
+ message: string;
16
+ choices?: Choice[];
17
+ }
18
+ export interface ChannelAdapter extends EventEmitter {
19
+ readonly type: string;
20
+ readonly id: string;
21
+ start(): Promise<void>;
22
+ stop(): Promise<void>;
23
+ sendText(chatId: string, text: string, opts?: SendOpts): Promise<SentMessage>;
24
+ sendFile(chatId: string, filePath: string, opts?: SendOpts): Promise<SentMessage>;
25
+ editMessage(chatId: string, messageId: string, text: string): Promise<void>;
26
+ react(chatId: string, messageId: string, emoji: string): Promise<void>;
27
+ sendApproval(prompt: PermissionPrompt, callback: (decision: "approve" | "approve_always" | "deny") => void, signal?: AbortSignal, threadId?: string): Promise<ApprovalHandle>;
28
+ downloadAttachment(fileId: string): Promise<string>;
29
+ handlePairing(chatId: string, userId: string): Promise<string>;
30
+ confirmPairing(code: string): Promise<boolean>;
31
+ readonly topology: "topics" | "channels" | "flat";
32
+ setChatId(chatId: string): void;
33
+ getChatId(): string | null;
34
+ promptUser(chatId: string, text: string, choices: Choice[], opts?: SendOpts): Promise<string>;
35
+ notifyAlert(chatId: string, alert: AlertData, opts?: SendOpts): Promise<SentMessage>;
36
+ createTopic?(name: string): Promise<number>;
37
+ topicExists?(topicId: number): Promise<boolean>;
38
+ closeForumTopic?(threadId: number): Promise<void>;
39
+ reopenForumTopic?(threadId: number): Promise<void>;
40
+ editForumTopic?(threadId: number, opts: {
41
+ name?: string;
42
+ iconCustomEmojiId?: string;
43
+ }): Promise<void>;
44
+ getTopicIconStickers?(): Promise<{
45
+ customEmojiId: string;
46
+ emoji: string;
47
+ }[]>;
48
+ }
49
+ export interface ApprovalHandle {
50
+ cancel(): void;
51
+ }
52
+ export interface SendOpts {
53
+ threadId?: string;
54
+ replyTo?: string;
55
+ format?: "text" | "markdown";
56
+ chunkLimit?: number;
57
+ }
58
+ export interface SentMessage {
59
+ messageId: string;
60
+ chatId: string;
61
+ threadId?: string;
62
+ }
63
+ export interface OutboundMessage {
64
+ text?: string;
65
+ filePath?: string;
66
+ threadId?: string;
67
+ replyTo?: string;
68
+ format?: "text" | "markdown";
69
+ }
70
+ export interface InboundMessage {
71
+ source: string;
72
+ adapterId: string;
73
+ chatId: string;
74
+ threadId?: string;
75
+ messageId: string;
76
+ userId: string;
77
+ username: string;
78
+ text: string;
79
+ timestamp: Date;
80
+ attachments?: Attachment[];
81
+ replyTo?: string;
82
+ replyToText?: string;
83
+ }
84
+ export interface Attachment {
85
+ kind: "photo" | "document" | "audio" | "voice" | "video" | "sticker";
86
+ fileId: string;
87
+ localPath?: string;
88
+ mime?: string;
89
+ size?: number;
90
+ filename?: string;
91
+ transcription?: string;
92
+ }
93
+ export interface PermissionPrompt {
94
+ tool_name: string;
95
+ description: string;
96
+ input_preview?: string;
97
+ }
98
+ export interface ApprovalResponse {
99
+ decision: "approve" | "approve_always" | "deny";
100
+ respondedBy?: {
101
+ channelType: string;
102
+ userId: string;
103
+ };
104
+ reason?: string;
105
+ }
106
+ export interface Target {
107
+ adapterId?: string;
108
+ chatId: string;
109
+ threadId?: string;
110
+ }
111
+ export interface QueuedMessage {
112
+ type: "content" | "status_update" | "status_clear";
113
+ text?: string;
114
+ filePath?: string;
115
+ editMessageId?: string;
116
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/channel/types.ts"],"names":[],"mappings":""}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};