@rubytech/create-maxy-code 0.1.282 → 0.1.283
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/package.json +1 -1
- package/payload/platform/config/brand.json +0 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -4
- package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +5 -5
- package/payload/platform/plugins/cloudflare/references/api.md +76 -37
- package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +27 -21
- package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +3 -2
- package/payload/platform/plugins/cloudflare/references/hosting-sites.md +7 -5
- package/payload/platform/plugins/cloudflare/references/manual-setup.md +3 -2
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +6 -6
- package/payload/platform/plugins/docs/references/telegram-guide.md +3 -3
- package/payload/platform/plugins/telegram/PLUGIN.md +7 -2
- package/payload/platform/plugins/telegram/mcp/dist/index.js +66 -11
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts +6 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js +20 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts +21 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js +52 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +5 -2
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -1
- package/payload/platform/plugins/telegram/references/setup-guide.md +10 -7
- package/payload/platform/plugins/telegram/skills/configure/SKILL.md +79 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +17 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/server/public/assets/AdminShell-8Y7-maNi.js +1 -0
- package/payload/server/public/assets/{admin-0_VxffD5.js → admin-DyuZ4NT5.js} +1 -1
- package/payload/server/public/assets/{browser-Cxjkhtsk.js → browser-XrVAUQdG.js} +1 -1
- package/payload/server/public/assets/{data-BOgwOWnw.js → data-tcu3MXmK.js} +1 -1
- package/payload/server/public/assets/{graph-BqD2GjQd.js → graph-I4GyC2MW.js} +1 -1
- package/payload/server/public/browser.html +2 -2
- package/payload/server/public/data.html +2 -2
- package/payload/server/public/graph.html +2 -2
- package/payload/server/public/index.html +2 -2
- package/payload/server/server.js +827 -531
- package/payload/server/public/assets/AdminShell-FO766lOW.js +0 -1
|
@@ -7,6 +7,7 @@ import { z } from "zod";
|
|
|
7
7
|
import { message } from "./tools/message.js";
|
|
8
8
|
import { messageHistory } from "./tools/message-history.js";
|
|
9
9
|
import { setWebhook, getWebhookInfo } from "./lib/telegram.js";
|
|
10
|
+
import { persistTelegramConfig, CANONICAL_TELEGRAM_PREFIX } from "./lib/account-write.js";
|
|
10
11
|
const server = new McpServer({
|
|
11
12
|
name: "maxy-messaging",
|
|
12
13
|
version: "0.1.0",
|
|
@@ -103,23 +104,26 @@ eagerTool(server, "message-history", "Query conversation history from the messag
|
|
|
103
104
|
import { homedir } from "node:os";
|
|
104
105
|
import { resolve, join } from "node:path";
|
|
105
106
|
import { existsSync, readFileSync } from "node:fs";
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
// The brand config-dir name (e.g. ".siteoffice-code"), read from brand.json.
|
|
108
|
+
// Falls back to ".maxy". Used for both the webhook-secret path and the
|
|
109
|
+
// op=token-write brand= log field.
|
|
110
|
+
function configDirName() {
|
|
110
111
|
const platformRoot = process.env.PLATFORM_ROOT;
|
|
111
112
|
if (platformRoot) {
|
|
112
113
|
const brandPath = join(platformRoot, "config", "brand.json");
|
|
113
114
|
if (existsSync(brandPath)) {
|
|
114
115
|
try {
|
|
115
|
-
|
|
116
|
-
if (brand.configDir)
|
|
117
|
-
configDirName = brand.configDir;
|
|
116
|
+
return JSON.parse(readFileSync(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
118
117
|
}
|
|
119
118
|
catch { /* fall back to .maxy */ }
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
|
-
|
|
121
|
+
return ".maxy";
|
|
122
|
+
}
|
|
123
|
+
// Derive the webhook secret file path (mirrors paths.ts logic).
|
|
124
|
+
// Restricted to known filenames — prevents path traversal.
|
|
125
|
+
function resolveSecretFilePath(botType) {
|
|
126
|
+
const maxyDir = resolve(homedir(), configDirName());
|
|
123
127
|
const filename = botType === "admin"
|
|
124
128
|
? ".telegram-admin-webhook-secret"
|
|
125
129
|
: ".telegram-webhook-secret";
|
|
@@ -127,10 +131,36 @@ function resolveSecretFilePath(botType) {
|
|
|
127
131
|
}
|
|
128
132
|
eagerTool(server, "telegram-webhook-register", "Register or re-register a Telegram bot webhook. Generates a cryptographic secret, persists it to disk, and passes it to the Telegram Bot API. Call this after obtaining a bot token from BotFather.", {
|
|
129
133
|
botToken: z.string().describe("Telegram bot token from BotFather"),
|
|
130
|
-
webhookUrl: z.string().url().describe("Full webhook URL
|
|
131
|
-
botType: z.enum(["public", "admin"]).describe("Bot type — determines which secret file
|
|
132
|
-
|
|
134
|
+
webhookUrl: z.string().url().describe("Full webhook URL; path MUST be under /api/telegram/ (the maxy edge-admitted path), with ?bot=public or ?bot=admin"),
|
|
135
|
+
botType: z.enum(["public", "admin"]).describe("Bot type — determines which secret file + which account.json token field"),
|
|
136
|
+
adminUsers: z.array(z.number()).optional().describe("Admin numeric user IDs (admin bot only)"),
|
|
137
|
+
dmPolicy: z.enum(["open", "allowlist", "disabled"]).optional().describe("DM policy (public bot only)"),
|
|
138
|
+
allowFrom: z.array(z.number()).optional().describe("Allowlisted numeric user IDs (public bot, allowlist policy)"),
|
|
139
|
+
}, async ({ botToken, webhookUrl, botType, adminUsers, dmPolicy, allowFrom }) => {
|
|
133
140
|
const secretFilePath = resolveSecretFilePath(botType);
|
|
141
|
+
// Assert the webhook path is the one canonical maxy edge-admitted path
|
|
142
|
+
// before touching Telegram. A /channels/telegram URL (the official plugin's
|
|
143
|
+
// path) is rejected at the maxy edge, so registering it would silently fail
|
|
144
|
+
// on the first inbound — fail loudly here instead.
|
|
145
|
+
const webhookPath = (() => {
|
|
146
|
+
try {
|
|
147
|
+
return new URL(webhookUrl).pathname;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return webhookUrl;
|
|
151
|
+
}
|
|
152
|
+
})();
|
|
153
|
+
const admitted = webhookPath.startsWith(CANONICAL_TELEGRAM_PREFIX);
|
|
154
|
+
console.error(`[telegram-setup] op=webhook-register path=${webhookPath} admitted=${admitted}`);
|
|
155
|
+
if (!admitted) {
|
|
156
|
+
return {
|
|
157
|
+
content: [{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: `Webhook path "${webhookPath}" is not under ${CANONICAL_TELEGRAM_PREFIX} — the maxy edge will reject it. Use a URL whose path starts with ${CANONICAL_TELEGRAM_PREFIX}`,
|
|
160
|
+
}],
|
|
161
|
+
isError: true,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
134
164
|
try {
|
|
135
165
|
// Verify the token is valid by calling getMe
|
|
136
166
|
const meRes = await fetch(`https://api.telegram.org/bot${botToken}/getMe`);
|
|
@@ -160,6 +190,31 @@ eagerTool(server, "telegram-webhook-register", "Register or re-register a Telegr
|
|
|
160
190
|
isError: true,
|
|
161
191
|
};
|
|
162
192
|
}
|
|
193
|
+
// Persist the bot token + access policy into account.json's telegram
|
|
194
|
+
// block — the per-account, brand-isolated store the inbound receiver and
|
|
195
|
+
// the message tool both read. Assert the resolved dir is under the brand
|
|
196
|
+
// install (never ~/.claude) before claiming success.
|
|
197
|
+
const platformRoot = process.env.PLATFORM_ROOT;
|
|
198
|
+
const accountId = process.env.ACCOUNT_ID;
|
|
199
|
+
if (!platformRoot || !accountId) {
|
|
200
|
+
console.error(`[telegram-setup] op=token-write-rejected reason=no-account-env`);
|
|
201
|
+
return {
|
|
202
|
+
content: [{ type: "text", text: `PLATFORM_ROOT/ACCOUNT_ID not in MCP env — cannot persist the bot token to account.json` }],
|
|
203
|
+
isError: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// persistTelegramConfig asserts the resolved dir is under the brand
|
|
207
|
+
// install BEFORE writing (non-brand-path is rejected, not written), so a
|
|
208
|
+
// failure here means nothing was persisted.
|
|
209
|
+
const persisted = persistTelegramConfig(platformRoot, accountId, { botType, botToken, adminUsers, dmPolicy, allowFrom });
|
|
210
|
+
if (!persisted.ok) {
|
|
211
|
+
console.error(`[telegram-setup] op=token-write-rejected reason=${persisted.error}${persisted.dir ? ` dir=${persisted.dir}` : ""}`);
|
|
212
|
+
const text = persisted.error === "non-brand-path"
|
|
213
|
+
? `Refusing to write token outside the brand install: ${persisted.dir}`
|
|
214
|
+
: `Token persist failed: ${persisted.error}`;
|
|
215
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
216
|
+
}
|
|
217
|
+
console.error(`[telegram-setup] op=token-write dir=${persisted.dir} brand=${configDirName()}`);
|
|
163
218
|
// Verify registration — guarded because getWebhookInfo can fail
|
|
164
219
|
// independently of a successful registration (e.g., transient API error).
|
|
165
220
|
let verifyInfo = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAC7E,aAAa,CAAC,UAAU,CAAC,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Resolve the Telegram bot token from the per-account account.json telegram
|
|
2
|
+
* block. Brand-isolated: account.json lives under the install's data/accounts,
|
|
3
|
+
* never ~/.claude. Prefers adminBotToken (the admin agent's outbound bot),
|
|
4
|
+
* falling back to publicBotToken. Returns null when neither is present. */
|
|
5
|
+
export declare function resolveBotToken(platformRoot: string, accountId: string): string | null;
|
|
6
|
+
//# sourceMappingURL=account-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-token.d.ts","sourceRoot":"","sources":["../../src/lib/account-token.ts"],"names":[],"mappings":"AAGA;;;4EAG4E;AAC5E,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYtF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { resolve, join } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
/** Resolve the Telegram bot token from the per-account account.json telegram
|
|
4
|
+
* block. Brand-isolated: account.json lives under the install's data/accounts,
|
|
5
|
+
* never ~/.claude. Prefers adminBotToken (the admin agent's outbound bot),
|
|
6
|
+
* falling back to publicBotToken. Returns null when neither is present. */
|
|
7
|
+
export function resolveBotToken(platformRoot, accountId) {
|
|
8
|
+
const accountsDir = resolve(platformRoot, "..", "data", "accounts");
|
|
9
|
+
const configPath = join(accountsDir, accountId, "account.json");
|
|
10
|
+
if (!existsSync(configPath))
|
|
11
|
+
return null;
|
|
12
|
+
try {
|
|
13
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
14
|
+
return config.telegram?.adminBotToken ?? config.telegram?.publicBotToken ?? null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=account-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-token.js","sourceRoot":"","sources":["../../src/lib/account-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEnD;;;4EAG4E;AAC5E,MAAM,UAAU,eAAe,CAAC,YAAoB,EAAE,SAAiB;IACrE,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAChE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAE1D,CAAC;QACF,OAAO,MAAM,CAAC,QAAQ,EAAE,aAAa,IAAI,MAAM,CAAC,QAAQ,EAAE,cAAc,IAAI,IAAI,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** The single canonical maxy Telegram webhook path. Duplicated (intentionally)
|
|
2
|
+
* with platform/ui/server/public-host-gate.ts PUBLIC_ALLOWED_PREFIXES — a unit
|
|
3
|
+
* test asserts they agree. The official plugin's /channels/telegram is NOT this. */
|
|
4
|
+
export declare const CANONICAL_TELEGRAM_PREFIX = "/api/telegram/";
|
|
5
|
+
export interface PersistInput {
|
|
6
|
+
botType: "admin" | "public";
|
|
7
|
+
botToken: string;
|
|
8
|
+
adminUsers?: number[];
|
|
9
|
+
dmPolicy?: "open" | "allowlist" | "disabled";
|
|
10
|
+
allowFrom?: number[];
|
|
11
|
+
}
|
|
12
|
+
/** Persist the bot token + access policy into account.json's telegram block.
|
|
13
|
+
* Brand-isolated: account.json lives under the install's data/accounts. Returns
|
|
14
|
+
* the resolved account.json directory so the caller can log + assert it is under
|
|
15
|
+
* the brand install (never ~/.claude). */
|
|
16
|
+
export declare function persistTelegramConfig(platformRoot: string, accountId: string, input: PersistInput): {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
dir?: string;
|
|
19
|
+
error?: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=account-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-write.d.ts","sourceRoot":"","sources":["../../src/lib/account-write.ts"],"names":[],"mappings":"AAGA;;qFAEqF;AACrF,eAAO,MAAM,yBAAyB,mBAAmB,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;2CAG2C;AAC3C,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,YAAY,GAClB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAmC/C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolve, join, relative, isAbsolute } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
/** The single canonical maxy Telegram webhook path. Duplicated (intentionally)
|
|
4
|
+
* with platform/ui/server/public-host-gate.ts PUBLIC_ALLOWED_PREFIXES — a unit
|
|
5
|
+
* test asserts they agree. The official plugin's /channels/telegram is NOT this. */
|
|
6
|
+
export const CANONICAL_TELEGRAM_PREFIX = "/api/telegram/";
|
|
7
|
+
/** Persist the bot token + access policy into account.json's telegram block.
|
|
8
|
+
* Brand-isolated: account.json lives under the install's data/accounts. Returns
|
|
9
|
+
* the resolved account.json directory so the caller can log + assert it is under
|
|
10
|
+
* the brand install (never ~/.claude). */
|
|
11
|
+
export function persistTelegramConfig(platformRoot, accountId, input) {
|
|
12
|
+
const accountsDir = resolve(platformRoot, "..", "data", "accounts");
|
|
13
|
+
const dir = join(accountsDir, accountId);
|
|
14
|
+
const configPath = join(dir, "account.json");
|
|
15
|
+
// Assert the resolved dir is under the brand install BEFORE any write — a
|
|
16
|
+
// traversal in accountId (e.g. "../../.claude") must never let a token land
|
|
17
|
+
// outside ~/.<brand>/. `relative` is separator-aware; a non-brand path yields
|
|
18
|
+
// a result that escapes ("..") or is absolute.
|
|
19
|
+
const brandRoot = resolve(platformRoot, "..");
|
|
20
|
+
const rel = relative(brandRoot, resolve(dir));
|
|
21
|
+
const underBrand = rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
22
|
+
if (!underBrand) {
|
|
23
|
+
return { ok: false, error: "non-brand-path", dir };
|
|
24
|
+
}
|
|
25
|
+
if (!existsSync(configPath)) {
|
|
26
|
+
return { ok: false, error: `account.json not found at ${configPath}` };
|
|
27
|
+
}
|
|
28
|
+
let config;
|
|
29
|
+
try {
|
|
30
|
+
config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
return { ok: false, error: `account.json parse failed: ${e.message}` };
|
|
34
|
+
}
|
|
35
|
+
const telegram = config.telegram ?? {};
|
|
36
|
+
if (input.botType === "admin") {
|
|
37
|
+
telegram.adminBotToken = input.botToken;
|
|
38
|
+
if (input.adminUsers)
|
|
39
|
+
telegram.adminUsers = input.adminUsers;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
telegram.publicBotToken = input.botToken;
|
|
43
|
+
if (input.dmPolicy)
|
|
44
|
+
telegram.dmPolicy = input.dmPolicy;
|
|
45
|
+
if (input.allowFrom)
|
|
46
|
+
telegram.allowFrom = input.allowFrom;
|
|
47
|
+
}
|
|
48
|
+
config.telegram = telegram;
|
|
49
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
50
|
+
return { ok: true, dir };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=account-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-write.js","sourceRoot":"","sources":["../../src/lib/account-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAElE;;qFAEqF;AACrF,MAAM,CAAC,MAAM,yBAAyB,GAAG,gBAAgB,CAAC;AAU1D;;;2CAG2C;AAC3C,MAAM,UAAU,qBAAqB,CACnC,YAAoB,EACpB,SAAiB,EACjB,KAAmB;IAEnB,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,4EAA4E;IAC5E,8EAA8E;IAC9E,+CAA+C;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,UAAU,EAAE,EAAE,CAAC;IACzE,CAAC;IACD,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA+B,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC;IACpF,CAAC;IACD,MAAM,QAAQ,GAAI,MAAM,CAAC,QAAoC,IAAI,EAAE,CAAC;IACpE,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC9B,QAAQ,CAAC,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC;QACxC,IAAI,KAAK,CAAC,UAAU;YAAE,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAC/D,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,cAAc,GAAG,KAAK,CAAC,QAAQ,CAAC;QACzC,IAAI,KAAK,CAAC,QAAQ;YAAE,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QACvD,IAAI,KAAK,CAAC,SAAS;YAAE,QAAQ,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAC5D,CAAC;IACD,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/C,cAAc,CAAC,EAAE,KAAK,CACpB,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAC7D,CAAC;CACH;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAwC3E"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { sendMessage } from "../lib/telegram.js";
|
|
2
|
+
import { resolveBotToken } from "../lib/account-token.js";
|
|
2
3
|
export async function message(params) {
|
|
3
|
-
const
|
|
4
|
+
const platformRoot = process.env.PLATFORM_ROOT;
|
|
5
|
+
const accountId = process.env.ACCOUNT_ID;
|
|
6
|
+
const botToken = platformRoot && accountId ? resolveBotToken(platformRoot, accountId) : null;
|
|
4
7
|
if (!botToken) {
|
|
5
8
|
return {
|
|
6
9
|
sent: false,
|
|
7
10
|
channel: params.channel,
|
|
8
|
-
error: "
|
|
11
|
+
error: "No Telegram bot token in account.json telegram block — run telegram:configure first",
|
|
9
12
|
};
|
|
10
13
|
}
|
|
11
14
|
let replyMarkup;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA+B,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/tools/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA+B,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAmB1D,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAAqB;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACzC,MAAM,QAAQ,GACZ,YAAY,IAAI,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9E,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EACH,qFAAqF;SACxF,CAAC;IACJ,CAAC;IAED,IAAI,WAA+C,CAAC;IACpD,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,WAAW,GAAG;YACZ,eAAe,EAAE,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACjD,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAChB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,aAAa,EAAE,GAAG,CAAC,YAAY;gBAC/B,GAAG,EAAE,GAAG,CAAC,GAAG;aACb,CAAC,CAAC,CACJ;SACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW;KACZ,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,EAAE;QACf,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
## Connecting the Bot
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
Setup happens entirely in the admin chat — there is no settings page to click through.
|
|
14
|
+
|
|
15
|
+
1. Tell the admin agent: "I want to connect a Telegram bot." The agent runs the `telegram:configure` skill.
|
|
16
|
+
2. Paste the bot token from BotFather when the agent asks.
|
|
17
|
+
3. Tell the agent whether this is an **admin bot** or a **public bot** (see below).
|
|
18
|
+
4. For an admin bot, give the agent the numeric Telegram user IDs that should have admin access. For a public bot, choose a DM policy (who can message it) and, for a whitelist, the allowed numeric IDs.
|
|
19
|
+
5. The agent verifies the token, registers the webhook on the brand's edge path, stores the token under the brand install, and — for a public bot — sets the agent that will respond.
|
|
20
|
+
6. The agent confirms the bot is connected. Message the bot; the reply comes back from the agent.
|
|
21
|
+
|
|
22
|
+
The token is stored in your account config under the brand install (never in a shared `~/.claude` directory), and the webhook is registered on the `/api/telegram/` path the brand's edge admits.
|
|
20
23
|
|
|
21
24
|
## Admin Bot vs Public Bot
|
|
22
25
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: configure
|
|
3
|
+
description: Guide the user through connecting a Telegram bot entirely via the admin chat — store the BotFather token under the brand install, register the webhook on the maxy edge-admitted path, set access policy, and select the agent. Complete PTY setup, no UI clicks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Configure Telegram
|
|
7
|
+
|
|
8
|
+
Invoked from `specialists:personal-assistant`. This is the maxy `telegram:configure` skill. On `-code` brands the upstream `claude-plugins-official/telegram` plugin is not installed, so this is the only `telegram:configure` — it is brand-aware and PTY-only.
|
|
9
|
+
|
|
10
|
+
## When to activate
|
|
11
|
+
|
|
12
|
+
User says anything about connecting, linking, or setting up Telegram, BotFather, or a Telegram bot.
|
|
13
|
+
|
|
14
|
+
## What a correct setup looks like
|
|
15
|
+
|
|
16
|
+
A finished Telegram setup has all of these, and the skill is not done until each is true:
|
|
17
|
+
|
|
18
|
+
- The bot token from BotFather is stored in `account.json`'s `telegram` block (under the brand install, never `~/.claude/`). The `telegram-webhook-register` tool writes it there and logs `[telegram-setup] op=token-write dir=… brand=…`.
|
|
19
|
+
- The webhook is registered against a URL whose path is `/api/telegram/` (the only path the maxy edge admits). The register tool refuses any other path and logs `op=webhook-register path=… admitted=false` when it does.
|
|
20
|
+
- Access policy is set: admin bots carry the operator's numeric Telegram user IDs (`adminUsers`); public bots carry a DM policy (and an allowlist when the policy is `allowlist`).
|
|
21
|
+
- For a public bot, `account.json` `defaultAgent` names an existing public agent. Without it, public inbound is dropped with `op=reject reason=no-default-agent`.
|
|
22
|
+
|
|
23
|
+
## Flow
|
|
24
|
+
|
|
25
|
+
### Step 1 — Get the bot token
|
|
26
|
+
|
|
27
|
+
Follow `references/setup-guide.md` "Creating a Bot": the operator creates the bot via @BotFather and gives you the token (e.g. `123456:ABC-DEF…`). Confirm you have it before continuing.
|
|
28
|
+
|
|
29
|
+
### Step 2 — Decide admin or public
|
|
30
|
+
|
|
31
|
+
Ask which role this bot serves (see `references/setup-guide.md` "Admin Bot vs Public Bot"):
|
|
32
|
+
|
|
33
|
+
- **Admin bot** — only the operator's numeric Telegram user IDs may message it; everything else is denied. Collect those IDs (`references/setup-guide.md` "Finding Your Telegram User ID").
|
|
34
|
+
- **Public bot** — customer-facing; choose a DM policy (`open`, `allowlist`, or `disabled`) and, for `allowlist`, the allowed numeric IDs.
|
|
35
|
+
|
|
36
|
+
### Step 3 — Build the webhook URL
|
|
37
|
+
|
|
38
|
+
The path MUST be `/api/telegram/` with `?bot=admin` or `?bot=public`. Use the account's domain for the host — the admin domain for an admin bot, the public domain for a public bot (read them from `brand-settings` / the account config). Example: `https://<admin-domain>/api/telegram/?bot=admin`.
|
|
39
|
+
|
|
40
|
+
The register tool aborts on any other path, so do not invent `/channels/telegram` or similar.
|
|
41
|
+
|
|
42
|
+
### Step 4 — Register (stores token + policy + webhook + secret in one call)
|
|
43
|
+
|
|
44
|
+
Call `telegram-webhook-register` with:
|
|
45
|
+
- `botToken` — the BotFather token
|
|
46
|
+
- `webhookUrl` — the URL from Step 3
|
|
47
|
+
- `botType` — `admin` or `public`
|
|
48
|
+
- admin bot: `adminUsers` — the numeric IDs from Step 2
|
|
49
|
+
- public bot: `dmPolicy` and, for `allowlist`, `allowFrom`
|
|
50
|
+
|
|
51
|
+
On success the tool has: verified the token, set the webhook with a generated secret (written to the brand configDir), persisted the token + policy into `account.json`'s `telegram` block, and logged `op=token-write` + `op=webhook-register admitted=true`. If it returns an error, read it back to the operator verbatim — the common ones are a wrong path (`admitted=false`) or a token write blocked outside the brand install (`op=token-write-rejected`).
|
|
52
|
+
|
|
53
|
+
### Step 5 — Select the agent (public bot)
|
|
54
|
+
|
|
55
|
+
Public inbound routes to the account's `defaultAgent`. Set it and confirm:
|
|
56
|
+
|
|
57
|
+
1. `account-manage` to list available public agents.
|
|
58
|
+
2. `account-update` with `field: "defaultAgent"`, `value: "<slug>"`.
|
|
59
|
+
3. Re-read by calling `account-manage` (or `account-update` reports the change) and confirm `defaultAgent` is the chosen slug. The post-condition is a non-empty `defaultAgent`, not the intent to set it.
|
|
60
|
+
|
|
61
|
+
An admin bot does not need `defaultAgent` — admin inbound routes to the admin agent.
|
|
62
|
+
|
|
63
|
+
### Step 6 — Confirm
|
|
64
|
+
|
|
65
|
+
Tell the operator the bot is connected, which role it has, and that messaging the bot now reaches the agent and a reply returns. For a public bot, name the agent that will respond.
|
|
66
|
+
|
|
67
|
+
## Failure modes (state these loudly, do not paper over)
|
|
68
|
+
|
|
69
|
+
- **Wrong webhook path** — register returns an error and logs `op=webhook-register admitted=false`. Fix the URL to use `/api/telegram/`.
|
|
70
|
+
- **Token write outside the brand** — `op=token-write-rejected reason=non-brand-path`. The MCP env is misconfigured; do not retry blindly — report it.
|
|
71
|
+
- **`defaultAgent` unset on a public bot** — inbound is dropped with `[telegram-inbound] op=reject reason=no-default-agent`. Complete Step 5.
|
|
72
|
+
- **Bad secret on inbound** — `[telegram-inbound] op=reject reason=bad-secret` means the registered secret and the stored secret diverged; re-run register.
|
|
73
|
+
|
|
74
|
+
## Language
|
|
75
|
+
|
|
76
|
+
Use plain English:
|
|
77
|
+
- "bot token" not "Bot API credential"
|
|
78
|
+
- "your numeric Telegram ID" not "user_id integer"
|
|
79
|
+
- "the bot is connected" not "webhook registered with secret_token"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,OAAO,EAgBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAoBzB,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAA;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAgFtD,eAAO,MAAM,kBAAkB,QAA2B,CAAA;AAS1D,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAIlD,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC7E;;qEAEiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;IAC9B;kFAC8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AA+MD;;;kEAGkE;AAClE,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG;IAC3B,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACpD;;;+CAG2C;IAC3C,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAChD,CAAA;AAmBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,OAAO,EAgBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAoBzB,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAA;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAgFtD,eAAO,MAAM,kBAAkB,QAA2B,CAAA;AAS1D,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAIlD,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC7E;;qEAEiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;IAC9B;kFAC8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AA+MD;;;kEAGkE;AAClE,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG;IAC3B,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACpD;;;+CAG2C;IAC3C,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAChD,CAAA;AAmBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAo4DpD"}
|
|
@@ -1551,6 +1551,23 @@ export function buildHttpApp(deps) {
|
|
|
1551
1551
|
if (mainPid !== null && defaultProcessSignals.isAlive(mainPid))
|
|
1552
1552
|
seen.set(row.sessionId, mainPid);
|
|
1553
1553
|
}
|
|
1554
|
+
// Task 731 — a live, non-detached row whose owned PTY tracker has been
|
|
1555
|
+
// released (or was registered under a placeholder sessionId, never the
|
|
1556
|
+
// real one) is counted by the master-reconcile `liveSessions` census yet
|
|
1557
|
+
// missed by both arms above: it is not an owned PTY and not a detached
|
|
1558
|
+
// survivor. Adopt it on PID-file process truth — `row.pid` is claude's own
|
|
1559
|
+
// live pid for a `state==='live'` row — gated on `isAlive` so a stale PID
|
|
1560
|
+
// file (dead process) never reports a false-green dot. Detached rows are
|
|
1561
|
+
// excluded here on purpose: their liveness is the scope MainPID (resolved
|
|
1562
|
+
// above) and their `row.pid` may be a stale manager-side pid.
|
|
1563
|
+
for (const row of deps.watcher.all()) {
|
|
1564
|
+
if (row.state !== 'live' || row.status === 'detached' || seen.has(row.sessionId) || row.pid === null)
|
|
1565
|
+
continue;
|
|
1566
|
+
if (defaultProcessSignals.isAlive(row.pid)) {
|
|
1567
|
+
seen.set(row.sessionId, row.pid);
|
|
1568
|
+
deps.logger(`[live-sessions] op=adopt-orphan-live sessionId=${row.sessionId.slice(0, 8)} pid=${row.pid} via=reconcile`);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1554
1571
|
const sessions = [...seen.entries()].map(([sessionId, pid]) => ({ sessionId, pid }));
|
|
1555
1572
|
return c.json({ sessions });
|
|
1556
1573
|
});
|