claudeck 1.0.0
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/LICENSE +21 -0
- package/README.md +233 -0
- package/cli.js +2 -0
- package/config/agent-chains.json +16 -0
- package/config/agent-dags.json +16 -0
- package/config/agents.json +46 -0
- package/config/bot-prompt.json +3 -0
- package/config/folders.json +66 -0
- package/config/prompts.json +92 -0
- package/config/repos.json +86 -0
- package/config/telegram-config.json +17 -0
- package/config/workflows.json +90 -0
- package/db.js +1198 -0
- package/package.json +55 -0
- package/plugins/claude-editor/client.css +171 -0
- package/plugins/claude-editor/client.js +183 -0
- package/plugins/event-stream/client.css +207 -0
- package/plugins/event-stream/client.js +271 -0
- package/plugins/linear/client.css +345 -0
- package/plugins/linear/client.js +380 -0
- package/plugins/linear/config.json +5 -0
- package/plugins/linear/server.js +312 -0
- package/plugins/repos/client.css +549 -0
- package/plugins/repos/client.js +663 -0
- package/plugins/repos/server.js +232 -0
- package/plugins/sudoku/client.css +196 -0
- package/plugins/sudoku/client.js +329 -0
- package/plugins/tasks/client.css +414 -0
- package/plugins/tasks/client.js +394 -0
- package/plugins/tasks/server.js +116 -0
- package/plugins/tic-tac-toe/client.css +167 -0
- package/plugins/tic-tac-toe/client.js +241 -0
- package/public/css/core/components.css +232 -0
- package/public/css/core/layout.css +330 -0
- package/public/css/core/print.css +18 -0
- package/public/css/core/reset.css +36 -0
- package/public/css/core/responsive.css +378 -0
- package/public/css/core/theme.css +116 -0
- package/public/css/core/variables.css +93 -0
- package/public/css/features/agent-monitor.css +297 -0
- package/public/css/features/agent-sidebar.css +525 -0
- package/public/css/features/agents.css +996 -0
- package/public/css/features/analytics.css +181 -0
- package/public/css/features/background-sessions.css +321 -0
- package/public/css/features/cost-dashboard.css +168 -0
- package/public/css/features/home.css +313 -0
- package/public/css/features/retro-terminal.css +88 -0
- package/public/css/features/telegram.css +127 -0
- package/public/css/features/tour.css +148 -0
- package/public/css/features/voice-input.css +60 -0
- package/public/css/features/welcome.css +241 -0
- package/public/css/panels/assistant-bot.css +442 -0
- package/public/css/panels/dev-docs.css +292 -0
- package/public/css/panels/file-explorer.css +322 -0
- package/public/css/panels/git-panel.css +221 -0
- package/public/css/panels/mcp-manager.css +199 -0
- package/public/css/panels/tips-feed.css +353 -0
- package/public/css/ui/commands.css +273 -0
- package/public/css/ui/context-gauge.css +76 -0
- package/public/css/ui/file-picker.css +69 -0
- package/public/css/ui/image-attachments.css +106 -0
- package/public/css/ui/messages.css +884 -0
- package/public/css/ui/modals.css +122 -0
- package/public/css/ui/parallel.css +217 -0
- package/public/css/ui/permissions.css +110 -0
- package/public/css/ui/right-panel.css +481 -0
- package/public/css/ui/sessions.css +689 -0
- package/public/css/ui/status-bar.css +425 -0
- package/public/css/ui/toolbox.css +206 -0
- package/public/data/tips.json +218 -0
- package/public/icons/favicon.png +0 -0
- package/public/icons/icon-192.png +0 -0
- package/public/icons/icon-512.png +0 -0
- package/public/icons/whaly.png +0 -0
- package/public/index.html +1140 -0
- package/public/js/core/api.js +591 -0
- package/public/js/core/constants.js +3 -0
- package/public/js/core/dom.js +270 -0
- package/public/js/core/events.js +10 -0
- package/public/js/core/plugin-loader.js +153 -0
- package/public/js/core/store.js +39 -0
- package/public/js/core/utils.js +25 -0
- package/public/js/core/ws.js +64 -0
- package/public/js/features/agent-monitor.js +222 -0
- package/public/js/features/agents.js +1209 -0
- package/public/js/features/analytics.js +397 -0
- package/public/js/features/attachments.js +251 -0
- package/public/js/features/background-sessions.js +475 -0
- package/public/js/features/chat.js +589 -0
- package/public/js/features/cost-dashboard.js +152 -0
- package/public/js/features/dag-editor.js +399 -0
- package/public/js/features/easter-egg.js +46 -0
- package/public/js/features/home.js +270 -0
- package/public/js/features/projects.js +372 -0
- package/public/js/features/prompts.js +228 -0
- package/public/js/features/sessions.js +332 -0
- package/public/js/features/telegram.js +131 -0
- package/public/js/features/tour.js +210 -0
- package/public/js/features/voice-input.js +185 -0
- package/public/js/features/welcome.js +43 -0
- package/public/js/features/workflows.js +277 -0
- package/public/js/main.js +51 -0
- package/public/js/panels/assistant-bot.js +445 -0
- package/public/js/panels/dev-docs.js +380 -0
- package/public/js/panels/file-explorer.js +486 -0
- package/public/js/panels/git-panel.js +285 -0
- package/public/js/panels/mcp-manager.js +311 -0
- package/public/js/panels/tips-feed.js +303 -0
- package/public/js/ui/commands.js +114 -0
- package/public/js/ui/context-gauge.js +100 -0
- package/public/js/ui/diff.js +124 -0
- package/public/js/ui/disabled-tools.js +36 -0
- package/public/js/ui/export.js +74 -0
- package/public/js/ui/formatting.js +206 -0
- package/public/js/ui/header-dropdowns.js +72 -0
- package/public/js/ui/input-meta.js +71 -0
- package/public/js/ui/max-turns.js +21 -0
- package/public/js/ui/messages.js +387 -0
- package/public/js/ui/model-selector.js +20 -0
- package/public/js/ui/notifications.js +232 -0
- package/public/js/ui/parallel.js +176 -0
- package/public/js/ui/permissions.js +168 -0
- package/public/js/ui/right-panel.js +173 -0
- package/public/js/ui/shortcuts.js +143 -0
- package/public/js/ui/sidebar-toggle.js +29 -0
- package/public/js/ui/status-bar.js +172 -0
- package/public/js/ui/tab-sdk.js +623 -0
- package/public/js/ui/theme.js +38 -0
- package/public/manifest.json +13 -0
- package/public/offline.html +190 -0
- package/public/style.css +42 -0
- package/public/sw.js +91 -0
- package/server/agent-loop.js +385 -0
- package/server/dag-executor.js +265 -0
- package/server/orchestrator.js +514 -0
- package/server/paths.js +61 -0
- package/server/plugin-mount.js +56 -0
- package/server/push-sender.js +31 -0
- package/server/routes/agents.js +294 -0
- package/server/routes/bot.js +45 -0
- package/server/routes/exec.js +35 -0
- package/server/routes/files.js +218 -0
- package/server/routes/mcp.js +82 -0
- package/server/routes/messages.js +36 -0
- package/server/routes/notifications.js +37 -0
- package/server/routes/projects.js +207 -0
- package/server/routes/prompts.js +53 -0
- package/server/routes/sessions.js +103 -0
- package/server/routes/stats.js +143 -0
- package/server/routes/telegram.js +71 -0
- package/server/routes/tips.js +135 -0
- package/server/routes/workflows.js +81 -0
- package/server/summarizer.js +55 -0
- package/server/telegram-poller.js +205 -0
- package/server/telegram-sender.js +304 -0
- package/server/ws-handler.js +926 -0
- package/server.js +179 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// Telegram notification sender — two-way: rich notifications + permission approvals
|
|
2
|
+
import { readFile, writeFile } from "fs/promises";
|
|
3
|
+
import { configPath } from "./paths.js";
|
|
4
|
+
|
|
5
|
+
const configFile = configPath("telegram-config.json");
|
|
6
|
+
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
enabled: false,
|
|
9
|
+
botToken: "",
|
|
10
|
+
chatId: "",
|
|
11
|
+
afkTimeoutMinutes: 15,
|
|
12
|
+
notify: {
|
|
13
|
+
sessionComplete: true,
|
|
14
|
+
workflowComplete: true,
|
|
15
|
+
chainComplete: true,
|
|
16
|
+
agentComplete: true,
|
|
17
|
+
orchestratorComplete: true,
|
|
18
|
+
dagComplete: true,
|
|
19
|
+
errors: true,
|
|
20
|
+
permissionRequests: true,
|
|
21
|
+
taskStart: true,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
let config = { ...DEFAULT_CONFIG };
|
|
26
|
+
|
|
27
|
+
async function readConfig() {
|
|
28
|
+
try {
|
|
29
|
+
const raw = await readFile(configFile, "utf-8");
|
|
30
|
+
const saved = JSON.parse(raw);
|
|
31
|
+
return { ...DEFAULT_CONFIG, ...saved, notify: { ...DEFAULT_CONFIG.notify, ...saved.notify } };
|
|
32
|
+
} catch {
|
|
33
|
+
return { ...DEFAULT_CONFIG };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function initTelegramSender() {
|
|
38
|
+
config = await readConfig();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function saveTelegramConfig(newConfig) {
|
|
42
|
+
const merged = {
|
|
43
|
+
...DEFAULT_CONFIG,
|
|
44
|
+
...newConfig,
|
|
45
|
+
notify: { ...DEFAULT_CONFIG.notify, ...newConfig.notify },
|
|
46
|
+
};
|
|
47
|
+
await writeFile(configFile, JSON.stringify(merged, null, 2) + "\n");
|
|
48
|
+
config = merged;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getTelegramConfig() {
|
|
52
|
+
return {
|
|
53
|
+
enabled: config.enabled,
|
|
54
|
+
botToken: config.botToken ? maskToken(config.botToken) : "",
|
|
55
|
+
chatId: config.chatId || "",
|
|
56
|
+
afkTimeoutMinutes: config.afkTimeoutMinutes || 15,
|
|
57
|
+
notify: { ...config.notify },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getRawBotToken() {
|
|
62
|
+
return config.botToken || "";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isEnabled() {
|
|
66
|
+
return !!(config.enabled && config.botToken && config.chatId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getConfig() {
|
|
70
|
+
return config;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function maskToken(token) {
|
|
74
|
+
if (!token || token.length < 8) return "****";
|
|
75
|
+
return "****:" + token.slice(-6);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Telegram Bot API helpers ──
|
|
79
|
+
|
|
80
|
+
async function apiCall(method, body) {
|
|
81
|
+
if (!config.botToken) return null;
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch(
|
|
84
|
+
`https://api.telegram.org/bot${config.botToken}/${method}`,
|
|
85
|
+
{
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "Content-Type": "application/json" },
|
|
88
|
+
body: JSON.stringify(body),
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
const err = await res.text();
|
|
93
|
+
console.error(`Telegram ${method} failed:`, res.status, err);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return await res.json();
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.error(`Telegram ${method} error:`, err.message);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── Rich notification messages ──
|
|
104
|
+
|
|
105
|
+
function formatDuration(ms) {
|
|
106
|
+
if (!ms || ms < 1000) return "<1s";
|
|
107
|
+
const s = Math.floor(ms / 1000);
|
|
108
|
+
if (s < 60) return `${s}s`;
|
|
109
|
+
const m = Math.floor(s / 60);
|
|
110
|
+
const rs = s % 60;
|
|
111
|
+
if (m < 60) return rs ? `${m}m ${rs}s` : `${m}m`;
|
|
112
|
+
const h = Math.floor(m / 60);
|
|
113
|
+
const rm = m % 60;
|
|
114
|
+
return rm ? `${h}h ${rm}m` : `${h}h`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function formatCost(usd) {
|
|
118
|
+
if (!usd) return "$0.00";
|
|
119
|
+
return usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function formatTokens(n) {
|
|
123
|
+
if (!n) return "0";
|
|
124
|
+
if (n >= 1000000) return `${(n / 1000000).toFixed(1)}M`;
|
|
125
|
+
if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;
|
|
126
|
+
return String(n);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const EVENT_ICONS = {
|
|
130
|
+
session: "\u{1F4AC}", // 💬
|
|
131
|
+
workflow: "\u{2699}\u{FE0F}", // ⚙️
|
|
132
|
+
chain: "\u{1F517}", // 🔗
|
|
133
|
+
agent: "\u{1F916}", // 🤖
|
|
134
|
+
orchestrator: "\u{1F3AF}", // 🎯
|
|
135
|
+
dag: "\u{1F310}", // 🌐
|
|
136
|
+
error: "\u{26A0}\u{FE0F}", // ⚠️
|
|
137
|
+
start: "\u{25B6}\u{FE0F}", // ▶️
|
|
138
|
+
permission: "\u{1F512}", // 🔒
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Send a rich notification with optional metrics.
|
|
143
|
+
* @param {string} eventType - One of: session, workflow, chain, agent, orchestrator, dag, error, start
|
|
144
|
+
* @param {string} title - Main title
|
|
145
|
+
* @param {string} body - Description
|
|
146
|
+
* @param {object} [metrics] - { durationMs, costUsd, inputTokens, outputTokens, model, turns, steps, succeeded, failed }
|
|
147
|
+
*/
|
|
148
|
+
export async function sendTelegramNotification(eventType, title, body, metrics = {}) {
|
|
149
|
+
if (!isEnabled()) return;
|
|
150
|
+
|
|
151
|
+
// Check notification preference
|
|
152
|
+
const prefMap = {
|
|
153
|
+
session: "sessionComplete",
|
|
154
|
+
workflow: "workflowComplete",
|
|
155
|
+
chain: "chainComplete",
|
|
156
|
+
agent: "agentComplete",
|
|
157
|
+
orchestrator: "orchestratorComplete",
|
|
158
|
+
dag: "dagComplete",
|
|
159
|
+
error: "errors",
|
|
160
|
+
start: "taskStart",
|
|
161
|
+
};
|
|
162
|
+
const pref = prefMap[eventType];
|
|
163
|
+
if (pref && config.notify && config.notify[pref] === false) return;
|
|
164
|
+
|
|
165
|
+
const icon = EVENT_ICONS[eventType] || "";
|
|
166
|
+
let text = `${icon} <b>${escapeHtml(title)}</b>\n${escapeHtml(body)}`;
|
|
167
|
+
|
|
168
|
+
// Build metrics line
|
|
169
|
+
const parts = [];
|
|
170
|
+
if (metrics.durationMs) parts.push(`\u{23F1} ${formatDuration(metrics.durationMs)}`);
|
|
171
|
+
if (metrics.costUsd) parts.push(`\u{1F4B0} ${formatCost(metrics.costUsd)}`);
|
|
172
|
+
if (metrics.inputTokens || metrics.outputTokens) {
|
|
173
|
+
parts.push(`\u{1F4CA} ${formatTokens(metrics.inputTokens)}in / ${formatTokens(metrics.outputTokens)}out`);
|
|
174
|
+
}
|
|
175
|
+
if (metrics.model) parts.push(`\u{1F9E0} ${escapeHtml(metrics.model)}`);
|
|
176
|
+
if (metrics.turns) parts.push(`\u{1F504} ${metrics.turns} turns`);
|
|
177
|
+
if (metrics.steps) parts.push(`\u{1F4CB} ${metrics.steps} steps`);
|
|
178
|
+
if (typeof metrics.succeeded === "number" && typeof metrics.failed === "number") {
|
|
179
|
+
parts.push(`\u{2705} ${metrics.succeeded} / \u{274C} ${metrics.failed}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (parts.length) {
|
|
183
|
+
text += `\n\n${parts.join(" \u{00B7} ")}`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return apiCall("sendMessage", {
|
|
187
|
+
chat_id: config.chatId,
|
|
188
|
+
text,
|
|
189
|
+
parse_mode: "HTML",
|
|
190
|
+
disable_notification: eventType === "start",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Send a permission request with Approve/Deny inline keyboard.
|
|
196
|
+
* Returns the sent message (with message_id) or null.
|
|
197
|
+
*/
|
|
198
|
+
export async function sendPermissionRequest(approvalId, toolName, toolInput, sessionTitle) {
|
|
199
|
+
if (!isEnabled() || config.notify?.permissionRequests === false) return null;
|
|
200
|
+
|
|
201
|
+
const summary = getToolSummary(toolName, toolInput);
|
|
202
|
+
const label = sessionTitle ? `\n\u{1F4C1} ${escapeHtml(sessionTitle)}` : "";
|
|
203
|
+
|
|
204
|
+
const text =
|
|
205
|
+
`${EVENT_ICONS.permission} <b>Tool Approval Needed</b>${label}\n\n` +
|
|
206
|
+
`<b>${escapeHtml(toolName)}</b>\n` +
|
|
207
|
+
`<code>${escapeHtml(summary)}</code>`;
|
|
208
|
+
|
|
209
|
+
return apiCall("sendMessage", {
|
|
210
|
+
chat_id: config.chatId,
|
|
211
|
+
text,
|
|
212
|
+
parse_mode: "HTML",
|
|
213
|
+
reply_markup: {
|
|
214
|
+
inline_keyboard: [
|
|
215
|
+
[
|
|
216
|
+
{ text: "\u{2705} Approve", callback_data: `approve:${approvalId}` },
|
|
217
|
+
{ text: "\u{274C} Deny", callback_data: `deny:${approvalId}` },
|
|
218
|
+
],
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Edit a message (e.g., after approval/denial to update status).
|
|
226
|
+
*/
|
|
227
|
+
export async function editMessageText(messageId, newText) {
|
|
228
|
+
if (!isEnabled()) return null;
|
|
229
|
+
return apiCall("editMessageText", {
|
|
230
|
+
chat_id: config.chatId,
|
|
231
|
+
message_id: messageId,
|
|
232
|
+
text: newText,
|
|
233
|
+
parse_mode: "HTML",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Remove inline keyboard from a message.
|
|
239
|
+
*/
|
|
240
|
+
export async function editMessageReplyMarkup(messageId) {
|
|
241
|
+
if (!isEnabled()) return null;
|
|
242
|
+
return apiCall("editMessageReplyMarkup", {
|
|
243
|
+
chat_id: config.chatId,
|
|
244
|
+
message_id: messageId,
|
|
245
|
+
reply_markup: { inline_keyboard: [] },
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Answer a callback query (required by Telegram to dismiss the loading indicator).
|
|
251
|
+
*/
|
|
252
|
+
export async function answerCallbackQuery(callbackQueryId, text) {
|
|
253
|
+
if (!config.botToken) return null;
|
|
254
|
+
return apiCall("answerCallbackQuery", {
|
|
255
|
+
callback_query_id: callbackQueryId,
|
|
256
|
+
text: text || "",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ── Tool summary helper ──
|
|
261
|
+
|
|
262
|
+
function getToolSummary(toolName, input) {
|
|
263
|
+
if (!input) return toolName;
|
|
264
|
+
const maxLen = 200;
|
|
265
|
+
let summary = "";
|
|
266
|
+
|
|
267
|
+
switch (toolName) {
|
|
268
|
+
case "Bash":
|
|
269
|
+
case "Shell":
|
|
270
|
+
summary = input.command || "";
|
|
271
|
+
break;
|
|
272
|
+
case "Read":
|
|
273
|
+
case "Write":
|
|
274
|
+
summary = input.file_path || "";
|
|
275
|
+
break;
|
|
276
|
+
case "Edit":
|
|
277
|
+
summary = input.file_path ? `${input.file_path}` : "";
|
|
278
|
+
break;
|
|
279
|
+
case "Glob":
|
|
280
|
+
summary = input.pattern || "";
|
|
281
|
+
break;
|
|
282
|
+
case "Grep":
|
|
283
|
+
summary = `/${input.pattern || ""}/ in ${input.path || "."}`;
|
|
284
|
+
break;
|
|
285
|
+
case "WebSearch":
|
|
286
|
+
summary = input.query || "";
|
|
287
|
+
break;
|
|
288
|
+
case "WebFetch":
|
|
289
|
+
summary = input.url || "";
|
|
290
|
+
break;
|
|
291
|
+
default:
|
|
292
|
+
summary = JSON.stringify(input);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (summary.length > maxLen) summary = summary.slice(0, maxLen) + "...";
|
|
296
|
+
return summary;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ── HTML escaping ──
|
|
300
|
+
|
|
301
|
+
function escapeHtml(str) {
|
|
302
|
+
if (!str) return "";
|
|
303
|
+
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
304
|
+
}
|