notoken-core 1.5.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/config/chat-responses.json +767 -0
  2. package/config/concept-clusters.json +31 -0
  3. package/config/entities.json +93 -0
  4. package/config/image-prompts.json +20 -0
  5. package/config/intent-vectors.json +1 -0
  6. package/config/intents.json +5023 -65
  7. package/config/ollama-models.json +193 -0
  8. package/config/rules.json +32 -1
  9. package/dist/automation/discordPatchright.d.ts +35 -0
  10. package/dist/automation/discordPatchright.js +424 -0
  11. package/dist/automation/discordSetup.d.ts +31 -0
  12. package/dist/automation/discordSetup.js +338 -0
  13. package/dist/conversation/coreference.js +44 -4
  14. package/dist/conversation/pendingActions.d.ts +55 -0
  15. package/dist/conversation/pendingActions.js +127 -0
  16. package/dist/conversation/store.d.ts +72 -0
  17. package/dist/conversation/store.js +140 -1
  18. package/dist/conversation/topicTracker.d.ts +36 -0
  19. package/dist/conversation/topicTracker.js +141 -0
  20. package/dist/execution/ssh.d.ts +42 -1
  21. package/dist/execution/ssh.js +532 -3
  22. package/dist/handlers/executor.js +3981 -16
  23. package/dist/index.d.ts +25 -3
  24. package/dist/index.js +36 -2
  25. package/dist/nlp/batchParser.d.ts +30 -0
  26. package/dist/nlp/batchParser.js +77 -0
  27. package/dist/nlp/conceptExpansion.d.ts +54 -0
  28. package/dist/nlp/conceptExpansion.js +136 -0
  29. package/dist/nlp/conceptRouter.d.ts +49 -0
  30. package/dist/nlp/conceptRouter.js +302 -0
  31. package/dist/nlp/confidenceCalibrator.d.ts +62 -0
  32. package/dist/nlp/confidenceCalibrator.js +116 -0
  33. package/dist/nlp/correctionLearner.d.ts +45 -0
  34. package/dist/nlp/correctionLearner.js +207 -0
  35. package/dist/nlp/entitySpellCorrect.d.ts +35 -0
  36. package/dist/nlp/entitySpellCorrect.js +141 -0
  37. package/dist/nlp/knowledgeGraph.d.ts +70 -0
  38. package/dist/nlp/knowledgeGraph.js +380 -0
  39. package/dist/nlp/llmFallback.js +28 -1
  40. package/dist/nlp/multiClassifier.js +91 -6
  41. package/dist/nlp/multiIntent.d.ts +43 -0
  42. package/dist/nlp/multiIntent.js +154 -0
  43. package/dist/nlp/parseIntent.d.ts +6 -1
  44. package/dist/nlp/parseIntent.js +180 -5
  45. package/dist/nlp/ruleParser.js +315 -0
  46. package/dist/nlp/semanticSimilarity.d.ts +30 -0
  47. package/dist/nlp/semanticSimilarity.js +174 -0
  48. package/dist/nlp/vocabularyBuilder.d.ts +43 -0
  49. package/dist/nlp/vocabularyBuilder.js +224 -0
  50. package/dist/nlp/wikidata.d.ts +49 -0
  51. package/dist/nlp/wikidata.js +228 -0
  52. package/dist/policy/confirm.d.ts +10 -0
  53. package/dist/policy/confirm.js +39 -0
  54. package/dist/policy/safety.js +6 -4
  55. package/dist/utils/aliases.d.ts +5 -0
  56. package/dist/utils/aliases.js +39 -0
  57. package/dist/utils/analysis.js +71 -15
  58. package/dist/utils/browser.d.ts +64 -0
  59. package/dist/utils/browser.js +364 -0
  60. package/dist/utils/commandHistory.d.ts +20 -0
  61. package/dist/utils/commandHistory.js +108 -0
  62. package/dist/utils/completer.d.ts +17 -0
  63. package/dist/utils/completer.js +79 -0
  64. package/dist/utils/config.js +32 -2
  65. package/dist/utils/dbQuery.d.ts +25 -0
  66. package/dist/utils/dbQuery.js +248 -0
  67. package/dist/utils/discordDiag.d.ts +35 -0
  68. package/dist/utils/discordDiag.js +826 -0
  69. package/dist/utils/diskCleanup.d.ts +36 -0
  70. package/dist/utils/diskCleanup.js +775 -0
  71. package/dist/utils/entityResolver.d.ts +107 -0
  72. package/dist/utils/entityResolver.js +468 -0
  73. package/dist/utils/imageGen.d.ts +92 -0
  74. package/dist/utils/imageGen.js +2031 -0
  75. package/dist/utils/installTracker.d.ts +57 -0
  76. package/dist/utils/installTracker.js +160 -0
  77. package/dist/utils/multiExec.d.ts +21 -0
  78. package/dist/utils/multiExec.js +141 -0
  79. package/dist/utils/openclawDiag.d.ts +29 -0
  80. package/dist/utils/openclawDiag.js +1035 -0
  81. package/dist/utils/output.js +4 -0
  82. package/dist/utils/platform.js +2 -1
  83. package/dist/utils/progressReporter.d.ts +50 -0
  84. package/dist/utils/progressReporter.js +58 -0
  85. package/dist/utils/projectDetect.d.ts +44 -0
  86. package/dist/utils/projectDetect.js +319 -0
  87. package/dist/utils/projectScanner.d.ts +44 -0
  88. package/dist/utils/projectScanner.js +312 -0
  89. package/dist/utils/shellCompat.d.ts +78 -0
  90. package/dist/utils/shellCompat.js +186 -0
  91. package/dist/utils/smartArchive.d.ts +16 -0
  92. package/dist/utils/smartArchive.js +172 -0
  93. package/dist/utils/smartRetry.d.ts +26 -0
  94. package/dist/utils/smartRetry.js +114 -0
  95. package/dist/utils/updater.d.ts +1 -0
  96. package/dist/utils/updater.js +1 -1
  97. package/dist/utils/version.d.ts +20 -0
  98. package/dist/utils/version.js +212 -0
  99. package/package.json +6 -3
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Discord Developer Portal automation via patchright.
3
+ *
4
+ * Runs on Windows Node via cmd.exe (patchright can't launch visible
5
+ * Windows browsers from WSL due to pipe FD limitation).
6
+ *
7
+ * Scripts are written to C:\temp and executed via Windows Node.
8
+ * Browser uses persistent profile at C:\temp\notoken-browser-profile
9
+ * to preserve Discord login sessions across runs.
10
+ *
11
+ * User handles: captcha, MFA (password). Script waits patiently.
12
+ * Token captured via Windows clipboard (Get-Clipboard).
13
+ */
14
+ import { execSync } from "node:child_process";
15
+ import { writeFileSync, readFileSync, existsSync } from "node:fs";
16
+ const c = {
17
+ reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
18
+ green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m",
19
+ };
20
+ function tryExec(cmd, timeout = 15_000) {
21
+ try {
22
+ return execSync(cmd, { timeout, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
23
+ }
24
+ catch (e) {
25
+ return e.stdout?.trim?.() ?? "";
26
+ }
27
+ }
28
+ const isNativeWin = process.platform === "win32";
29
+ const tempDir = isNativeWin ? "C:\\temp" : "/mnt/c/temp";
30
+ const tempDirPosix = isNativeWin ? "/c/temp" : "/mnt/c/temp";
31
+ const cmdPrefix = isNativeWin ? `cmd.exe /c "cd ${tempDir} &&` : `/mnt/c/Windows/System32/cmd.exe /c "cd ${tempDir} &&`;
32
+ function winExec(script, timeout = 300_000) {
33
+ // Write script to temp dir, run via Node
34
+ const scriptPath = isNativeWin ? `${tempDir}\\notoken-discord-script.js` : `${tempDir}/notoken-discord-script.js`;
35
+ try {
36
+ execSync(`mkdir ${isNativeWin ? tempDir : "-p " + tempDir}`, { stdio: "pipe" });
37
+ }
38
+ catch { }
39
+ writeFileSync(scriptPath, script);
40
+ return tryExec(`${cmdPrefix} node notoken-discord-script.js"`, timeout);
41
+ }
42
+ /**
43
+ * Ensure patchright is installed on Windows.
44
+ */
45
+ export function ensurePatchright() {
46
+ try {
47
+ execSync(`mkdir ${isNativeWin ? tempDir : "-p " + tempDir}`, { stdio: "pipe" });
48
+ }
49
+ catch { }
50
+ const check = tryExec(`${cmdPrefix} node -e \\"require('patchright');\\"" 2>&1`);
51
+ if (check.includes("Cannot find")) {
52
+ console.log(` ${c.dim}Installing patchright...${c.reset}`);
53
+ tryExec(`${cmdPrefix} npm install patchright" 2>&1`, 60_000);
54
+ return true;
55
+ }
56
+ return true;
57
+ }
58
+ /** Detect which browser channel is available */
59
+ function detectBrowserChannel() {
60
+ if (isNativeWin) {
61
+ if (existsSync("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe") ||
62
+ existsSync("C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"))
63
+ return "msedge";
64
+ if (existsSync("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe") ||
65
+ existsSync("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"))
66
+ return "chrome";
67
+ }
68
+ else {
69
+ // WSL — check Windows browsers via /mnt/c
70
+ if (existsSync("/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe") ||
71
+ existsSync("/mnt/c/Program Files/Microsoft/Edge/Application/msedge.exe"))
72
+ return "msedge";
73
+ if (existsSync("/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"))
74
+ return "chrome";
75
+ }
76
+ return "chromium"; // fallback to bundled
77
+ }
78
+ /**
79
+ * Create a Discord bot application, get token, enable intents.
80
+ * Returns { token, appId, success }.
81
+ */
82
+ export async function createDiscordBot(appName = "NoToken-Bot") {
83
+ ensurePatchright();
84
+ const uniqueName = `${appName}-${Date.now().toString().slice(-4)}`;
85
+ const browserChannel = detectBrowserChannel();
86
+ console.log(`\n${c.bold}${c.cyan}── Creating Discord Bot: ${uniqueName} ──${c.reset}`);
87
+ console.log(`${c.dim} Browser: ${browserChannel}${c.reset}\n`);
88
+ const script = `
89
+ const { chromium } = require('patchright');
90
+ const fs = require('fs');
91
+ const APP_NAME = '${uniqueName}';
92
+ const USER_DATA_DIR = 'C:\\\\temp\\\\notoken-browser-profile';
93
+
94
+ (async () => {
95
+ const ctx = await chromium.launchPersistentContext(USER_DATA_DIR, {
96
+ headless: false, channel: '${browserChannel}',
97
+ args: ['--disable-blink-features=AutomationControlled'],
98
+ viewport: { width: 1280, height: 900 },
99
+ });
100
+ const page = ctx.pages()[0] || await ctx.newPage();
101
+
102
+ // Navigate
103
+ await page.goto('https://discord.com/developers/applications', { timeout: 60000 });
104
+ await page.waitForLoadState('networkidle').catch(() => {});
105
+ await page.waitForTimeout(3000);
106
+
107
+ // Login handling
108
+ if (await page.locator('button:has-text("Log In")').first().isVisible({ timeout: 2000 }).catch(() => false)) {
109
+ await page.locator('button:has-text("Log In")').first().click();
110
+ await page.waitForTimeout(2000);
111
+ }
112
+ if (page.url().includes('/login') || await page.locator('input[name="password"]').isVisible({ timeout: 2000 }).catch(() => false)) {
113
+ console.log('LOGIN_REQUIRED');
114
+ await page.waitForURL('**/developers/applications**', { timeout: 600000 });
115
+ await page.waitForTimeout(3000);
116
+ }
117
+ console.log('LOGGED_IN');
118
+
119
+ // Dismiss survey
120
+ await page.locator('button[aria-label="Dismiss"]').click({ timeout: 1000 }).catch(() => {});
121
+
122
+ // Create app
123
+ await page.waitForSelector('button:has-text("New Application")', { timeout: 10000 });
124
+ await page.click('button:has-text("New Application")');
125
+ await page.waitForSelector('input#appname', { timeout: 5000 });
126
+ await page.locator('input#appname').click();
127
+ await page.locator('input#appname').fill(APP_NAME);
128
+ await page.locator('div[class*="checkboxIndicator"]').first().click();
129
+ await page.waitForTimeout(300);
130
+ await page.locator('button[class*="primary"]:has-text("Create")').first().click();
131
+ console.log('CREATE_CLICKED');
132
+
133
+ // Wait for captcha/redirect
134
+ await page.waitForURL(/applications\\/\\d+/, { timeout: 300000 });
135
+ await page.waitForLoadState('networkidle').catch(() => {});
136
+ const appId = (page.url().match(/applications\\/(\\d+)/) || [])[1] || '';
137
+ console.log('APP_CREATED:' + appId);
138
+
139
+ // Bot tab
140
+ await page.locator('a:has-text("Bot")').first().click();
141
+ await page.waitForSelector('button:has-text("Reset Token")', { timeout: 10000 });
142
+
143
+ // Intercept API responses to capture token from network
144
+ let tokenFromApi = '';
145
+ page.on('response', async (resp) => {
146
+ try {
147
+ if (resp.url().includes('/bot/reset') || resp.url().includes('/bot/token') || resp.url().includes('/applications/')) {
148
+ const body = await resp.text().catch(() => '');
149
+ const match = body.match(/"token"\\s*:\\s*"([^"]+)"/);
150
+ if (match && match[1].includes('.') && match[1].length > 50) {
151
+ tokenFromApi = match[1];
152
+ fs.writeFileSync('C:\\\\temp\\\\discord-token-api.txt', tokenFromApi);
153
+ console.log('TOKEN_FROM_API');
154
+ }
155
+ }
156
+ } catch {}
157
+ });
158
+
159
+ // Reset Token
160
+ await page.click('button:has-text("Reset Token")');
161
+ await page.waitForTimeout(1500);
162
+ await page.click('button:has-text("Yes, do it!")', { timeout: 5000 }).catch(() => {});
163
+ console.log('TOKEN_RESET');
164
+
165
+ // Wait for MFA/token — poll API intercept, DOM, clipboard
166
+ let token = '';
167
+ const log = [];
168
+ for (let i = 0; i < 150; i++) {
169
+ await page.waitForTimeout(2000);
170
+
171
+ // Check API intercept first (most reliable)
172
+ if (tokenFromApi) { token = tokenFromApi; log.push('SOURCE:api'); break; }
173
+
174
+ // Check all page content for token pattern
175
+ token = await page.evaluate(() => {
176
+ const found = [];
177
+ // Walk entire DOM text
178
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
179
+ while (walker.nextNode()) {
180
+ const text = walker.currentNode.textContent || '';
181
+ if (text.includes('.') && text.length > 50 && text.length < 200 && !text.includes(' ') && !text.includes('\\n')) {
182
+ found.push(text.trim());
183
+ }
184
+ }
185
+ // Check input values
186
+ for (const inp of document.querySelectorAll('input')) {
187
+ const val = inp.value || inp.getAttribute('value') || '';
188
+ if (val.includes('.') && val.length > 50 && val.length < 200 && !val.includes(' ')) {
189
+ found.push(val.trim());
190
+ }
191
+ }
192
+ return found[0] || '';
193
+ }).catch(() => '');
194
+ if (token) { log.push('SOURCE:dom'); break; }
195
+
196
+ // Click Copy and check clipboard
197
+ if (i % 2 === 1) {
198
+ await page.locator('button:has-text("Copy")').first().click({ timeout: 500 }).catch(() => {});
199
+ await page.locator('[class*="copy"] button, [class*="Copy"] button, button[class*="copy"]').first().click({ timeout: 500 }).catch(() => {});
200
+ await page.waitForTimeout(500);
201
+ try {
202
+ const { execSync: es } = require('child_process');
203
+ const clip = es('powershell -Command "Get-Clipboard"', { encoding: 'utf-8', timeout: 3000 }).trim();
204
+ if (clip && clip.includes('.') && clip.length > 50 && clip.length < 200 && !clip.includes(' ')) {
205
+ token = clip;
206
+ log.push('SOURCE:clipboard');
207
+ break;
208
+ }
209
+ } catch {}
210
+ }
211
+ if (i % 5 === 0) log.push('POLL:' + (i * 2) + 's');
212
+ }
213
+
214
+ // Write debug log
215
+ fs.writeFileSync('C:\\\\temp\\\\discord-debug.log', log.join('\\n') + '\\nTOKEN_LEN:' + token.length + '\\nAPI_LEN:' + tokenFromApi.length);
216
+
217
+ if (!token && tokenFromApi) token = tokenFromApi;
218
+ if (!token) {
219
+ console.log('TOKEN_NOT_FOUND');
220
+ }
221
+
222
+ // Enable intents
223
+ await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
224
+ await page.waitForTimeout(1500);
225
+ await page.locator('text=Privileged Gateway Intents').scrollIntoViewIfNeeded().catch(() => {});
226
+ await page.waitForTimeout(1000);
227
+ const switches = await page.locator('label[data-react-aria-pressable="true"] input[role="switch"]').all();
228
+ let toggled = 0;
229
+ for (const sw of switches) {
230
+ if (!await sw.isChecked().catch(() => true)) {
231
+ await sw.locator('..').locator('..').first().click({ force: true }).catch(() => {});
232
+ await page.waitForTimeout(500);
233
+ toggled++;
234
+ }
235
+ }
236
+ await page.click('button:has-text("Save Changes")', { timeout: 3000 }).catch(() => {});
237
+ console.log('INTENTS_ENABLED:' + toggled);
238
+
239
+ // Save result
240
+ const result = { token, appId, success: !!token };
241
+ fs.writeFileSync('C:\\\\temp\\\\discord-bot-result.json', JSON.stringify(result));
242
+ if (token) console.log('TOKEN:' + token);
243
+ console.log('DONE');
244
+ await ctx.close();
245
+ })().catch(e => console.error('FATAL:' + e.message));
246
+ `;
247
+ const output = winExec(script, 600_000);
248
+ // Parse output
249
+ const lines = output.split("\n");
250
+ let appId = "";
251
+ let token = "";
252
+ for (const line of lines) {
253
+ if (line.startsWith("APP_CREATED:"))
254
+ appId = line.replace("APP_CREATED:", "");
255
+ if (line.startsWith("TOKEN:"))
256
+ token = line.replace("TOKEN:", "");
257
+ if (line === "LOGIN_REQUIRED")
258
+ console.log(` ${c.yellow}Log in to Discord in the browser window...${c.reset}`);
259
+ if (line === "LOGGED_IN")
260
+ console.log(` ${c.green}✓${c.reset} Logged in`);
261
+ if (line === "CREATE_CLICKED")
262
+ console.log(` ${c.dim}Creating app — solve captcha if shown...${c.reset}`);
263
+ if (line.startsWith("APP_CREATED"))
264
+ console.log(` ${c.green}✓${c.reset} App created: ${appId}`);
265
+ if (line === "TOKEN_RESET")
266
+ console.log(` ${c.dim}Token reset — complete MFA if shown...${c.reset}`);
267
+ if (line.startsWith("POLLING"))
268
+ console.log(` ${c.dim}Waiting for token... ${line.replace("POLLING:", "")}${c.reset}`);
269
+ if (line.startsWith("INTENTS_ENABLED"))
270
+ console.log(` ${c.green}✓${c.reset} Intents enabled: ${line.replace("INTENTS_ENABLED:", "")}`);
271
+ if (line === "TRYING_CLIPBOARD")
272
+ console.log(` ${c.dim}Checking clipboard...${c.reset}`);
273
+ }
274
+ // If token not from DOM, try clipboard
275
+ if (!token) {
276
+ const psCmd = isNativeWin
277
+ ? 'powershell -Command "Get-Clipboard" 2>/dev/null'
278
+ : '/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -Command "Get-Clipboard" 2>/dev/null';
279
+ token = tryExec(psCmd);
280
+ if (token && token.includes(".") && token.length > 50) {
281
+ console.log(` ${c.green}✓${c.reset} Token captured from clipboard`);
282
+ }
283
+ else {
284
+ token = "";
285
+ }
286
+ }
287
+ // Also try saved result
288
+ if (!token) {
289
+ try {
290
+ const saved = JSON.parse(readFileSync(`${tempDirPosix}/discord-bot-result.json`, "utf-8"));
291
+ if (saved.token)
292
+ token = saved.token;
293
+ if (saved.appId && !appId)
294
+ appId = saved.appId;
295
+ }
296
+ catch { }
297
+ }
298
+ if (token) {
299
+ console.log(` ${c.green}✓${c.reset} Token: ${token.substring(0, 25)}...`);
300
+ }
301
+ else {
302
+ console.log(` ${c.red}✗${c.reset} Could not capture token`);
303
+ }
304
+ return { token, appId, success: !!token };
305
+ }
306
+ /**
307
+ * Authorize (invite) a Discord bot to a server.
308
+ * Opens invite page, selects server, clicks authorize, waits for captcha.
309
+ */
310
+ export async function authorizeDiscordBot(appId) {
311
+ ensurePatchright();
312
+ const browserChannel = detectBrowserChannel();
313
+ console.log(`\n ${c.dim}Opening invite page...${c.reset}`);
314
+ const script = `
315
+ const { chromium } = require('patchright');
316
+ (async () => {
317
+ const ctx = await chromium.launchPersistentContext('C:\\\\temp\\\\notoken-browser-profile', {
318
+ headless: false, channel: '${browserChannel}',
319
+ args: ['--disable-blink-features=AutomationControlled'],
320
+ viewport: { width: 1280, height: 900 },
321
+ });
322
+ const page = ctx.pages()[0] || await ctx.newPage();
323
+
324
+ await page.goto('https://discord.com/oauth2/authorize?client_id=${appId}&permissions=68608&scope=bot', { timeout: 30000 });
325
+ await page.waitForLoadState('networkidle').catch(() => {});
326
+ await page.waitForTimeout(5000);
327
+
328
+ // Select server
329
+ await page.locator('[role="combobox"]').click({ timeout: 5000 });
330
+ await page.waitForTimeout(2000);
331
+ const opt = page.locator('[role="option"]').first();
332
+ const name = await opt.textContent().catch(() => '');
333
+ console.log('SERVER:' + name);
334
+ await opt.click();
335
+ await page.waitForTimeout(1000);
336
+
337
+ // Continue
338
+ await page.click('button:has-text("Continue")', { timeout: 3000 }).catch(() => {});
339
+ await page.waitForTimeout(3000);
340
+
341
+ // Authorize
342
+ await page.click('button:has-text("Authorize")', { timeout: 5000 }).catch(() => {});
343
+ console.log('AUTHORIZE_CLICKED');
344
+
345
+ // Wait for captcha resolution — poll for redirect
346
+ for (let i = 0; i < 90; i++) {
347
+ await page.waitForTimeout(2000);
348
+ if (page.url().includes('authorized')) { console.log('AUTHORIZED'); break; }
349
+ if (i % 15 === 0 && i > 0) console.log('WAITING_CAPTCHA:' + (i * 2) + 's');
350
+ }
351
+
352
+ await ctx.close();
353
+ })().catch(e => console.error('FATAL:' + e.message));
354
+ `;
355
+ const output = winExec(script, 300_000);
356
+ for (const line of output.split("\n")) {
357
+ if (line.startsWith("SERVER:"))
358
+ console.log(` ${c.green}✓${c.reset} Server: ${line.replace("SERVER:", "")}`);
359
+ if (line === "AUTHORIZE_CLICKED")
360
+ console.log(` ${c.dim}Authorize clicked — solve captcha if shown...${c.reset}`);
361
+ if (line.startsWith("WAITING_CAPTCHA"))
362
+ console.log(` ${c.dim}Waiting... ${line.replace("WAITING_CAPTCHA:", "")}${c.reset}`);
363
+ if (line === "AUTHORIZED")
364
+ console.log(` ${c.green}✓${c.reset} Bot authorized!`);
365
+ }
366
+ return output.includes("AUTHORIZED");
367
+ }
368
+ /**
369
+ * Enable all Privileged Gateway Intents on the Discord Developer Portal.
370
+ */
371
+ export async function enableDiscordIntents(appId) {
372
+ ensurePatchright();
373
+ const browserChannel = detectBrowserChannel();
374
+ console.log(` ${c.dim}Enabling intents on Developer Portal...${c.reset}`);
375
+ const script = `
376
+ const { chromium } = require('patchright');
377
+ (async () => {
378
+ const ctx = await chromium.launchPersistentContext('C:\\\\temp\\\\notoken-browser-profile', {
379
+ headless: false, channel: '${browserChannel}',
380
+ args: ['--disable-blink-features=AutomationControlled'],
381
+ viewport: { width: 1280, height: 900 },
382
+ });
383
+ const page = ctx.pages()[0] || await ctx.newPage();
384
+
385
+ await page.goto('https://discord.com/developers/applications/${appId}/bot', { timeout: 60000 });
386
+ await page.waitForLoadState('networkidle').catch(() => {});
387
+ await page.waitForTimeout(5000);
388
+
389
+ // Login if needed
390
+ if (await page.locator('button:has-text("Log In")').first().isVisible({ timeout: 2000 }).catch(() => false)) {
391
+ await page.locator('button:has-text("Log In")').first().click();
392
+ console.log('LOGIN_REQUIRED');
393
+ await page.waitForURL('**/${appId}/bot**', { timeout: 600000 });
394
+ await page.waitForTimeout(3000);
395
+ }
396
+
397
+ // Scroll to intents
398
+ await page.locator('text=Privileged Gateway Intents').scrollIntoViewIfNeeded().catch(() => {});
399
+ await page.waitForTimeout(2000);
400
+
401
+ // Enable unchecked switches
402
+ const switches = await page.locator('label[data-react-aria-pressable="true"] input[role="switch"]').all();
403
+ let toggled = 0;
404
+ for (const sw of switches) {
405
+ if (!await sw.isChecked().catch(() => true)) {
406
+ await sw.locator('..').locator('..').first().click({ force: true }).catch(() => {});
407
+ await page.waitForTimeout(500);
408
+ toggled++;
409
+ }
410
+ }
411
+
412
+ await page.click('button:has-text("Save Changes")', { timeout: 3000 }).catch(() => {});
413
+ await page.waitForTimeout(2000);
414
+ console.log('ENABLED:' + toggled);
415
+ await ctx.close();
416
+ })().catch(e => console.error('FATAL:' + e.message));
417
+ `;
418
+ const output = winExec(script, 120_000);
419
+ const enabled = output.includes("ENABLED:");
420
+ const count = output.match(/ENABLED:(\d+)/)?.[1] ?? "0";
421
+ if (enabled)
422
+ console.log(` ${c.green}✓${c.reset} Enabled ${count} intent(s)`);
423
+ return enabled;
424
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Automated Discord bot setup via Playwright.
3
+ *
4
+ * Opens the Discord Developer Portal, walks the user through login,
5
+ * then automates: create application, create bot, copy token, enable
6
+ * Message Content Intent, generate OAuth2 invite URL, open it.
7
+ *
8
+ * The user only needs to:
9
+ * 1. Log in to Discord (notoken never touches credentials)
10
+ * 2. Pick which server to add the bot to
11
+ *
12
+ * Returns the bot token for OpenClaw channel registration.
13
+ */
14
+ export interface DiscordSetupResult {
15
+ success: boolean;
16
+ botToken?: string;
17
+ applicationId?: string;
18
+ inviteUrl?: string;
19
+ error?: string;
20
+ }
21
+ /**
22
+ * Run the automated Discord bot setup.
23
+ *
24
+ * @param appName - Name for the Discord application (default: "OpenClaw")
25
+ * @param headless - Run headless (default: false — user needs to see login)
26
+ */
27
+ export declare function automateDiscordBotSetup(appName?: string, headless?: boolean): Promise<DiscordSetupResult>;
28
+ /**
29
+ * Full Discord setup flow — automate browser + register with OpenClaw.
30
+ */
31
+ export declare function setupDiscordChannel(appName?: string): Promise<string>;