openclaw-telegram-manager 1.0.1 → 1.1.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/README.md CHANGED
@@ -25,6 +25,8 @@ npx openclaw-telegram-manager setup
25
25
 
26
26
  That's it. The setup script installs the plugin, patches your config, creates the workspace, and restarts the OpenClaw gateway. It's idempotent — running it twice won't break anything.
27
27
 
28
+ **Security warnings during install:** OpenClaw's automatic scanner may flag `child_process` and `process.env` usage. These are expected — the setup script calls `openclaw --version`, `openclaw plugins install`, and `openclaw gateway restart`, and reads `process.env` for config directory detection. No data is sent externally.
29
+
28
30
  Once that's done, head to your Telegram group:
29
31
 
30
32
  1. Open any topic
@@ -92,6 +94,14 @@ The first person to run `/topic init` automatically becomes admin.
92
94
 
93
95
  See [SECURITY.md](SECURITY.md) for reporting vulnerabilities.
94
96
 
97
+ ## Uninstalling
98
+
99
+ ```bash
100
+ npx openclaw-telegram-manager uninstall
101
+ ```
102
+
103
+ This removes the plugin extension files, the `$include` reference from `openclaw.json`, and the generated include file, then restarts the gateway. Workspace data (your topic capsules) is kept — the command prints the path if you want to remove it manually.
104
+
95
105
  ## Contributing
96
106
 
97
107
  See [CONTRIBUTING.md](CONTRIBUTING.md).
package/dist/setup.js CHANGED
@@ -3,97 +3,143 @@ import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import * as crypto from 'node:crypto';
5
5
  import { execSync } from 'node:child_process';
6
- import * as readline from 'node:readline';
7
6
  // ── Constants ──────────────────────────────────────────────────────────
7
+ const PLUGIN_NAME = 'openclaw-telegram-manager';
8
+ const PLUGIN_VERSION = '1.0.0';
8
9
  const MIN_OPENCLAW_VERSION = '2026.1.0';
9
10
  const INCLUDE_FILENAME = 'telegram-manager.generated.groups.json5';
10
11
  const REGISTRY_FILENAME = 'topics.json';
11
- // ── Main ──────────────────────────────────────────────────────────────
12
- async function main() {
13
- console.log('openclaw-telegram-manager setup');
14
- console.log('================================\n');
15
- // Step 1: Check OpenClaw version
12
+ const PLUGIN_FILES = ['openclaw.plugin.json', 'src', 'skills', 'package.json'];
13
+ // ── Colors (zero dependencies, respects NO_COLOR / non-TTY) ──────────
14
+ const useColor = process.stdout.isTTY === true &&
15
+ !process.env['NO_COLOR'] &&
16
+ process.env['TERM'] !== 'dumb';
17
+ const c = {
18
+ reset: useColor ? '\x1b[0m' : '',
19
+ bold: useColor ? '\x1b[1m' : '',
20
+ dim: useColor ? '\x1b[2m' : '',
21
+ green: useColor ? '\x1b[32m' : '',
22
+ yellow: useColor ? '\x1b[33m' : '',
23
+ red: useColor ? '\x1b[31m' : '',
24
+ cyan: useColor ? '\x1b[36m' : '',
25
+ magenta: useColor ? '\x1b[35m' : '',
26
+ };
27
+ // ── Logging helpers ───────────────────────────────────────────────────
28
+ function ok(msg) {
29
+ console.log(` ${c.green}✓${c.reset} ${msg}`);
30
+ }
31
+ function warn(msg) {
32
+ console.warn(` ${c.yellow}⚠${c.reset} ${c.yellow}${msg}${c.reset}`);
33
+ }
34
+ function fail(msg) {
35
+ console.error(` ${c.red}✗${c.reset} ${c.red}${msg}${c.reset}`);
36
+ }
37
+ function info(msg) {
38
+ console.log(` ${c.dim}${msg}${c.reset}`);
39
+ }
40
+ function banner(title, subtitle) {
41
+ console.log('');
42
+ console.log(` ${c.cyan}◆${c.reset} ${c.bold}${title}${c.reset}${subtitle ? ` ${c.dim}${subtitle}${c.reset}` : ''}`);
43
+ console.log(` ${c.dim}│${c.reset}`);
44
+ }
45
+ function footer(msg) {
46
+ console.log(` ${c.dim}│${c.reset}`);
47
+ console.log(` ${c.green}◆${c.reset} ${c.bold}${msg}${c.reset}`);
48
+ console.log('');
49
+ }
50
+ // ── Entry point ───────────────────────────────────────────────────────
51
+ const command = process.argv[2] ?? 'setup';
52
+ if (command === 'setup') {
53
+ runSetup().catch((err) => {
54
+ console.error('Setup failed:', err instanceof Error ? err.message : String(err));
55
+ process.exit(1);
56
+ });
57
+ }
58
+ else if (command === 'uninstall') {
59
+ runUninstall().catch((err) => {
60
+ console.error('Uninstall failed:', err instanceof Error ? err.message : String(err));
61
+ process.exit(1);
62
+ });
63
+ }
64
+ else {
65
+ console.error(`Unknown command: ${command}`);
66
+ console.error(`Usage: ${PLUGIN_NAME} [setup|uninstall]`);
67
+ process.exit(1);
68
+ }
69
+ // ── Setup ─────────────────────────────────────────────────────────────
70
+ async function runSetup() {
71
+ banner(PLUGIN_NAME, `v${PLUGIN_VERSION}`);
16
72
  const version = checkOpenClawVersion();
17
- console.log(`[1/11] OpenClaw version: ${version}`);
18
- // Step 2: Locate config directory
73
+ ok(`OpenClaw ${c.dim}${version}${c.reset}`);
19
74
  const configDir = locateConfigDir();
20
- console.log(`[2/11] Config directory: ${configDir}`);
21
- // Step 3: Check directory permissions
22
75
  checkDirPermissions(configDir);
23
- console.log('[3/11] Directory permissions checked');
24
- // Step 4: Install plugin
25
- installPlugin();
26
- console.log('[4/11] Plugin installation checked');
27
- // Step 5: Patch openclaw.json with $include reference
76
+ ok(`Config ${c.dim}${configDir}${c.reset}`);
77
+ installPlugin(configDir);
28
78
  patchConfig(configDir);
29
- console.log('[5/11] Config patched with $include reference');
30
- // Step 6: Create workspace directory structure
31
- const workspaceDir = path.join(configDir, 'workspace');
32
- const projectsDir = path.join(workspaceDir, 'projects');
79
+ const projectsDir = path.join(configDir, 'workspace', 'projects');
33
80
  ensureDir(projectsDir);
34
- console.log(`[6/11] Workspace directory: ${projectsDir}`);
35
- // Step 7: Initialize empty registry
36
81
  initRegistry(projectsDir);
37
- console.log('[7/11] Registry initialized');
38
- // Step 8: Create empty generated include
39
82
  createEmptyInclude(configDir);
40
- console.log('[8/11] Empty include file created');
41
- // Step 9: Optional cron setup
42
- const isInteractive = process.stdin.isTTY === true;
43
- const setupCron = isInteractive ? await promptYesNo('Set up daily doctor cron job? [Y/n] ') : true;
44
- if (setupCron) {
45
- const groupId = isInteractive
46
- ? await promptInput('Enter your Telegram group ID (e.g., -1003731538650): ')
47
- : '';
48
- setupDoctorCron(configDir, groupId);
49
- console.log('[9/11] Doctor cron job configured');
83
+ ok('Workspace ready');
84
+ triggerRestart();
85
+ ok('Gateway restarted');
86
+ footer('Setup complete');
87
+ console.log(` ${c.dim}Next steps:${c.reset}`);
88
+ console.log(` ${c.dim}1.${c.reset} Open any Telegram forum topic`);
89
+ console.log(` ${c.dim}2.${c.reset} Type ${c.cyan}/topic init${c.reset}`);
90
+ console.log(` ${c.dim}3.${c.reset} The topic will be registered and a capsule created`);
91
+ console.log('');
92
+ }
93
+ // ── Uninstall ─────────────────────────────────────────────────────────
94
+ async function runUninstall() {
95
+ banner(PLUGIN_NAME, 'uninstall');
96
+ const configDir = locateConfigDir();
97
+ ok(`Config ${c.dim}${configDir}${c.reset}`);
98
+ unpatchConfig(configDir);
99
+ removeFile(path.join(configDir, INCLUDE_FILENAME));
100
+ removePluginDir(configDir);
101
+ ok('Plugin files removed');
102
+ triggerRestart();
103
+ ok('Gateway restarted');
104
+ const projectsDir = path.join(configDir, 'workspace', 'projects');
105
+ if (fs.existsSync(projectsDir)) {
106
+ info('Workspace data kept: ' + projectsDir);
107
+ info('To remove: rm -rf ' + projectsDir);
50
108
  }
51
- else {
52
- console.log('[9/11] Skipped cron setup');
53
- }
54
- // Step 10: Trigger gateway restart
55
- triggerRestart(configDir);
56
- console.log('[10/11] Gateway restart triggered');
57
- // Step 11: Print summary
58
- printSummary(configDir, projectsDir);
59
- console.log('[11/11] Setup complete!\n');
109
+ footer('Uninstall complete');
60
110
  }
61
- // ── Step implementations ──────────────────────────────────────────────
111
+ // ── Setup step implementations ────────────────────────────────────────
62
112
  function checkOpenClawVersion() {
63
113
  let version;
64
114
  try {
65
115
  version = execSync('openclaw --version', { encoding: 'utf-8' }).trim();
66
116
  }
67
117
  catch {
68
- console.error('Error: OpenClaw not found. Please install OpenClaw (>=2026.1.0) first.');
118
+ fail('OpenClaw not found. Install OpenClaw (>=2026.1.0) first.');
69
119
  process.exit(1);
70
120
  }
71
- // Extract version number (e.g., "openclaw 2026.2.0" -> "2026.2.0")
72
121
  const match = version.match(/(\d+\.\d+\.\d+)/);
73
122
  if (!match) {
74
- console.warn(`Warning: Could not parse OpenClaw version from "${version}". Proceeding anyway.`);
123
+ warn(`Could not parse version from "${version}". Proceeding anyway.`);
75
124
  return version;
76
125
  }
77
126
  const versionStr = match[1];
78
127
  if (compareVersions(versionStr, MIN_OPENCLAW_VERSION) < 0) {
79
- console.error(`Error: OpenClaw ${versionStr} found, but openclaw-telegram-manager requires >=${MIN_OPENCLAW_VERSION}. Please upgrade.`);
128
+ fail(`OpenClaw ${versionStr} found, requires >=${MIN_OPENCLAW_VERSION}. Please upgrade.`);
80
129
  process.exit(1);
81
130
  }
82
131
  return versionStr;
83
132
  }
84
133
  function locateConfigDir() {
85
- // Check environment variable
86
134
  const envDir = process.env['OPENCLAW_CONFIG_DIR'];
87
135
  if (envDir && fs.existsSync(envDir)) {
88
136
  return path.resolve(envDir);
89
137
  }
90
- // Check default location
91
138
  const homeDir = process.env['HOME'] ?? process.env['USERPROFILE'] ?? '';
92
139
  const defaultDir = path.join(homeDir, '.openclaw');
93
140
  if (fs.existsSync(defaultDir)) {
94
141
  return defaultDir;
95
142
  }
96
- // Walk up from cwd looking for openclaw.json
97
143
  let dir = process.cwd();
98
144
  while (dir !== path.dirname(dir)) {
99
145
  if (fs.existsSync(path.join(dir, 'openclaw.json'))) {
@@ -101,7 +147,7 @@ function locateConfigDir() {
101
147
  }
102
148
  dir = path.dirname(dir);
103
149
  }
104
- console.error('Error: Could not find OpenClaw config directory. Set $OPENCLAW_CONFIG_DIR or ensure ~/.openclaw/ exists.');
150
+ fail('Could not find OpenClaw config directory. Set $OPENCLAW_CONFIG_DIR or ensure ~/.openclaw/ exists.');
105
151
  process.exit(1);
106
152
  }
107
153
  function checkDirPermissions(dir) {
@@ -109,94 +155,89 @@ function checkDirPermissions(dir) {
109
155
  const stat = fs.statSync(dir);
110
156
  const mode = stat.mode;
111
157
  const permissions = (mode & 0o777).toString(8);
112
- // Check for world-writable or group-writable
113
158
  if (mode & 0o002) {
114
- console.warn(`Warning: ${dir} is world-writable (${permissions}). Consider restricting to owner-only (chmod 700).`);
159
+ warn(`${dir} is world-writable (${permissions}). Consider chmod 700.`);
115
160
  }
116
161
  else if (mode & 0o020) {
117
- console.warn(`Warning: ${dir} is group-writable (${permissions}). Consider restricting to owner-only (chmod 700).`);
162
+ warn(`${dir} is group-writable (${permissions}). Consider chmod 700.`);
118
163
  }
119
164
  }
120
165
  catch {
121
- console.warn(`Warning: Could not check permissions for ${dir}.`);
166
+ warn(`Could not check permissions for ${dir}.`);
122
167
  }
123
168
  }
124
- function installPlugin() {
125
- try {
126
- // Check if already installed
127
- const result = execSync('openclaw plugins list', { encoding: 'utf-8' });
128
- if (result.includes('openclaw-telegram-manager')) {
129
- console.log(' Plugin already installed, skipping.');
130
- return;
131
- }
169
+ function installPlugin(configDir) {
170
+ const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
171
+ if (fs.existsSync(path.join(extDir, 'openclaw.plugin.json'))) {
172
+ ok('Plugin already installed');
173
+ return;
132
174
  }
133
- catch {
134
- // plugins list might not be available, try installing anyway
175
+ const pkgRoot = findPackageRoot();
176
+ if (pkgRoot) {
177
+ fs.mkdirSync(extDir, { recursive: true });
178
+ for (const entry of PLUGIN_FILES) {
179
+ const src = path.join(pkgRoot, entry);
180
+ if (!fs.existsSync(src))
181
+ continue;
182
+ copyRecursive(src, path.join(extDir, entry));
183
+ }
184
+ ok('Plugin installed');
185
+ return;
135
186
  }
136
187
  try {
137
- execSync('openclaw plugins install openclaw-telegram-manager', {
188
+ execSync(`openclaw plugins install ${PLUGIN_NAME}`, {
138
189
  encoding: 'utf-8',
139
190
  stdio: 'inherit',
140
191
  });
192
+ ok('Plugin installed');
141
193
  }
142
194
  catch {
143
- console.warn(' Warning: Could not install plugin via `openclaw plugins install`. You may need to install manually.');
195
+ warn('Could not install plugin. You may need to install manually.');
144
196
  }
145
197
  }
146
198
  function patchConfig(configDir) {
147
199
  const configPath = path.join(configDir, 'openclaw.json');
148
200
  if (!fs.existsSync(configPath)) {
149
- console.warn(` Warning: ${configPath} not found. Skipping config patch.`);
201
+ warn(`${configPath} not found. Skipping config patch.`);
150
202
  return;
151
203
  }
152
204
  let content;
153
205
  try {
154
206
  content = fs.readFileSync(configPath, 'utf-8');
155
207
  }
156
- catch (err) {
157
- console.warn(` Warning: Could not read ${configPath}. Skipping config patch.`);
208
+ catch {
209
+ warn(`Could not read ${configPath}. Skipping config patch.`);
158
210
  return;
159
211
  }
160
- // Check if $include reference already exists
161
212
  if (content.includes(INCLUDE_FILENAME)) {
162
- console.log(' $include reference already present, skipping.');
213
+ ok('Config already patched');
163
214
  return;
164
215
  }
165
- // Parse as JSON (OpenClaw config may be JSON or JSON5)
166
216
  let config;
167
217
  try {
168
218
  config = JSON.parse(content);
169
219
  }
170
220
  catch {
171
- // Try a more lenient approach: just check for the string and warn
172
- console.warn(' Warning: Could not parse openclaw.json as JSON. Please manually add the $include reference.');
173
- console.warn(` Add to channels.telegram.groups: { "$include": "./${INCLUDE_FILENAME}" }`);
221
+ warn('Could not parse openclaw.json. Please manually add the $include reference.');
222
+ info(`Add to channels.telegram.groups: { "$include": "./${INCLUDE_FILENAME}" }`);
174
223
  return;
175
224
  }
176
- // Ensure path exists: channels.telegram.groups
177
225
  if (!config['channels'])
178
226
  config['channels'] = {};
179
227
  const channels = config['channels'];
180
228
  if (!channels['telegram'])
181
229
  channels['telegram'] = {};
182
230
  const telegram = channels['telegram'];
183
- // Set groups to $include
184
231
  telegram['groups'] = { $include: `./${INCLUDE_FILENAME}` };
185
- // Backup and write
186
232
  const bakPath = configPath + '.bak';
187
233
  fs.copyFileSync(configPath, bakPath);
188
234
  const newContent = JSON.stringify(config, null, 2) + '\n';
189
235
  fs.writeFileSync(configPath, newContent, { mode: 0o600 });
190
- }
191
- function ensureDir(dir) {
192
- if (!fs.existsSync(dir)) {
193
- fs.mkdirSync(dir, { recursive: true });
194
- }
236
+ ok('Config patched');
195
237
  }
196
238
  function initRegistry(projectsDir) {
197
239
  const registryPath = path.join(projectsDir, REGISTRY_FILENAME);
198
240
  if (fs.existsSync(registryPath)) {
199
- console.log(' Registry already exists, skipping initialization.');
200
241
  return;
201
242
  }
202
243
  const callbackSecret = crypto.randomBytes(32).toString('hex');
@@ -215,7 +256,6 @@ function initRegistry(projectsDir) {
215
256
  function createEmptyInclude(configDir) {
216
257
  const includePath = path.join(configDir, INCLUDE_FILENAME);
217
258
  if (fs.existsSync(includePath)) {
218
- console.log(' Include file already exists, skipping.');
219
259
  return;
220
260
  }
221
261
  const content = [
@@ -225,45 +265,60 @@ function createEmptyInclude(configDir) {
225
265
  ].join('\n');
226
266
  fs.writeFileSync(includePath, content, { mode: 0o600 });
227
267
  }
228
- function setupDoctorCron(configDir, groupId) {
229
- const cronDir = path.join(configDir, 'cron');
230
- ensureDir(cronDir);
231
- const cronJobPath = path.join(cronDir, 'topic-doctor-daily.json');
232
- if (fs.existsSync(cronJobPath)) {
233
- console.log(' Cron job already exists, skipping.');
268
+ // ── Uninstall step implementations ────────────────────────────────────
269
+ function unpatchConfig(configDir) {
270
+ const configPath = path.join(configDir, 'openclaw.json');
271
+ const bakPath = configPath + '.bak';
272
+ if (!fs.existsSync(configPath)) {
234
273
  return;
235
274
  }
236
- const target = groupId
237
- ? `${groupId}:topic:1`
238
- : '-100XXXXXXXXXX:topic:1';
239
- const cronJob = {
240
- name: 'topic-doctor-daily',
241
- schedule: { kind: 'cron', expr: '0 9 * * *', tz: 'UTC' },
242
- sessionTarget: 'isolated',
243
- payload: {
244
- kind: 'agentTurn',
245
- message: 'Run topic doctor health checks on all registered topics. Check the registry at projects/topics.json and evaluate each eligible topic. Post per-topic reports with inline keyboards. If any topic\'s thread returns an API error (deleted/migrated), log it and continue to the next topic.',
246
- timeoutSeconds: 300,
247
- },
248
- delivery: {
249
- mode: 'announce',
250
- channel: 'telegram',
251
- to: target,
252
- bestEffort: true,
253
- },
254
- enabled: true,
255
- deleteAfterRun: false,
256
- };
257
- fs.writeFileSync(cronJobPath, JSON.stringify(cronJob, null, 2) + '\n', {
258
- mode: 0o600,
259
- });
260
- if (!groupId) {
261
- console.warn(' Warning: No group ID provided. Edit the cron job at:');
262
- console.warn(` ${cronJobPath}`);
263
- console.warn(' Replace -100XXXXXXXXXX with your actual group ID.');
275
+ let content;
276
+ try {
277
+ content = fs.readFileSync(configPath, 'utf-8');
278
+ }
279
+ catch {
280
+ warn(`Could not read ${configPath}.`);
281
+ return;
282
+ }
283
+ if (!content.includes(INCLUDE_FILENAME)) {
284
+ return;
285
+ }
286
+ let config;
287
+ try {
288
+ config = JSON.parse(content);
289
+ }
290
+ catch {
291
+ warn('Could not parse openclaw.json. Please manually remove the $include reference.');
292
+ return;
293
+ }
294
+ const channels = config['channels'];
295
+ const telegram = channels?.['telegram'];
296
+ if (telegram) {
297
+ delete telegram['groups'];
298
+ if (Object.keys(telegram).length === 0)
299
+ delete channels['telegram'];
300
+ if (Object.keys(channels).length === 0)
301
+ delete config['channels'];
302
+ }
303
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
304
+ // Clean up stale backup from install time
305
+ if (fs.existsSync(bakPath)) {
306
+ fs.unlinkSync(bakPath);
264
307
  }
265
308
  }
266
- function triggerRestart(configDir) {
309
+ function removeFile(filePath) {
310
+ if (fs.existsSync(filePath)) {
311
+ fs.unlinkSync(filePath);
312
+ }
313
+ }
314
+ function removePluginDir(configDir) {
315
+ const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
316
+ if (fs.existsSync(extDir)) {
317
+ fs.rmSync(extDir, { recursive: true });
318
+ }
319
+ }
320
+ // ── Shared helpers ────────────────────────────────────────────────────
321
+ function triggerRestart() {
267
322
  try {
268
323
  execSync('openclaw gateway restart', {
269
324
  encoding: 'utf-8',
@@ -271,24 +326,14 @@ function triggerRestart(configDir) {
271
326
  });
272
327
  }
273
328
  catch {
274
- console.warn(' Warning: Could not restart gateway. Run `openclaw gateway restart` manually.');
329
+ warn('Could not restart gateway. Run `openclaw gateway restart` manually.');
275
330
  }
276
331
  }
277
- function printSummary(configDir, projectsDir) {
278
- console.log('\n================================');
279
- console.log('Setup complete!\n');
280
- console.log('What was done:');
281
- console.log(` - Config directory: ${configDir}`);
282
- console.log(` - Projects directory: ${projectsDir}`);
283
- console.log(` - Registry: ${path.join(projectsDir, REGISTRY_FILENAME)}`);
284
- console.log(` - Include: ${path.join(configDir, INCLUDE_FILENAME)}`);
285
- console.log('\nNext steps:');
286
- console.log(' 1. Go to any Telegram forum topic');
287
- console.log(' 2. Type /topic init');
288
- console.log(' 3. The topic will be registered and a capsule created');
289
- console.log('\nFor help: /topic help');
332
+ function ensureDir(dir) {
333
+ if (!fs.existsSync(dir)) {
334
+ fs.mkdirSync(dir, { recursive: true });
335
+ }
290
336
  }
291
- // ── Helpers ───────────────────────────────────────────────────────────
292
337
  function compareVersions(a, b) {
293
338
  const aParts = a.split('.').map(Number);
294
339
  const bParts = b.split('.').map(Number);
@@ -300,34 +345,26 @@ function compareVersions(a, b) {
300
345
  }
301
346
  return 0;
302
347
  }
303
- function promptYesNo(question) {
304
- return new Promise((resolve) => {
305
- const rl = readline.createInterface({
306
- input: process.stdin,
307
- output: process.stdout,
308
- });
309
- rl.question(question, (answer) => {
310
- rl.close();
311
- const normalized = answer.trim().toLowerCase();
312
- resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
313
- });
314
- });
348
+ function findPackageRoot() {
349
+ let dir = path.dirname(new URL(import.meta.url).pathname);
350
+ for (let i = 0; i < 5; i++) {
351
+ if (fs.existsSync(path.join(dir, 'openclaw.plugin.json'))) {
352
+ return dir;
353
+ }
354
+ dir = path.dirname(dir);
355
+ }
356
+ return null;
315
357
  }
316
- function promptInput(question) {
317
- return new Promise((resolve) => {
318
- const rl = readline.createInterface({
319
- input: process.stdin,
320
- output: process.stdout,
321
- });
322
- rl.question(question, (answer) => {
323
- rl.close();
324
- resolve(answer.trim());
325
- });
326
- });
358
+ function copyRecursive(src, dest) {
359
+ const stat = fs.statSync(src);
360
+ if (stat.isDirectory()) {
361
+ fs.mkdirSync(dest, { recursive: true });
362
+ for (const entry of fs.readdirSync(src)) {
363
+ copyRecursive(path.join(src, entry), path.join(dest, entry));
364
+ }
365
+ }
366
+ else {
367
+ fs.copyFileSync(src, dest);
368
+ }
327
369
  }
328
- // ── Entry point ───────────────────────────────────────────────────────
329
- main().catch((err) => {
330
- console.error('Setup failed:', err instanceof Error ? err.message : String(err));
331
- process.exit(1);
332
- });
333
370
  //# sourceMappingURL=setup.js.map
package/dist/setup.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,10 @@
3
3
  "name": "Telegram Topic Manager",
4
4
  "version": "1.0.0",
5
5
  "description": "Deterministic Telegram forum topic management for OpenClaw",
6
- "license": "MIT",
7
- "slotType": "tool",
8
- "entry": "./src/index.ts"
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {}
10
+ },
11
+ "skills": ["./skills"]
9
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-telegram-manager",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Deterministic Telegram forum topic management for OpenClaw",
6
6
  "license": "MIT",
package/src/setup.ts CHANGED
@@ -4,101 +4,159 @@ import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
5
5
  import * as crypto from 'node:crypto';
6
6
  import { execSync } from 'node:child_process';
7
- import * as readline from 'node:readline';
8
7
 
9
8
  // ── Constants ──────────────────────────────────────────────────────────
10
9
 
10
+ const PLUGIN_NAME = 'openclaw-telegram-manager';
11
+ const PLUGIN_VERSION = '1.0.0';
11
12
  const MIN_OPENCLAW_VERSION = '2026.1.0';
12
13
  const INCLUDE_FILENAME = 'telegram-manager.generated.groups.json5';
13
14
  const REGISTRY_FILENAME = 'topics.json';
15
+ const PLUGIN_FILES = ['openclaw.plugin.json', 'src', 'skills', 'package.json'];
16
+
17
+ // ── Colors (zero dependencies, respects NO_COLOR / non-TTY) ──────────
18
+
19
+ const useColor =
20
+ process.stdout.isTTY === true &&
21
+ !process.env['NO_COLOR'] &&
22
+ process.env['TERM'] !== 'dumb';
23
+
24
+ const c = {
25
+ reset: useColor ? '\x1b[0m' : '',
26
+ bold: useColor ? '\x1b[1m' : '',
27
+ dim: useColor ? '\x1b[2m' : '',
28
+ green: useColor ? '\x1b[32m' : '',
29
+ yellow: useColor ? '\x1b[33m' : '',
30
+ red: useColor ? '\x1b[31m' : '',
31
+ cyan: useColor ? '\x1b[36m' : '',
32
+ magenta: useColor ? '\x1b[35m' : '',
33
+ };
34
+
35
+ // ── Logging helpers ───────────────────────────────────────────────────
36
+
37
+ function ok(msg: string): void {
38
+ console.log(` ${c.green}✓${c.reset} ${msg}`);
39
+ }
40
+ function warn(msg: string): void {
41
+ console.warn(` ${c.yellow}⚠${c.reset} ${c.yellow}${msg}${c.reset}`);
42
+ }
43
+ function fail(msg: string): void {
44
+ console.error(` ${c.red}✗${c.reset} ${c.red}${msg}${c.reset}`);
45
+ }
46
+ function info(msg: string): void {
47
+ console.log(` ${c.dim}${msg}${c.reset}`);
48
+ }
49
+
50
+ function banner(title: string, subtitle?: string): void {
51
+ console.log('');
52
+ console.log(` ${c.cyan}◆${c.reset} ${c.bold}${title}${c.reset}${subtitle ? ` ${c.dim}${subtitle}${c.reset}` : ''}`);
53
+ console.log(` ${c.dim}│${c.reset}`);
54
+ }
55
+
56
+ function footer(msg: string): void {
57
+ console.log(` ${c.dim}│${c.reset}`);
58
+ console.log(` ${c.green}◆${c.reset} ${c.bold}${msg}${c.reset}`);
59
+ console.log('');
60
+ }
61
+
62
+ // ── Entry point ───────────────────────────────────────────────────────
63
+
64
+ const command = process.argv[2] ?? 'setup';
65
+
66
+ if (command === 'setup') {
67
+ runSetup().catch((err) => {
68
+ console.error('Setup failed:', err instanceof Error ? err.message : String(err));
69
+ process.exit(1);
70
+ });
71
+ } else if (command === 'uninstall') {
72
+ runUninstall().catch((err) => {
73
+ console.error('Uninstall failed:', err instanceof Error ? err.message : String(err));
74
+ process.exit(1);
75
+ });
76
+ } else {
77
+ console.error(`Unknown command: ${command}`);
78
+ console.error(`Usage: ${PLUGIN_NAME} [setup|uninstall]`);
79
+ process.exit(1);
80
+ }
14
81
 
15
- // ── Main ──────────────────────────────────────────────────────────────
82
+ // ── Setup ─────────────────────────────────────────────────────────────
16
83
 
17
- async function main(): Promise<void> {
18
- console.log('openclaw-telegram-manager setup');
19
- console.log('================================\n');
84
+ async function runSetup(): Promise<void> {
85
+ banner(PLUGIN_NAME, `v${PLUGIN_VERSION}`);
20
86
 
21
- // Step 1: Check OpenClaw version
22
87
  const version = checkOpenClawVersion();
23
- console.log(`[1/11] OpenClaw version: ${version}`);
88
+ ok(`OpenClaw ${c.dim}${version}${c.reset}`);
24
89
 
25
- // Step 2: Locate config directory
26
90
  const configDir = locateConfigDir();
27
- console.log(`[2/11] Config directory: ${configDir}`);
28
-
29
- // Step 3: Check directory permissions
30
91
  checkDirPermissions(configDir);
31
- console.log('[3/11] Directory permissions checked');
32
-
33
- // Step 4: Install plugin
34
- installPlugin();
35
- console.log('[4/11] Plugin installation checked');
92
+ ok(`Config ${c.dim}${configDir}${c.reset}`);
36
93
 
37
- // Step 5: Patch openclaw.json with $include reference
94
+ installPlugin(configDir);
38
95
  patchConfig(configDir);
39
- console.log('[5/11] Config patched with $include reference');
40
96
 
41
- // Step 6: Create workspace directory structure
42
- const workspaceDir = path.join(configDir, 'workspace');
43
- const projectsDir = path.join(workspaceDir, 'projects');
97
+ const projectsDir = path.join(configDir, 'workspace', 'projects');
44
98
  ensureDir(projectsDir);
45
- console.log(`[6/11] Workspace directory: ${projectsDir}`);
46
-
47
- // Step 7: Initialize empty registry
48
99
  initRegistry(projectsDir);
49
- console.log('[7/11] Registry initialized');
50
-
51
- // Step 8: Create empty generated include
52
100
  createEmptyInclude(configDir);
53
- console.log('[8/11] Empty include file created');
54
-
55
- // Step 9: Optional cron setup
56
- const isInteractive = process.stdin.isTTY === true;
57
- const setupCron = isInteractive ? await promptYesNo('Set up daily doctor cron job? [Y/n] ') : true;
58
- if (setupCron) {
59
- const groupId = isInteractive
60
- ? await promptInput('Enter your Telegram group ID (e.g., -1003731538650): ')
61
- : '';
62
- setupDoctorCron(configDir, groupId);
63
- console.log('[9/11] Doctor cron job configured');
64
- } else {
65
- console.log('[9/11] Skipped cron setup');
66
- }
101
+ ok('Workspace ready');
102
+
103
+ triggerRestart();
104
+ ok('Gateway restarted');
67
105
 
68
- // Step 10: Trigger gateway restart
69
- triggerRestart(configDir);
70
- console.log('[10/11] Gateway restart triggered');
106
+ footer('Setup complete');
71
107
 
72
- // Step 11: Print summary
73
- printSummary(configDir, projectsDir);
74
- console.log('[11/11] Setup complete!\n');
108
+ console.log(` ${c.dim}Next steps:${c.reset}`);
109
+ console.log(` ${c.dim}1.${c.reset} Open any Telegram forum topic`);
110
+ console.log(` ${c.dim}2.${c.reset} Type ${c.cyan}/topic init${c.reset}`);
111
+ console.log(` ${c.dim}3.${c.reset} The topic will be registered and a capsule created`);
112
+ console.log('');
75
113
  }
76
114
 
77
- // ── Step implementations ──────────────────────────────────────────────
115
+ // ── Uninstall ─────────────────────────────────────────────────────────
116
+
117
+ async function runUninstall(): Promise<void> {
118
+ banner(PLUGIN_NAME, 'uninstall');
119
+
120
+ const configDir = locateConfigDir();
121
+ ok(`Config ${c.dim}${configDir}${c.reset}`);
122
+
123
+ unpatchConfig(configDir);
124
+ removeFile(path.join(configDir, INCLUDE_FILENAME));
125
+ removePluginDir(configDir);
126
+ ok('Plugin files removed');
127
+
128
+ triggerRestart();
129
+ ok('Gateway restarted');
130
+
131
+ const projectsDir = path.join(configDir, 'workspace', 'projects');
132
+ if (fs.existsSync(projectsDir)) {
133
+ info('Workspace data kept: ' + projectsDir);
134
+ info('To remove: rm -rf ' + projectsDir);
135
+ }
136
+
137
+ footer('Uninstall complete');
138
+ }
139
+
140
+ // ── Setup step implementations ────────────────────────────────────────
78
141
 
79
142
  function checkOpenClawVersion(): string {
80
143
  let version: string;
81
144
  try {
82
145
  version = execSync('openclaw --version', { encoding: 'utf-8' }).trim();
83
146
  } catch {
84
- console.error(
85
- 'Error: OpenClaw not found. Please install OpenClaw (>=2026.1.0) first.',
86
- );
147
+ fail('OpenClaw not found. Install OpenClaw (>=2026.1.0) first.');
87
148
  process.exit(1);
88
149
  }
89
150
 
90
- // Extract version number (e.g., "openclaw 2026.2.0" -> "2026.2.0")
91
151
  const match = version.match(/(\d+\.\d+\.\d+)/);
92
152
  if (!match) {
93
- console.warn(`Warning: Could not parse OpenClaw version from "${version}". Proceeding anyway.`);
153
+ warn(`Could not parse version from "${version}". Proceeding anyway.`);
94
154
  return version;
95
155
  }
96
156
 
97
157
  const versionStr = match[1]!;
98
158
  if (compareVersions(versionStr, MIN_OPENCLAW_VERSION) < 0) {
99
- console.error(
100
- `Error: OpenClaw ${versionStr} found, but openclaw-telegram-manager requires >=${MIN_OPENCLAW_VERSION}. Please upgrade.`,
101
- );
159
+ fail(`OpenClaw ${versionStr} found, requires >=${MIN_OPENCLAW_VERSION}. Please upgrade.`);
102
160
  process.exit(1);
103
161
  }
104
162
 
@@ -106,20 +164,17 @@ function checkOpenClawVersion(): string {
106
164
  }
107
165
 
108
166
  function locateConfigDir(): string {
109
- // Check environment variable
110
167
  const envDir = process.env['OPENCLAW_CONFIG_DIR'];
111
168
  if (envDir && fs.existsSync(envDir)) {
112
169
  return path.resolve(envDir);
113
170
  }
114
171
 
115
- // Check default location
116
172
  const homeDir = process.env['HOME'] ?? process.env['USERPROFILE'] ?? '';
117
173
  const defaultDir = path.join(homeDir, '.openclaw');
118
174
  if (fs.existsSync(defaultDir)) {
119
175
  return defaultDir;
120
176
  }
121
177
 
122
- // Walk up from cwd looking for openclaw.json
123
178
  let dir = process.cwd();
124
179
  while (dir !== path.dirname(dir)) {
125
180
  if (fs.existsSync(path.join(dir, 'openclaw.json'))) {
@@ -128,9 +183,7 @@ function locateConfigDir(): string {
128
183
  dir = path.dirname(dir);
129
184
  }
130
185
 
131
- console.error(
132
- 'Error: Could not find OpenClaw config directory. Set $OPENCLAW_CONFIG_DIR or ensure ~/.openclaw/ exists.',
133
- );
186
+ fail('Could not find OpenClaw config directory. Set $OPENCLAW_CONFIG_DIR or ensure ~/.openclaw/ exists.');
134
187
  process.exit(1);
135
188
  }
136
189
 
@@ -140,42 +193,44 @@ function checkDirPermissions(dir: string): void {
140
193
  const mode = stat.mode;
141
194
  const permissions = (mode & 0o777).toString(8);
142
195
 
143
- // Check for world-writable or group-writable
144
196
  if (mode & 0o002) {
145
- console.warn(
146
- `Warning: ${dir} is world-writable (${permissions}). Consider restricting to owner-only (chmod 700).`,
147
- );
197
+ warn(`${dir} is world-writable (${permissions}). Consider chmod 700.`);
148
198
  } else if (mode & 0o020) {
149
- console.warn(
150
- `Warning: ${dir} is group-writable (${permissions}). Consider restricting to owner-only (chmod 700).`,
151
- );
199
+ warn(`${dir} is group-writable (${permissions}). Consider chmod 700.`);
152
200
  }
153
201
  } catch {
154
- console.warn(`Warning: Could not check permissions for ${dir}.`);
202
+ warn(`Could not check permissions for ${dir}.`);
155
203
  }
156
204
  }
157
205
 
158
- function installPlugin(): void {
159
- try {
160
- // Check if already installed
161
- const result = execSync('openclaw plugins list', { encoding: 'utf-8' });
162
- if (result.includes('openclaw-telegram-manager')) {
163
- console.log(' Plugin already installed, skipping.');
164
- return;
206
+ function installPlugin(configDir: string): void {
207
+ const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
208
+
209
+ if (fs.existsSync(path.join(extDir, 'openclaw.plugin.json'))) {
210
+ ok('Plugin already installed');
211
+ return;
212
+ }
213
+
214
+ const pkgRoot = findPackageRoot();
215
+ if (pkgRoot) {
216
+ fs.mkdirSync(extDir, { recursive: true });
217
+ for (const entry of PLUGIN_FILES) {
218
+ const src = path.join(pkgRoot, entry);
219
+ if (!fs.existsSync(src)) continue;
220
+ copyRecursive(src, path.join(extDir, entry));
165
221
  }
166
- } catch {
167
- // plugins list might not be available, try installing anyway
222
+ ok('Plugin installed');
223
+ return;
168
224
  }
169
225
 
170
226
  try {
171
- execSync('openclaw plugins install openclaw-telegram-manager', {
227
+ execSync(`openclaw plugins install ${PLUGIN_NAME}`, {
172
228
  encoding: 'utf-8',
173
229
  stdio: 'inherit',
174
230
  });
231
+ ok('Plugin installed');
175
232
  } catch {
176
- console.warn(
177
- ' Warning: Could not install plugin via `openclaw plugins install`. You may need to install manually.',
178
- );
233
+ warn('Could not install plugin. You may need to install manually.');
179
234
  }
180
235
  }
181
236
 
@@ -183,66 +238,52 @@ function patchConfig(configDir: string): void {
183
238
  const configPath = path.join(configDir, 'openclaw.json');
184
239
 
185
240
  if (!fs.existsSync(configPath)) {
186
- console.warn(` Warning: ${configPath} not found. Skipping config patch.`);
241
+ warn(`${configPath} not found. Skipping config patch.`);
187
242
  return;
188
243
  }
189
244
 
190
245
  let content: string;
191
246
  try {
192
247
  content = fs.readFileSync(configPath, 'utf-8');
193
- } catch (err) {
194
- console.warn(` Warning: Could not read ${configPath}. Skipping config patch.`);
248
+ } catch {
249
+ warn(`Could not read ${configPath}. Skipping config patch.`);
195
250
  return;
196
251
  }
197
252
 
198
- // Check if $include reference already exists
199
253
  if (content.includes(INCLUDE_FILENAME)) {
200
- console.log(' $include reference already present, skipping.');
254
+ ok('Config already patched');
201
255
  return;
202
256
  }
203
257
 
204
- // Parse as JSON (OpenClaw config may be JSON or JSON5)
205
258
  let config: Record<string, unknown>;
206
259
  try {
207
260
  config = JSON.parse(content) as Record<string, unknown>;
208
261
  } catch {
209
- // Try a more lenient approach: just check for the string and warn
210
- console.warn(
211
- ' Warning: Could not parse openclaw.json as JSON. Please manually add the $include reference.',
212
- );
213
- console.warn(` Add to channels.telegram.groups: { "$include": "./${INCLUDE_FILENAME}" }`);
262
+ warn('Could not parse openclaw.json. Please manually add the $include reference.');
263
+ info(`Add to channels.telegram.groups: { "$include": "./${INCLUDE_FILENAME}" }`);
214
264
  return;
215
265
  }
216
266
 
217
- // Ensure path exists: channels.telegram.groups
218
267
  if (!config['channels']) config['channels'] = {};
219
268
  const channels = config['channels'] as Record<string, unknown>;
220
269
 
221
270
  if (!channels['telegram']) channels['telegram'] = {};
222
271
  const telegram = channels['telegram'] as Record<string, unknown>;
223
272
 
224
- // Set groups to $include
225
273
  telegram['groups'] = { $include: `./${INCLUDE_FILENAME}` };
226
274
 
227
- // Backup and write
228
275
  const bakPath = configPath + '.bak';
229
276
  fs.copyFileSync(configPath, bakPath);
230
277
 
231
278
  const newContent = JSON.stringify(config, null, 2) + '\n';
232
279
  fs.writeFileSync(configPath, newContent, { mode: 0o600 });
233
- }
234
-
235
- function ensureDir(dir: string): void {
236
- if (!fs.existsSync(dir)) {
237
- fs.mkdirSync(dir, { recursive: true });
238
- }
280
+ ok('Config patched');
239
281
  }
240
282
 
241
283
  function initRegistry(projectsDir: string): void {
242
284
  const registryPath = path.join(projectsDir, REGISTRY_FILENAME);
243
285
 
244
286
  if (fs.existsSync(registryPath)) {
245
- console.log(' Registry already exists, skipping initialization.');
246
287
  return;
247
288
  }
248
289
 
@@ -265,7 +306,6 @@ function createEmptyInclude(configDir: string): void {
265
306
  const includePath = path.join(configDir, INCLUDE_FILENAME);
266
307
 
267
308
  if (fs.existsSync(includePath)) {
268
- console.log(' Include file already exists, skipping.');
269
309
  return;
270
310
  }
271
311
 
@@ -278,84 +318,84 @@ function createEmptyInclude(configDir: string): void {
278
318
  fs.writeFileSync(includePath, content, { mode: 0o600 });
279
319
  }
280
320
 
281
- function setupDoctorCron(configDir: string, groupId: string): void {
282
- const cronDir = path.join(configDir, 'cron');
283
- ensureDir(cronDir);
321
+ // ── Uninstall step implementations ────────────────────────────────────
322
+
323
+ function unpatchConfig(configDir: string): void {
324
+ const configPath = path.join(configDir, 'openclaw.json');
325
+ const bakPath = configPath + '.bak';
326
+
327
+ if (!fs.existsSync(configPath)) {
328
+ return;
329
+ }
284
330
 
285
- const cronJobPath = path.join(cronDir, 'topic-doctor-daily.json');
331
+ let content: string;
332
+ try {
333
+ content = fs.readFileSync(configPath, 'utf-8');
334
+ } catch {
335
+ warn(`Could not read ${configPath}.`);
336
+ return;
337
+ }
286
338
 
287
- if (fs.existsSync(cronJobPath)) {
288
- console.log(' Cron job already exists, skipping.');
339
+ if (!content.includes(INCLUDE_FILENAME)) {
289
340
  return;
290
341
  }
291
342
 
292
- const target = groupId
293
- ? `${groupId}:topic:1`
294
- : '-100XXXXXXXXXX:topic:1';
295
-
296
- const cronJob = {
297
- name: 'topic-doctor-daily',
298
- schedule: { kind: 'cron', expr: '0 9 * * *', tz: 'UTC' },
299
- sessionTarget: 'isolated',
300
- payload: {
301
- kind: 'agentTurn',
302
- message:
303
- 'Run topic doctor health checks on all registered topics. Check the registry at projects/topics.json and evaluate each eligible topic. Post per-topic reports with inline keyboards. If any topic\'s thread returns an API error (deleted/migrated), log it and continue to the next topic.',
304
- timeoutSeconds: 300,
305
- },
306
- delivery: {
307
- mode: 'announce',
308
- channel: 'telegram',
309
- to: target,
310
- bestEffort: true,
311
- },
312
- enabled: true,
313
- deleteAfterRun: false,
314
- };
343
+ let config: Record<string, unknown>;
344
+ try {
345
+ config = JSON.parse(content) as Record<string, unknown>;
346
+ } catch {
347
+ warn('Could not parse openclaw.json. Please manually remove the $include reference.');
348
+ return;
349
+ }
315
350
 
316
- fs.writeFileSync(cronJobPath, JSON.stringify(cronJob, null, 2) + '\n', {
317
- mode: 0o600,
318
- });
351
+ const channels = config['channels'] as Record<string, unknown> | undefined;
352
+ const telegram = channels?.['telegram'] as Record<string, unknown> | undefined;
353
+ if (telegram) {
354
+ delete telegram['groups'];
355
+ if (Object.keys(telegram).length === 0) delete channels!['telegram'];
356
+ if (Object.keys(channels!).length === 0) delete config['channels'];
357
+ }
358
+
359
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
360
+
361
+ // Clean up stale backup from install time
362
+ if (fs.existsSync(bakPath)) {
363
+ fs.unlinkSync(bakPath);
364
+ }
365
+ }
319
366
 
320
- if (!groupId) {
321
- console.warn(
322
- ' Warning: No group ID provided. Edit the cron job at:',
323
- );
324
- console.warn(` ${cronJobPath}`);
325
- console.warn(' Replace -100XXXXXXXXXX with your actual group ID.');
367
+ function removeFile(filePath: string): void {
368
+ if (fs.existsSync(filePath)) {
369
+ fs.unlinkSync(filePath);
326
370
  }
327
371
  }
328
372
 
329
- function triggerRestart(configDir: string): void {
373
+ function removePluginDir(configDir: string): void {
374
+ const extDir = path.join(configDir, 'extensions', PLUGIN_NAME);
375
+ if (fs.existsSync(extDir)) {
376
+ fs.rmSync(extDir, { recursive: true });
377
+ }
378
+ }
379
+
380
+ // ── Shared helpers ────────────────────────────────────────────────────
381
+
382
+ function triggerRestart(): void {
330
383
  try {
331
384
  execSync('openclaw gateway restart', {
332
385
  encoding: 'utf-8',
333
386
  timeout: 10_000,
334
387
  });
335
388
  } catch {
336
- console.warn(
337
- ' Warning: Could not restart gateway. Run `openclaw gateway restart` manually.',
338
- );
389
+ warn('Could not restart gateway. Run `openclaw gateway restart` manually.');
339
390
  }
340
391
  }
341
392
 
342
- function printSummary(configDir: string, projectsDir: string): void {
343
- console.log('\n================================');
344
- console.log('Setup complete!\n');
345
- console.log('What was done:');
346
- console.log(` - Config directory: ${configDir}`);
347
- console.log(` - Projects directory: ${projectsDir}`);
348
- console.log(` - Registry: ${path.join(projectsDir, REGISTRY_FILENAME)}`);
349
- console.log(` - Include: ${path.join(configDir, INCLUDE_FILENAME)}`);
350
- console.log('\nNext steps:');
351
- console.log(' 1. Go to any Telegram forum topic');
352
- console.log(' 2. Type /topic init');
353
- console.log(' 3. The topic will be registered and a capsule created');
354
- console.log('\nFor help: /topic help');
393
+ function ensureDir(dir: string): void {
394
+ if (!fs.existsSync(dir)) {
395
+ fs.mkdirSync(dir, { recursive: true });
396
+ }
355
397
  }
356
398
 
357
- // ── Helpers ───────────────────────────────────────────────────────────
358
-
359
399
  function compareVersions(a: string, b: string): number {
360
400
  const aParts = a.split('.').map(Number);
361
401
  const bParts = b.split('.').map(Number);
@@ -367,36 +407,25 @@ function compareVersions(a: string, b: string): number {
367
407
  return 0;
368
408
  }
369
409
 
370
- function promptYesNo(question: string): Promise<boolean> {
371
- return new Promise((resolve) => {
372
- const rl = readline.createInterface({
373
- input: process.stdin,
374
- output: process.stdout,
375
- });
376
- rl.question(question, (answer) => {
377
- rl.close();
378
- const normalized = answer.trim().toLowerCase();
379
- resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
380
- });
381
- });
410
+ function findPackageRoot(): string | null {
411
+ let dir = path.dirname(new URL(import.meta.url).pathname);
412
+ for (let i = 0; i < 5; i++) {
413
+ if (fs.existsSync(path.join(dir, 'openclaw.plugin.json'))) {
414
+ return dir;
415
+ }
416
+ dir = path.dirname(dir);
417
+ }
418
+ return null;
382
419
  }
383
420
 
384
- function promptInput(question: string): Promise<string> {
385
- return new Promise((resolve) => {
386
- const rl = readline.createInterface({
387
- input: process.stdin,
388
- output: process.stdout,
389
- });
390
- rl.question(question, (answer) => {
391
- rl.close();
392
- resolve(answer.trim());
393
- });
394
- });
421
+ function copyRecursive(src: string, dest: string): void {
422
+ const stat = fs.statSync(src);
423
+ if (stat.isDirectory()) {
424
+ fs.mkdirSync(dest, { recursive: true });
425
+ for (const entry of fs.readdirSync(src)) {
426
+ copyRecursive(path.join(src, entry), path.join(dest, entry));
427
+ }
428
+ } else {
429
+ fs.copyFileSync(src, dest);
430
+ }
395
431
  }
396
-
397
- // ── Entry point ───────────────────────────────────────────────────────
398
-
399
- main().catch((err) => {
400
- console.error('Setup failed:', err instanceof Error ? err.message : String(err));
401
- process.exit(1);
402
- });