openclaw-telegram-manager 1.3.0 → 1.3.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 (44) hide show
  1. package/dist/lib/include-generator.d.ts +1 -1
  2. package/dist/lib/include-generator.d.ts.map +1 -1
  3. package/dist/lib/include-generator.js +33 -2
  4. package/dist/lib/include-generator.js.map +1 -1
  5. package/dist/plugin.js +29 -2
  6. package/dist/setup.js +33 -15
  7. package/dist/setup.js.map +1 -1
  8. package/package.json +2 -3
  9. package/src/commands/archive.ts +0 -89
  10. package/src/commands/doctor-all.ts +0 -243
  11. package/src/commands/doctor.ts +0 -100
  12. package/src/commands/help.ts +0 -11
  13. package/src/commands/init.ts +0 -376
  14. package/src/commands/list.ts +0 -28
  15. package/src/commands/rename.ts +0 -140
  16. package/src/commands/snooze.ts +0 -69
  17. package/src/commands/status.ts +0 -59
  18. package/src/commands/sync.ts +0 -46
  19. package/src/commands/upgrade.ts +0 -64
  20. package/src/index.ts +0 -91
  21. package/src/lib/audit.ts +0 -44
  22. package/src/lib/auth.ts +0 -96
  23. package/src/lib/capsule.ts +0 -206
  24. package/src/lib/config-restart.ts +0 -167
  25. package/src/lib/doctor-checks.ts +0 -639
  26. package/src/lib/include-generator.ts +0 -174
  27. package/src/lib/registry.ts +0 -197
  28. package/src/lib/security.ts +0 -174
  29. package/src/lib/telegram.ts +0 -311
  30. package/src/lib/types.ts +0 -172
  31. package/src/setup.ts +0 -475
  32. package/src/templates/base/COMMANDS.md +0 -3
  33. package/src/templates/base/CRON.md +0 -3
  34. package/src/templates/base/LINKS.md +0 -3
  35. package/src/templates/base/NOTES.md +0 -3
  36. package/src/templates/base/README.md +0 -3
  37. package/src/templates/base/TODO.md +0 -11
  38. package/src/templates/overlays/coding/ARCHITECTURE.md +0 -3
  39. package/src/templates/overlays/coding/DEPLOY.md +0 -3
  40. package/src/templates/overlays/marketing/CAMPAIGNS.md +0 -3
  41. package/src/templates/overlays/marketing/METRICS.md +0 -3
  42. package/src/templates/overlays/research/FINDINGS.md +0 -3
  43. package/src/templates/overlays/research/SOURCES.md +0 -3
  44. package/src/tool.ts +0 -282
package/src/setup.ts DELETED
@@ -1,475 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import * as fs from 'node:fs';
4
- import * as path from 'node:path';
5
- import * as crypto from 'node:crypto';
6
- import { execSync } from 'node:child_process';
7
-
8
- // ── Constants ──────────────────────────────────────────────────────────
9
-
10
- const PLUGIN_NAME = 'openclaw-telegram-manager';
11
- const PLUGIN_VERSION: string = JSON.parse(
12
- fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'),
13
- ).version;
14
- const MIN_OPENCLAW_VERSION = '2026.1.0';
15
- const INCLUDE_FILENAME = 'telegram-manager.generated.groups.json5';
16
- const REGISTRY_FILENAME = 'topics.json';
17
- const PLUGIN_FILES = ['openclaw.plugin.json', 'dist/plugin.js', 'skills', 'package.json'];
18
-
19
- // ── Colors (zero dependencies, respects NO_COLOR / non-TTY) ──────────
20
-
21
- const useColor =
22
- process.stdout.isTTY === true &&
23
- !process.env['NO_COLOR'] &&
24
- process.env['TERM'] !== 'dumb';
25
-
26
- const c = {
27
- reset: useColor ? '\x1b[0m' : '',
28
- bold: useColor ? '\x1b[1m' : '',
29
- dim: useColor ? '\x1b[2m' : '',
30
- green: useColor ? '\x1b[32m' : '',
31
- yellow: useColor ? '\x1b[33m' : '',
32
- red: useColor ? '\x1b[31m' : '',
33
- cyan: useColor ? '\x1b[36m' : '',
34
- magenta: useColor ? '\x1b[35m' : '',
35
- };
36
-
37
- // ── Spinner (zero dependencies, TTY-only) ────────────────────────────
38
-
39
- let spinnerTimer: ReturnType<typeof setInterval> | null = null;
40
-
41
- function startSpinner(msg: string): void {
42
- stopSpinner();
43
- if (!process.stdout.isTTY) return;
44
- const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
45
- let i = 0;
46
- const render = () => {
47
- process.stdout.write(`\r ${c.cyan}${frames[i++ % frames.length]}${c.reset} ${msg}`);
48
- };
49
- render();
50
- spinnerTimer = setInterval(render, 80);
51
- }
52
-
53
- function stopSpinner(): void {
54
- if (spinnerTimer) {
55
- clearInterval(spinnerTimer);
56
- spinnerTimer = null;
57
- process.stdout.write('\r\x1b[2K');
58
- }
59
- }
60
-
61
- // ── Logging helpers ───────────────────────────────────────────────────
62
-
63
- function ok(msg: string): void {
64
- stopSpinner();
65
- console.log(` ${c.green}✓${c.reset} ${msg}`);
66
- }
67
- function warn(msg: string): void {
68
- stopSpinner();
69
- console.warn(` ${c.yellow}⚠${c.reset} ${c.yellow}${msg}${c.reset}`);
70
- }
71
- function fail(msg: string): void {
72
- stopSpinner();
73
- console.error(` ${c.red}✗${c.reset} ${c.red}${msg}${c.reset}`);
74
- }
75
- function info(msg: string): void {
76
- console.log(` ${c.dim}${msg}${c.reset}`);
77
- }
78
-
79
- function banner(title: string, subtitle?: string): void {
80
- console.log('');
81
- console.log(` ${c.cyan}◆${c.reset} ${c.bold}${title}${c.reset}${subtitle ? ` ${c.dim}${subtitle}${c.reset}` : ''}`);
82
- console.log(` ${c.dim}│${c.reset}`);
83
- }
84
-
85
- function footer(msg: string): void {
86
- console.log(` ${c.dim}│${c.reset}`);
87
- console.log(` ${c.green}◆${c.reset} ${c.bold}${msg}${c.reset}`);
88
- console.log('');
89
- }
90
-
91
- // ── Entry point ───────────────────────────────────────────────────────
92
-
93
- const command = process.argv[2] ?? 'setup';
94
-
95
- if (command === 'setup') {
96
- runSetup().catch((err) => {
97
- stopSpinner();
98
- console.error('Setup failed:', err instanceof Error ? err.message : String(err));
99
- process.exit(1);
100
- });
101
- } else if (command === 'uninstall') {
102
- runUninstall().catch((err) => {
103
- stopSpinner();
104
- console.error('Uninstall failed:', err instanceof Error ? err.message : String(err));
105
- process.exit(1);
106
- });
107
- } else {
108
- console.error(`Unknown command: ${command}`);
109
- console.error(`Usage: ${PLUGIN_NAME} [setup|uninstall]`);
110
- process.exit(1);
111
- }
112
-
113
- // ── Setup ─────────────────────────────────────────────────────────────
114
-
115
- async function runSetup(): Promise<void> {
116
- banner(PLUGIN_NAME, `v${PLUGIN_VERSION}`);
117
-
118
- startSpinner('Checking OpenClaw version…');
119
- const version = checkOpenClawVersion();
120
- ok(`OpenClaw ${c.dim}${version}${c.reset}`);
121
-
122
- startSpinner('Locating config…');
123
- const configDir = locateConfigDir();
124
- checkDirPermissions(configDir);
125
- ok(`Config ${c.dim}${configDir}${c.reset}`);
126
-
127
- startSpinner('Installing plugin…');
128
- installPlugin(configDir);
129
-
130
- startSpinner('Patching config…');
131
- patchConfig(configDir);
132
-
133
- startSpinner('Preparing workspace…');
134
- const projectsDir = path.join(configDir, 'workspace', 'projects');
135
- ensureDir(projectsDir);
136
- initRegistry(projectsDir);
137
- createEmptyInclude(configDir);
138
- ok('Workspace ready');
139
-
140
- startSpinner('Restarting gateway…');
141
- triggerRestart();
142
- ok('Gateway restarted');
143
-
144
- footer('Setup complete');
145
-
146
- console.log(` ${c.dim}Next steps:${c.reset}`);
147
- console.log(` ${c.dim}1.${c.reset} Open any Telegram forum topic`);
148
- console.log(` ${c.dim}2.${c.reset} Type ${c.cyan}/topic init${c.reset}`);
149
- console.log(` ${c.dim}3.${c.reset} The topic will be registered and a capsule created`);
150
- console.log('');
151
- }
152
-
153
- // ── Uninstall ─────────────────────────────────────────────────────────
154
-
155
- async function runUninstall(): Promise<void> {
156
- banner(PLUGIN_NAME, 'uninstall');
157
-
158
- startSpinner('Locating config…');
159
- const configDir = locateConfigDir();
160
- ok(`Config ${c.dim}${configDir}${c.reset}`);
161
-
162
- startSpinner('Removing plugin…');
163
- unpatchConfig(configDir);
164
- removeFile(path.join(configDir, INCLUDE_FILENAME));
165
- removePluginDir(configDir);
166
- ok('Plugin files removed');
167
-
168
- startSpinner('Restarting gateway…');
169
- triggerRestart();
170
- ok('Gateway restarted');
171
-
172
- const projectsDir = path.join(configDir, 'workspace', 'projects');
173
- if (fs.existsSync(projectsDir)) {
174
- info('Workspace data kept: ' + projectsDir);
175
- info('To remove: rm -rf ' + projectsDir);
176
- }
177
-
178
- footer('Uninstall complete');
179
- }
180
-
181
- // ── Setup step implementations ────────────────────────────────────────
182
-
183
- function checkOpenClawVersion(): string {
184
- let version: string;
185
- try {
186
- version = execSync('openclaw --version', { encoding: 'utf-8' }).trim();
187
- } catch {
188
- fail('OpenClaw not found. Install OpenClaw (>=2026.1.0) first.');
189
- process.exit(1);
190
- }
191
-
192
- const match = version.match(/(\d+\.\d+\.\d+)/);
193
- if (!match) {
194
- warn(`Could not parse version from "${version}". Proceeding anyway.`);
195
- return version;
196
- }
197
-
198
- const versionStr = match[1]!;
199
- if (compareVersions(versionStr, MIN_OPENCLAW_VERSION) < 0) {
200
- fail(`OpenClaw ${versionStr} found, requires >=${MIN_OPENCLAW_VERSION}. Please upgrade.`);
201
- process.exit(1);
202
- }
203
-
204
- return versionStr;
205
- }
206
-
207
- function locateConfigDir(): string {
208
- const envDir = process.env['OPENCLAW_CONFIG_DIR'];
209
- if (envDir && fs.existsSync(envDir)) {
210
- return path.resolve(envDir);
211
- }
212
-
213
- const homeDir = process.env['HOME'] ?? process.env['USERPROFILE'] ?? '';
214
- const defaultDir = path.join(homeDir, '.openclaw');
215
- if (fs.existsSync(defaultDir)) {
216
- return defaultDir;
217
- }
218
-
219
- let dir = process.cwd();
220
- while (dir !== path.dirname(dir)) {
221
- if (fs.existsSync(path.join(dir, 'openclaw.json'))) {
222
- return dir;
223
- }
224
- dir = path.dirname(dir);
225
- }
226
-
227
- fail('Could not find OpenClaw config directory. Set $OPENCLAW_CONFIG_DIR or ensure ~/.openclaw/ exists.');
228
- process.exit(1);
229
- }
230
-
231
- function checkDirPermissions(dir: string): void {
232
- try {
233
- const stat = fs.statSync(dir);
234
- const mode = stat.mode;
235
- const permissions = (mode & 0o777).toString(8);
236
-
237
- if (mode & 0o002) {
238
- warn(`${dir} is world-writable (${permissions}). Consider chmod 700.`);
239
- } else if (mode & 0o020) {
240
- warn(`${dir} is group-writable (${permissions}). Consider chmod 700.`);
241
- }
242
- } catch {
243
- warn(`Could not check permissions for ${dir}.`);
244
- }
245
- }
246
-
247
- function installPlugin(configDir: string): void {
248
- const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
249
-
250
- if (fs.existsSync(path.join(extDir, 'openclaw.plugin.json'))) {
251
- ok('Plugin already installed');
252
- return;
253
- }
254
-
255
- const pkgRoot = findPackageRoot();
256
- if (pkgRoot) {
257
- fs.mkdirSync(extDir, { recursive: true });
258
- for (const entry of PLUGIN_FILES) {
259
- const src = path.join(pkgRoot, entry);
260
- if (!fs.existsSync(src)) continue;
261
- const dest = path.join(extDir, entry);
262
- fs.mkdirSync(path.dirname(dest), { recursive: true });
263
- copyRecursive(src, dest);
264
- }
265
- ok('Plugin installed');
266
- return;
267
- }
268
-
269
- try {
270
- execSync(`openclaw plugins install ${PLUGIN_NAME}`, {
271
- encoding: 'utf-8',
272
- stdio: 'inherit',
273
- });
274
- ok('Plugin installed');
275
- } catch {
276
- warn('Could not install plugin. You may need to install manually.');
277
- }
278
- }
279
-
280
- function patchConfig(configDir: string): void {
281
- const configPath = path.join(configDir, 'openclaw.json');
282
-
283
- if (!fs.existsSync(configPath)) {
284
- warn(`${configPath} not found. Skipping config patch.`);
285
- return;
286
- }
287
-
288
- let content: string;
289
- try {
290
- content = fs.readFileSync(configPath, 'utf-8');
291
- } catch {
292
- warn(`Could not read ${configPath}. Skipping config patch.`);
293
- return;
294
- }
295
-
296
- if (content.includes(INCLUDE_FILENAME)) {
297
- ok('Config already patched');
298
- return;
299
- }
300
-
301
- let config: Record<string, unknown>;
302
- try {
303
- config = JSON.parse(content) as Record<string, unknown>;
304
- } catch {
305
- warn('Could not parse openclaw.json. Please manually add the $include reference.');
306
- info(`Add to channels.telegram.groups: { "$include": "./${INCLUDE_FILENAME}" }`);
307
- return;
308
- }
309
-
310
- if (!config['channels']) config['channels'] = {};
311
- const channels = config['channels'] as Record<string, unknown>;
312
-
313
- if (!channels['telegram']) channels['telegram'] = {};
314
- const telegram = channels['telegram'] as Record<string, unknown>;
315
-
316
- telegram['groups'] = { $include: `./${INCLUDE_FILENAME}` };
317
-
318
- const bakPath = configPath + '.bak';
319
- fs.copyFileSync(configPath, bakPath);
320
-
321
- const newContent = JSON.stringify(config, null, 2) + '\n';
322
- fs.writeFileSync(configPath, newContent, { mode: 0o600 });
323
- ok('Config patched');
324
- }
325
-
326
- function initRegistry(projectsDir: string): void {
327
- const registryPath = path.join(projectsDir, REGISTRY_FILENAME);
328
-
329
- if (fs.existsSync(registryPath)) {
330
- return;
331
- }
332
-
333
- const callbackSecret = crypto.randomBytes(32).toString('hex');
334
- const registry = {
335
- version: 1,
336
- topicManagerAdmins: [],
337
- callbackSecret,
338
- lastDoctorAllRunAt: null,
339
- maxTopics: 100,
340
- topics: {},
341
- };
342
-
343
- fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + '\n', {
344
- mode: 0o600,
345
- });
346
- }
347
-
348
- function createEmptyInclude(configDir: string): void {
349
- const includePath = path.join(configDir, INCLUDE_FILENAME);
350
-
351
- if (fs.existsSync(includePath)) {
352
- return;
353
- }
354
-
355
- const content = [
356
- '// This file is generated by telegram-manager. Do not hand-edit.',
357
- '{}',
358
- '',
359
- ].join('\n');
360
-
361
- fs.writeFileSync(includePath, content, { mode: 0o600 });
362
- }
363
-
364
- // ── Uninstall step implementations ────────────────────────────────────
365
-
366
- function unpatchConfig(configDir: string): void {
367
- const configPath = path.join(configDir, 'openclaw.json');
368
- const bakPath = configPath + '.bak';
369
-
370
- if (!fs.existsSync(configPath)) {
371
- return;
372
- }
373
-
374
- let content: string;
375
- try {
376
- content = fs.readFileSync(configPath, 'utf-8');
377
- } catch {
378
- warn(`Could not read ${configPath}.`);
379
- return;
380
- }
381
-
382
- if (!content.includes(INCLUDE_FILENAME)) {
383
- return;
384
- }
385
-
386
- let config: Record<string, unknown>;
387
- try {
388
- config = JSON.parse(content) as Record<string, unknown>;
389
- } catch {
390
- warn('Could not parse openclaw.json. Please manually remove the $include reference.');
391
- return;
392
- }
393
-
394
- const channels = config['channels'] as Record<string, unknown> | undefined;
395
- const telegram = channels?.['telegram'] as Record<string, unknown> | undefined;
396
- if (telegram) {
397
- delete telegram['groups'];
398
- if (Object.keys(telegram).length === 0) delete channels!['telegram'];
399
- if (Object.keys(channels!).length === 0) delete config['channels'];
400
- }
401
-
402
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
403
-
404
- // Clean up stale backup from install time
405
- if (fs.existsSync(bakPath)) {
406
- fs.unlinkSync(bakPath);
407
- }
408
- }
409
-
410
- function removeFile(filePath: string): void {
411
- if (fs.existsSync(filePath)) {
412
- fs.unlinkSync(filePath);
413
- }
414
- }
415
-
416
- function removePluginDir(configDir: string): void {
417
- const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
418
- if (fs.existsSync(extDir)) {
419
- fs.rmSync(extDir, { recursive: true });
420
- }
421
- }
422
-
423
- // ── Shared helpers ────────────────────────────────────────────────────
424
-
425
- function triggerRestart(): void {
426
- try {
427
- execSync('openclaw gateway restart', {
428
- encoding: 'utf-8',
429
- timeout: 10_000,
430
- });
431
- } catch {
432
- warn('Could not restart gateway. Run `openclaw gateway restart` manually.');
433
- }
434
- }
435
-
436
- function ensureDir(dir: string): void {
437
- if (!fs.existsSync(dir)) {
438
- fs.mkdirSync(dir, { recursive: true });
439
- }
440
- }
441
-
442
- function compareVersions(a: string, b: string): number {
443
- const aParts = a.split('.').map(Number);
444
- const bParts = b.split('.').map(Number);
445
- for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
446
- const aVal = aParts[i] ?? 0;
447
- const bVal = bParts[i] ?? 0;
448
- if (aVal !== bVal) return aVal - bVal;
449
- }
450
- return 0;
451
- }
452
-
453
-
454
- function findPackageRoot(): string | null {
455
- let dir = path.dirname(new URL(import.meta.url).pathname);
456
- for (let i = 0; i < 5; i++) {
457
- if (fs.existsSync(path.join(dir, 'openclaw.plugin.json'))) {
458
- return dir;
459
- }
460
- dir = path.dirname(dir);
461
- }
462
- return null;
463
- }
464
-
465
- function copyRecursive(src: string, dest: string): void {
466
- const stat = fs.statSync(src);
467
- if (stat.isDirectory()) {
468
- fs.mkdirSync(dest, { recursive: true });
469
- for (const entry of fs.readdirSync(src)) {
470
- copyRecursive(path.join(src, entry), path.join(dest, entry));
471
- }
472
- } else {
473
- fs.copyFileSync(src, dest);
474
- }
475
- }
@@ -1,3 +0,0 @@
1
- # Commands: {{slug}}
2
-
3
- _Build, deploy, test, and other commands for this topic. Kept here so they're not lost on reset._
@@ -1,3 +0,0 @@
1
- # Cron: {{slug}}
2
-
3
- _Cron job IDs and schedules for this topic._
@@ -1,3 +0,0 @@
1
- # Links: {{slug}}
2
-
3
- _URLs, paths, and service endpoints for this topic._
@@ -1,3 +0,0 @@
1
- # Notes: {{slug}}
2
-
3
- _Anything worth remembering about this topic._
@@ -1,3 +0,0 @@
1
- # {{slug}}
2
-
3
- {{description}}
@@ -1,11 +0,0 @@
1
- # TODO: {{slug}}
2
-
3
- ## Backlog
4
-
5
- - [T-1] _First task placeholder — replace with actual task_
6
- - [T-2] _Second task placeholder — replace with actual task_
7
- - [T-3] _Third task placeholder — replace with actual task_
8
-
9
- ## Completed
10
-
11
- _None yet._
@@ -1,3 +0,0 @@
1
- # Architecture: {{slug}}
2
-
3
- _Components, data flow, dependencies, and design decisions._
@@ -1,3 +0,0 @@
1
- # Deployment: {{slug}}
2
-
3
- _Environments, deployment steps, rollback procedures, and infra details._
@@ -1,3 +0,0 @@
1
- # Campaigns: {{slug}}
2
-
3
- _Active campaigns, target audiences, channels, timelines, and budgets._
@@ -1,3 +0,0 @@
1
- # Metrics: {{slug}}
2
-
3
- _KPIs, conversion rates, engagement stats, and performance data._
@@ -1,3 +0,0 @@
1
- # Findings: {{slug}}
2
-
3
- _Conclusions, insights, data summaries, and recommendations._
@@ -1,3 +0,0 @@
1
- # Sources: {{slug}}
2
-
3
- _Papers, articles, datasets, APIs, and other reference material._