notoken-core 1.6.0 → 1.8.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/config/ascii-art.json +12 -0
- package/config/chat-responses.json +1019 -0
- package/config/cheat-sheets.json +94 -0
- package/config/concept-clusters.json +31 -0
- package/config/daily-tips.json +105 -0
- package/config/entities.json +93 -0
- package/config/history-today.json +9762 -0
- package/config/image-prompts.json +20 -0
- package/config/intent-vectors.json +1 -0
- package/config/intents.json +5354 -85
- package/config/ollama-models.json +193 -0
- package/config/rules.json +32 -1
- package/config/startup-quotes.json +45 -0
- package/dist/automation/discordPatchright.d.ts +35 -0
- package/dist/automation/discordPatchright.js +424 -0
- package/dist/automation/discordSetup.d.ts +31 -0
- package/dist/automation/discordSetup.js +338 -0
- package/dist/automation/smAutomation.d.ts +82 -0
- package/dist/automation/smAutomation.js +448 -0
- package/dist/conversation/coreference.js +44 -4
- package/dist/conversation/pendingActions.d.ts +55 -0
- package/dist/conversation/pendingActions.js +127 -0
- package/dist/conversation/store.d.ts +72 -0
- package/dist/conversation/store.js +140 -1
- package/dist/conversation/topicTracker.d.ts +36 -0
- package/dist/conversation/topicTracker.js +141 -0
- package/dist/execution/ssh.d.ts +42 -1
- package/dist/execution/ssh.js +538 -3
- package/dist/handlers/executor.d.ts +2 -0
- package/dist/handlers/executor.js +4234 -31
- package/dist/index.d.ts +35 -4
- package/dist/index.js +51 -3
- package/dist/nlp/batchParser.d.ts +30 -0
- package/dist/nlp/batchParser.js +77 -0
- package/dist/nlp/conceptExpansion.d.ts +54 -0
- package/dist/nlp/conceptExpansion.js +136 -0
- package/dist/nlp/conceptRouter.d.ts +49 -0
- package/dist/nlp/conceptRouter.js +302 -0
- package/dist/nlp/confidenceCalibrator.d.ts +62 -0
- package/dist/nlp/confidenceCalibrator.js +116 -0
- package/dist/nlp/correctionLearner.d.ts +45 -0
- package/dist/nlp/correctionLearner.js +207 -0
- package/dist/nlp/entitySpellCorrect.d.ts +35 -0
- package/dist/nlp/entitySpellCorrect.js +141 -0
- package/dist/nlp/knowledgeGraph.d.ts +70 -0
- package/dist/nlp/knowledgeGraph.js +380 -0
- package/dist/nlp/llmFallback.js +28 -1
- package/dist/nlp/multiClassifier.js +91 -6
- package/dist/nlp/multiIntent.d.ts +43 -0
- package/dist/nlp/multiIntent.js +154 -0
- package/dist/nlp/parseIntent.d.ts +6 -1
- package/dist/nlp/parseIntent.js +180 -5
- package/dist/nlp/ruleParser.js +317 -0
- package/dist/nlp/semanticSimilarity.d.ts +30 -0
- package/dist/nlp/semanticSimilarity.js +174 -0
- package/dist/nlp/vocabularyBuilder.d.ts +43 -0
- package/dist/nlp/vocabularyBuilder.js +224 -0
- package/dist/nlp/wikidata.d.ts +49 -0
- package/dist/nlp/wikidata.js +228 -0
- package/dist/policy/confirm.d.ts +10 -0
- package/dist/policy/confirm.js +39 -0
- package/dist/policy/safety.js +6 -4
- package/dist/types/intent.d.ts +8 -0
- package/dist/types/intent.js +1 -0
- package/dist/utils/achievements.d.ts +38 -0
- package/dist/utils/achievements.js +126 -0
- package/dist/utils/aliases.d.ts +5 -0
- package/dist/utils/aliases.js +39 -0
- package/dist/utils/analysis.js +71 -15
- package/dist/utils/bookmarks.d.ts +13 -0
- package/dist/utils/bookmarks.js +51 -0
- package/dist/utils/browser.d.ts +64 -0
- package/dist/utils/browser.js +364 -0
- package/dist/utils/commandHistory.d.ts +20 -0
- package/dist/utils/commandHistory.js +108 -0
- package/dist/utils/completer.d.ts +17 -0
- package/dist/utils/completer.js +79 -0
- package/dist/utils/config.js +32 -2
- package/dist/utils/dbQuery.d.ts +25 -0
- package/dist/utils/dbQuery.js +248 -0
- package/dist/utils/devTools.d.ts +35 -0
- package/dist/utils/devTools.js +95 -0
- package/dist/utils/discordDiag.d.ts +35 -0
- package/dist/utils/discordDiag.js +826 -0
- package/dist/utils/diskCleanup.d.ts +36 -0
- package/dist/utils/diskCleanup.js +775 -0
- package/dist/utils/entityResolver.d.ts +107 -0
- package/dist/utils/entityResolver.js +468 -0
- package/dist/utils/imageGen.d.ts +92 -0
- package/dist/utils/imageGen.js +2031 -0
- package/dist/utils/installTracker.d.ts +57 -0
- package/dist/utils/installTracker.js +160 -0
- package/dist/utils/multiExec.d.ts +21 -0
- package/dist/utils/multiExec.js +141 -0
- package/dist/utils/openclawDiag.d.ts +29 -0
- package/dist/utils/openclawDiag.js +1035 -0
- package/dist/utils/output.js +4 -0
- package/dist/utils/platform.js +2 -1
- package/dist/utils/progressReporter.d.ts +50 -0
- package/dist/utils/progressReporter.js +58 -0
- package/dist/utils/projectDetect.d.ts +44 -0
- package/dist/utils/projectDetect.js +319 -0
- package/dist/utils/projectScanner.d.ts +44 -0
- package/dist/utils/projectScanner.js +312 -0
- package/dist/utils/shellCompat.d.ts +78 -0
- package/dist/utils/shellCompat.js +186 -0
- package/dist/utils/smartArchive.d.ts +16 -0
- package/dist/utils/smartArchive.js +172 -0
- package/dist/utils/smartRetry.d.ts +26 -0
- package/dist/utils/smartRetry.js +114 -0
- package/dist/utils/snippets.d.ts +13 -0
- package/dist/utils/snippets.js +53 -0
- package/dist/utils/stabilityMatrixManager.d.ts +80 -0
- package/dist/utils/stabilityMatrixManager.js +268 -0
- package/dist/utils/teachMode.d.ts +41 -0
- package/dist/utils/teachMode.js +100 -0
- package/dist/utils/timer.d.ts +22 -0
- package/dist/utils/timer.js +52 -0
- package/dist/utils/updater.d.ts +1 -0
- package/dist/utils/updater.js +1 -1
- package/dist/utils/version.d.ts +20 -0
- package/dist/utils/version.js +212 -0
- package/package.json +6 -3
|
@@ -0,0 +1,338 @@
|
|
|
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
|
+
const c = {
|
|
15
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
16
|
+
green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m",
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Detect available browser executable on the system.
|
|
20
|
+
* Prefers Edge (available on Windows), falls back to Chrome, then Chromium.
|
|
21
|
+
*/
|
|
22
|
+
async function findBrowserPath() {
|
|
23
|
+
const { execSync } = await import("node:child_process");
|
|
24
|
+
const candidates = [
|
|
25
|
+
// Windows browsers via WSL
|
|
26
|
+
"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
|
|
27
|
+
"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
|
|
28
|
+
"/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
29
|
+
// Linux browsers
|
|
30
|
+
"/usr/bin/google-chrome",
|
|
31
|
+
"/usr/bin/chromium-browser",
|
|
32
|
+
"/usr/bin/chromium",
|
|
33
|
+
"/usr/bin/microsoft-edge",
|
|
34
|
+
];
|
|
35
|
+
for (const path of candidates) {
|
|
36
|
+
try {
|
|
37
|
+
execSync(`ls "${path}" 2>/dev/null`, { stdio: "pipe" });
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
|
+
catch { /* not found */ }
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Run the automated Discord bot setup.
|
|
46
|
+
*
|
|
47
|
+
* @param appName - Name for the Discord application (default: "OpenClaw")
|
|
48
|
+
* @param headless - Run headless (default: false — user needs to see login)
|
|
49
|
+
*/
|
|
50
|
+
export async function automateDiscordBotSetup(appName = "OpenClaw", headless = false) {
|
|
51
|
+
// Dynamic import — Playwright is optional, not a core dependency
|
|
52
|
+
let playwright;
|
|
53
|
+
try {
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
55
|
+
playwright = await Function('return import("playwright")')();
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
error: "Playwright not installed. Run: npm install -g playwright && npx playwright install chromium",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const browserPath = await findBrowserPath();
|
|
64
|
+
console.log(`\n${c.bold}${c.cyan}── Discord Bot Setup ──${c.reset}\n`);
|
|
65
|
+
let browser;
|
|
66
|
+
let context;
|
|
67
|
+
let page;
|
|
68
|
+
try {
|
|
69
|
+
// Launch browser — use Windows Edge if available for visible UI
|
|
70
|
+
console.log(` ${c.dim}Launching browser...${c.reset}`);
|
|
71
|
+
if (browserPath?.includes("/mnt/c/")) {
|
|
72
|
+
// Windows browser via WSL — use channel launch
|
|
73
|
+
const winPath = browserPath
|
|
74
|
+
.replace("/mnt/c/", "C:\\")
|
|
75
|
+
.replace(/\//g, "\\");
|
|
76
|
+
browser = await playwright.chromium.launch({
|
|
77
|
+
headless: false, // Must be visible for user login
|
|
78
|
+
executablePath: browserPath,
|
|
79
|
+
args: ["--no-sandbox"],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
browser = await playwright.chromium.launch({
|
|
84
|
+
headless,
|
|
85
|
+
args: ["--no-sandbox"],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
context = await browser.newContext({
|
|
89
|
+
viewport: { width: 1280, height: 900 },
|
|
90
|
+
});
|
|
91
|
+
page = await context.newPage();
|
|
92
|
+
// ── Step 1: Navigate to Discord Developer Portal ──
|
|
93
|
+
console.log(` ${c.bold}1.${c.reset} Opening Discord Developer Portal...`);
|
|
94
|
+
await page.goto("https://discord.com/developers/applications", {
|
|
95
|
+
waitUntil: "networkidle",
|
|
96
|
+
timeout: 30_000,
|
|
97
|
+
});
|
|
98
|
+
// Check if login is needed
|
|
99
|
+
const url = page.url();
|
|
100
|
+
if (url.includes("/login")) {
|
|
101
|
+
console.log(`\n ${c.yellow}${c.bold}Please log in to Discord in the browser window.${c.reset}`);
|
|
102
|
+
console.log(` ${c.dim}Waiting for you to complete login...${c.reset}\n`);
|
|
103
|
+
// Wait for redirect to developer portal after login (up to 5 minutes)
|
|
104
|
+
await page.waitForURL("**/developers/applications**", { timeout: 300_000 });
|
|
105
|
+
console.log(` ${c.green}✓${c.reset} Logged in successfully!\n`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.log(` ${c.green}✓${c.reset} Already logged in.\n`);
|
|
109
|
+
}
|
|
110
|
+
// ── Step 2: Create New Application ──
|
|
111
|
+
console.log(` ${c.bold}2.${c.reset} Creating application "${appName}"...`);
|
|
112
|
+
await page.waitForTimeout(2000);
|
|
113
|
+
// Click "New Application" button
|
|
114
|
+
const newAppBtn = page.locator('button:has-text("New Application"), div[class*="actionButton"]:has-text("New Application")');
|
|
115
|
+
await newAppBtn.waitFor({ timeout: 10_000 });
|
|
116
|
+
await newAppBtn.click();
|
|
117
|
+
// Fill in the application name
|
|
118
|
+
await page.waitForTimeout(1000);
|
|
119
|
+
const nameInput = page.locator('input[placeholder*="name"], input[name="name"]').first();
|
|
120
|
+
await nameInput.waitFor({ timeout: 5_000 });
|
|
121
|
+
await nameInput.fill(appName);
|
|
122
|
+
// Check the ToS checkbox if present
|
|
123
|
+
const tosCheckbox = page.locator('input[type="checkbox"], label:has-text("policy")').first();
|
|
124
|
+
if (await tosCheckbox.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
125
|
+
await tosCheckbox.click();
|
|
126
|
+
}
|
|
127
|
+
// Click Create
|
|
128
|
+
const createBtn = page.locator('button:has-text("Create")').first();
|
|
129
|
+
await createBtn.click();
|
|
130
|
+
await page.waitForTimeout(3000);
|
|
131
|
+
// Get the application ID from the URL
|
|
132
|
+
const appUrl = page.url();
|
|
133
|
+
const appIdMatch = appUrl.match(/applications\/(\d+)/);
|
|
134
|
+
const applicationId = appIdMatch?.[1] ?? "";
|
|
135
|
+
console.log(` ${c.green}✓${c.reset} Application created${applicationId ? ` (ID: ${applicationId})` : ""}\n`);
|
|
136
|
+
// ── Step 3: Navigate to Bot tab and create bot ──
|
|
137
|
+
console.log(` ${c.bold}3.${c.reset} Setting up bot...`);
|
|
138
|
+
// Click "Bot" in sidebar
|
|
139
|
+
const botTab = page.locator('a:has-text("Bot"), div[class*="item"]:has-text("Bot")').first();
|
|
140
|
+
await botTab.click();
|
|
141
|
+
await page.waitForTimeout(2000);
|
|
142
|
+
// Click "Reset Token" or "Add Bot" if needed
|
|
143
|
+
const resetTokenBtn = page.locator('button:has-text("Reset Token")').first();
|
|
144
|
+
const addBotBtn = page.locator('button:has-text("Add Bot")').first();
|
|
145
|
+
if (await addBotBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
146
|
+
await addBotBtn.click();
|
|
147
|
+
await page.waitForTimeout(1000);
|
|
148
|
+
// Confirm
|
|
149
|
+
const confirmBtn = page.locator('button:has-text("Yes, do it!")').first();
|
|
150
|
+
if (await confirmBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
151
|
+
await confirmBtn.click();
|
|
152
|
+
}
|
|
153
|
+
await page.waitForTimeout(2000);
|
|
154
|
+
}
|
|
155
|
+
// Reset/reveal token
|
|
156
|
+
if (await resetTokenBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
157
|
+
await resetTokenBtn.click();
|
|
158
|
+
await page.waitForTimeout(1000);
|
|
159
|
+
// Confirm reset
|
|
160
|
+
const confirmReset = page.locator('button:has-text("Yes, do it!")').first();
|
|
161
|
+
if (await confirmReset.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
162
|
+
await confirmReset.click();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Wait for token to appear and copy it
|
|
166
|
+
await page.waitForTimeout(2000);
|
|
167
|
+
let botToken = "";
|
|
168
|
+
// Try to find the token in an input or code element
|
|
169
|
+
const tokenInput = page.locator('input[value*="."], span[class*="token"], div[class*="token"] input').first();
|
|
170
|
+
if (await tokenInput.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
171
|
+
botToken = await tokenInput.inputValue().catch(() => "");
|
|
172
|
+
if (!botToken) {
|
|
173
|
+
botToken = await tokenInput.textContent().catch(() => "") ?? "";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Try clicking "Copy" button if token not grabbed directly
|
|
177
|
+
if (!botToken) {
|
|
178
|
+
const copyBtn = page.locator('button:has-text("Copy")').first();
|
|
179
|
+
if (await copyBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
180
|
+
await copyBtn.click();
|
|
181
|
+
// Token is now in clipboard — try to read it
|
|
182
|
+
try {
|
|
183
|
+
botToken = await page.evaluate(() => navigator.clipboard.readText());
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// Clipboard access denied — ask user
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (botToken) {
|
|
191
|
+
console.log(` ${c.green}✓${c.reset} Bot token captured\n`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.log(` ${c.yellow}⚠${c.reset} Could not auto-capture token.`);
|
|
195
|
+
console.log(` ${c.bold}Please copy the bot token from the browser and paste it here.${c.reset}\n`);
|
|
196
|
+
}
|
|
197
|
+
// ── Step 4: Enable Message Content Intent ──
|
|
198
|
+
console.log(` ${c.bold}4.${c.reset} Enabling Message Content Intent...`);
|
|
199
|
+
// Scroll down to Privileged Gateway Intents
|
|
200
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
201
|
+
await page.waitForTimeout(1000);
|
|
202
|
+
// Find and enable Message Content Intent toggle
|
|
203
|
+
const messageContentLabel = page.locator('text=Message Content Intent, label:has-text("MESSAGE CONTENT INTENT")').first();
|
|
204
|
+
if (await messageContentLabel.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
205
|
+
// Find the toggle near this label
|
|
206
|
+
const toggle = page.locator('div:has-text("MESSAGE CONTENT INTENT") input[type="checkbox"], div:has-text("Message Content Intent") [role="switch"]').first();
|
|
207
|
+
if (await toggle.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
208
|
+
const isChecked = await toggle.isChecked().catch(() => false);
|
|
209
|
+
if (!isChecked) {
|
|
210
|
+
await toggle.click();
|
|
211
|
+
await page.waitForTimeout(500);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Save changes
|
|
216
|
+
const saveBtn = page.locator('button:has-text("Save Changes")').first();
|
|
217
|
+
if (await saveBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
218
|
+
await saveBtn.click();
|
|
219
|
+
await page.waitForTimeout(1000);
|
|
220
|
+
}
|
|
221
|
+
console.log(` ${c.green}✓${c.reset} Message Content Intent enabled\n`);
|
|
222
|
+
// ── Step 5: Generate OAuth2 invite URL ──
|
|
223
|
+
console.log(` ${c.bold}5.${c.reset} Generating invite URL...`);
|
|
224
|
+
// Navigate to OAuth2 → URL Generator
|
|
225
|
+
const oauth2Tab = page.locator('a:has-text("OAuth2"), div[class*="item"]:has-text("OAuth2")').first();
|
|
226
|
+
await oauth2Tab.click();
|
|
227
|
+
await page.waitForTimeout(1000);
|
|
228
|
+
// Look for URL Generator sub-tab
|
|
229
|
+
const urlGenTab = page.locator('a:has-text("URL Generator"), div:has-text("URL Generator")').first();
|
|
230
|
+
if (await urlGenTab.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
231
|
+
await urlGenTab.click();
|
|
232
|
+
await page.waitForTimeout(1000);
|
|
233
|
+
}
|
|
234
|
+
// Select "bot" scope
|
|
235
|
+
const botScope = page.locator('label:has-text("bot"), input[value="bot"]').first();
|
|
236
|
+
if (await botScope.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
237
|
+
await botScope.click();
|
|
238
|
+
await page.waitForTimeout(1000);
|
|
239
|
+
}
|
|
240
|
+
// Select permissions: Send Messages, Read Messages
|
|
241
|
+
for (const perm of ["Send Messages", "Read Message History", "View Channels"]) {
|
|
242
|
+
const permLabel = page.locator(`label:has-text("${perm}")`).first();
|
|
243
|
+
if (await permLabel.isVisible({ timeout: 1000 }).catch(() => false)) {
|
|
244
|
+
await permLabel.click();
|
|
245
|
+
await page.waitForTimeout(300);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Copy the generated URL
|
|
249
|
+
await page.waitForTimeout(1000);
|
|
250
|
+
let inviteUrl = "";
|
|
251
|
+
const urlInput = page.locator('input[value*="discord.com/oauth2"], input[value*="discord.com/api/oauth2"]').first();
|
|
252
|
+
if (await urlInput.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
253
|
+
inviteUrl = await urlInput.inputValue();
|
|
254
|
+
}
|
|
255
|
+
if (inviteUrl) {
|
|
256
|
+
console.log(` ${c.green}✓${c.reset} Invite URL generated\n`);
|
|
257
|
+
// ── Step 6: Open invite URL to add bot to server ──
|
|
258
|
+
console.log(` ${c.bold}6.${c.reset} Opening bot invite page...`);
|
|
259
|
+
console.log(` ${c.yellow}${c.bold}Pick your Discord server in the browser to add the bot.${c.reset}\n`);
|
|
260
|
+
await page.goto(inviteUrl);
|
|
261
|
+
// Wait for user to authorize (page changes after clicking Authorize)
|
|
262
|
+
await page.waitForURL("**/oauth2/authorized**", { timeout: 120_000 }).catch(() => { });
|
|
263
|
+
console.log(` ${c.green}✓${c.reset} Bot added to server!\n`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
console.log(` ${c.yellow}⚠${c.reset} Could not auto-generate invite URL.`);
|
|
267
|
+
if (applicationId) {
|
|
268
|
+
inviteUrl = `https://discord.com/api/oauth2/authorize?client_id=${applicationId}&permissions=68608&scope=bot`;
|
|
269
|
+
console.log(` ${c.dim}Manual invite URL: ${inviteUrl}${c.reset}\n`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Close browser
|
|
273
|
+
await browser.close();
|
|
274
|
+
return {
|
|
275
|
+
success: !!botToken,
|
|
276
|
+
botToken: botToken || undefined,
|
|
277
|
+
applicationId: applicationId || undefined,
|
|
278
|
+
inviteUrl: inviteUrl || undefined,
|
|
279
|
+
error: botToken ? undefined : "Could not auto-capture bot token. Please copy it manually from the Discord Developer Portal.",
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
const msg = err.message ?? String(err);
|
|
284
|
+
console.log(`\n ${c.red}✗ Automation error: ${msg.split("\n")[0]}${c.reset}`);
|
|
285
|
+
// Try to close browser gracefully
|
|
286
|
+
try {
|
|
287
|
+
await browser?.close();
|
|
288
|
+
}
|
|
289
|
+
catch { /* */ }
|
|
290
|
+
return { success: false, error: msg };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Full Discord setup flow — automate browser + register with OpenClaw.
|
|
295
|
+
*/
|
|
296
|
+
export async function setupDiscordChannel(appName = "OpenClaw") {
|
|
297
|
+
const result = await automateDiscordBotSetup(appName);
|
|
298
|
+
if (result.success && result.botToken) {
|
|
299
|
+
// Register with OpenClaw
|
|
300
|
+
console.log(`${c.bold}${c.cyan}── Registering with OpenClaw ──${c.reset}\n`);
|
|
301
|
+
try {
|
|
302
|
+
const { execSync } = await import("node:child_process");
|
|
303
|
+
const nvmPrefix = `for d in "$HOME/.nvm" "/home/"*"/.nvm" "/root/.nvm"; do [ -s "$d/nvm.sh" ] && export NVM_DIR="$d" && . "$d/nvm.sh" && break; done 2>/dev/null; nvm use 22 > /dev/null 2>&1;`;
|
|
304
|
+
// Try direct Node 22 path first
|
|
305
|
+
const node22Paths = ["/home/ino/.nvm/versions/node/v22.22.2/bin/node"];
|
|
306
|
+
let node22 = "node";
|
|
307
|
+
for (const p of node22Paths) {
|
|
308
|
+
try {
|
|
309
|
+
execSync(`ls "${p}"`, { stdio: "pipe" });
|
|
310
|
+
node22 = p;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
catch { /* */ }
|
|
314
|
+
}
|
|
315
|
+
const ocBin = execSync("readlink -f $(which openclaw) 2>/dev/null || which openclaw", { encoding: "utf-8" }).trim();
|
|
316
|
+
execSync(`${node22} ${ocBin} channels add --channel discord --token "${result.botToken}"`, { stdio: "inherit", timeout: 15_000 });
|
|
317
|
+
console.log(`\n ${c.green}✓${c.reset} Discord channel registered with OpenClaw!`);
|
|
318
|
+
// Restart gateway to pick up new channel
|
|
319
|
+
console.log(` ${c.dim}Restarting gateway...${c.reset}`);
|
|
320
|
+
execSync("pkill -f openclaw-gateway 2>/dev/null", { stdio: "pipe" }).toString();
|
|
321
|
+
return [
|
|
322
|
+
`\n${c.green}${c.bold}✓ Discord bot setup complete!${c.reset}\n`,
|
|
323
|
+
` ${c.bold}Bot:${c.reset} ${appName}`,
|
|
324
|
+
result.applicationId ? ` ${c.bold}App ID:${c.reset} ${result.applicationId}` : "",
|
|
325
|
+
` ${c.bold}Channel:${c.reset} Discord — registered with OpenClaw`,
|
|
326
|
+
`\n ${c.dim}Restart OpenClaw: "restart openclaw"${c.reset}`,
|
|
327
|
+
` ${c.dim}Then chat with OpenClaw in your Discord server!${c.reset}`,
|
|
328
|
+
].filter(Boolean).join("\n");
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
return `${c.yellow}⚠${c.reset} Bot created but OpenClaw registration failed.\n Token: ${result.botToken}\n ${c.dim}Register manually: openclaw channels add --channel discord --token ${result.botToken}${c.reset}`;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (result.error) {
|
|
335
|
+
return `${c.yellow}⚠${c.reset} ${result.error}\n\n ${c.dim}If you have the token, say: "setup discord with token YOUR_TOKEN"${c.reset}`;
|
|
336
|
+
}
|
|
337
|
+
return `${c.red}✗ Discord setup failed.${c.reset}`;
|
|
338
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stability Matrix UI Automation via PowerShell.
|
|
3
|
+
*
|
|
4
|
+
* Uses Windows UIAutomation COM API through PowerShell to:
|
|
5
|
+
* - Launch SM and wait for window
|
|
6
|
+
* - Click "Add Package" button
|
|
7
|
+
* - Select the right package (Forge, ComfyUI, etc.)
|
|
8
|
+
* - Click Install and monitor progress
|
|
9
|
+
* - Click Launch when done
|
|
10
|
+
* - Configure settings
|
|
11
|
+
*
|
|
12
|
+
* All automation runs on Windows side via PowerShell.
|
|
13
|
+
* From WSL, commands are sent through /mnt/c/.../powershell.exe
|
|
14
|
+
*/
|
|
15
|
+
import { type SMLocation } from "../utils/stabilityMatrixManager.js";
|
|
16
|
+
export declare function isSMRunning(): boolean;
|
|
17
|
+
export declare function launchSM(sm: SMLocation): boolean;
|
|
18
|
+
export declare function focusSMWindow(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Find a UI element by name/automationId and click it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function clickButton(name: string, timeout?: number): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Find a UI element by partial text match and click it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function clickByText(text: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* List all clickable elements in SM window (for debugging).
|
|
29
|
+
*/
|
|
30
|
+
export declare function listUIElements(): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Full automated install flow:
|
|
33
|
+
* 1. Launch SM
|
|
34
|
+
* 2. Click "Add Package"
|
|
35
|
+
* 3. Select package (Forge, ComfyUI, etc.)
|
|
36
|
+
* 4. Click Install
|
|
37
|
+
* 5. Wait for completion
|
|
38
|
+
* 6. Click Launch
|
|
39
|
+
*/
|
|
40
|
+
export declare function automateInstallPackage(packageName?: string): Promise<{
|
|
41
|
+
success: boolean;
|
|
42
|
+
message: string;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Launch the active package.
|
|
46
|
+
*/
|
|
47
|
+
export declare function automateLaunch(): Promise<{
|
|
48
|
+
success: boolean;
|
|
49
|
+
message: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Check SD API from the Windows side (bypasses WSL networking issues).
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkAPIFromWindows(port?: number): {
|
|
55
|
+
running: boolean;
|
|
56
|
+
statusCode: number;
|
|
57
|
+
models?: string[];
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Check what port SD is listening on from Windows.
|
|
61
|
+
*/
|
|
62
|
+
export declare function findSDPort(): number | null;
|
|
63
|
+
/**
|
|
64
|
+
* Get Python process info from Windows.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getPythonProcesses(): Array<{
|
|
67
|
+
pid: number;
|
|
68
|
+
ram: number;
|
|
69
|
+
path: string;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Full diagnostic — check everything and report.
|
|
73
|
+
*/
|
|
74
|
+
export declare function diagnoseSD(): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Stop SD — kill Python processes running the package.
|
|
77
|
+
*/
|
|
78
|
+
export declare function stopSD(): string;
|
|
79
|
+
/**
|
|
80
|
+
* Restart SD — stop then launch.
|
|
81
|
+
*/
|
|
82
|
+
export declare function restartSD(): Promise<string>;
|