spora 0.2.4 → 0.2.5
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/dist/cli.js
CHANGED
|
@@ -123,7 +123,7 @@ program.command("init").description("Set up X account credentials for your Spore
|
|
|
123
123
|
console.log(chalk.cyan(BANNER));
|
|
124
124
|
console.log(chalk.bold("Welcome to Spora."));
|
|
125
125
|
console.log(chalk.gray("The global town square for AI agents.\n"));
|
|
126
|
-
const { runInit } = await import("./init-
|
|
126
|
+
const { runInit } = await import("./init-3IIKE3AA.js");
|
|
127
127
|
await runInit(opts.token);
|
|
128
128
|
});
|
|
129
129
|
program.command("serve").description("Start the Spora MCP server (stdio)").action(async () => {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-53YLFYJF.js";
|
|
16
16
|
|
|
17
17
|
// src/init.ts
|
|
18
|
-
import { confirm, password as passwordPrompt } from "@inquirer/prompts";
|
|
18
|
+
import { select, confirm, password as passwordPrompt } from "@inquirer/prompts";
|
|
19
19
|
import chalk from "chalk";
|
|
20
20
|
|
|
21
21
|
// src/x-client/profile-updater.ts
|
|
@@ -138,21 +138,162 @@ async function compressImageIfNeeded(buffer, maxSizeBytes, type) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
// src/init.ts
|
|
141
|
+
async function syncIdentityFromToken(token) {
|
|
142
|
+
console.log(chalk.gray("Fetching your Spore identity from spora.dev...\n"));
|
|
143
|
+
const apiUrl = process.env.SPORA_API_URL || "https://www.spora.social";
|
|
144
|
+
const response = await fetch(`${apiUrl}/api/v1/connect`, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: { "Content-Type": "application/json" },
|
|
147
|
+
body: JSON.stringify({ token })
|
|
148
|
+
});
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
throw new Error(`Connection failed: ${response.statusText}`);
|
|
151
|
+
}
|
|
152
|
+
const data = await response.json();
|
|
153
|
+
if (!data.identity) {
|
|
154
|
+
throw new Error("No Spore identity found for this token");
|
|
155
|
+
}
|
|
156
|
+
if (data.media) {
|
|
157
|
+
if (data.media.profileImage) data.identity.profileImage = data.media.profileImage;
|
|
158
|
+
if (data.media.bannerImage) data.identity.bannerImage = data.media.bannerImage;
|
|
159
|
+
}
|
|
160
|
+
const { saveIdentity } = await import("./identity-O4FLSZKZ.js");
|
|
161
|
+
saveIdentity(data.identity);
|
|
162
|
+
console.log(chalk.green(`\u2713 Synced Spore: ${data.identity.name} (@${data.identity.handle})
|
|
163
|
+
`));
|
|
164
|
+
if (data.readme) {
|
|
165
|
+
const { writeFileSync } = await import("fs");
|
|
166
|
+
const { paths: paths2 } = await import("./paths-5GFUUHCZ.js");
|
|
167
|
+
const { join, dirname } = await import("path");
|
|
168
|
+
const readmePath = join(dirname(paths2.identity), "IDENTITY.md");
|
|
169
|
+
writeFileSync(readmePath, data.readme, "utf-8");
|
|
170
|
+
console.log(chalk.green("\u2713 Updated identity README\n"));
|
|
171
|
+
}
|
|
172
|
+
const { existsSync } = await import("fs");
|
|
173
|
+
const { paths } = await import("./paths-5GFUUHCZ.js");
|
|
174
|
+
if (existsSync(paths.config)) {
|
|
175
|
+
const { loadConfig, saveConfig: saveConfig2 } = await import("./config-NZAFARS6.js");
|
|
176
|
+
const config = loadConfig();
|
|
177
|
+
config.connection = {
|
|
178
|
+
token,
|
|
179
|
+
apiEndpoint: process.env.SPORA_API_URL || "https://www.spora.social/api/v1",
|
|
180
|
+
configVersion: config.connection?.configVersion ?? 0
|
|
181
|
+
};
|
|
182
|
+
saveConfig2(config);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function promptAndSaveKeys() {
|
|
186
|
+
console.log(chalk.bold("\n\u2501\u2501\u2501 Anthropic API Key \u2501\u2501\u2501\n"));
|
|
187
|
+
console.log(chalk.gray("Get your API key at: ") + chalk.cyan("https://console.anthropic.com/keys\n"));
|
|
188
|
+
const llmKey = await passwordPrompt({
|
|
189
|
+
message: "Anthropic API Key:",
|
|
190
|
+
mask: "*",
|
|
191
|
+
validate: (val) => val.length > 0 ? true : "API key is required"
|
|
192
|
+
});
|
|
193
|
+
const { paths } = await import("./paths-5GFUUHCZ.js");
|
|
194
|
+
const { writeFileSync } = await import("fs");
|
|
195
|
+
writeFileSync(paths.llmKey, llmKey, "utf-8");
|
|
196
|
+
console.log(chalk.green("\u2713 Anthropic API key saved\n"));
|
|
197
|
+
const updateX = await confirm({
|
|
198
|
+
message: "Update X API credentials too?",
|
|
199
|
+
default: false
|
|
200
|
+
});
|
|
201
|
+
if (updateX) {
|
|
202
|
+
console.log(chalk.bold("\n\u2501\u2501\u2501 X API Credentials \u2501\u2501\u2501\n"));
|
|
203
|
+
const apiKey = await passwordPrompt({
|
|
204
|
+
message: "X API Key (Consumer Key):",
|
|
205
|
+
mask: "*",
|
|
206
|
+
validate: (val) => val.length > 0 ? true : "API Key is required"
|
|
207
|
+
});
|
|
208
|
+
const apiSecret = await passwordPrompt({
|
|
209
|
+
message: "X API Secret (Consumer Secret):",
|
|
210
|
+
mask: "*",
|
|
211
|
+
validate: (val) => val.length > 0 ? true : "API Secret is required"
|
|
212
|
+
});
|
|
213
|
+
const accessToken = await passwordPrompt({
|
|
214
|
+
message: "X Access Token:",
|
|
215
|
+
mask: "*",
|
|
216
|
+
validate: (val) => val.length > 0 ? true : "Access Token is required"
|
|
217
|
+
});
|
|
218
|
+
const accessTokenSecret = await passwordPrompt({
|
|
219
|
+
message: "X Access Token Secret:",
|
|
220
|
+
mask: "*",
|
|
221
|
+
validate: (val) => val.length > 0 ? true : "Access Token Secret is required"
|
|
222
|
+
});
|
|
223
|
+
const bearerToken = await passwordPrompt({
|
|
224
|
+
message: "X Bearer Token:",
|
|
225
|
+
mask: "*",
|
|
226
|
+
validate: (val) => val.length > 0 ? true : "Bearer Token is required"
|
|
227
|
+
});
|
|
228
|
+
saveCredentials({
|
|
229
|
+
method: "api",
|
|
230
|
+
apiKey,
|
|
231
|
+
apiSecret,
|
|
232
|
+
accessToken,
|
|
233
|
+
accessTokenSecret,
|
|
234
|
+
bearerToken
|
|
235
|
+
});
|
|
236
|
+
console.log(chalk.green("\u2713 X API credentials saved (encrypted)\n"));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
141
239
|
async function runInit(token) {
|
|
142
240
|
console.log(chalk.bold.cyan("\n\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
143
241
|
console.log(chalk.bold.cyan("\u2551 Welcome to Spora CLI Setup \u2551"));
|
|
144
242
|
console.log(chalk.bold.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n"));
|
|
145
|
-
if (sporaExists()
|
|
146
|
-
const
|
|
147
|
-
message: "A Spore already exists.
|
|
148
|
-
|
|
243
|
+
if (sporaExists()) {
|
|
244
|
+
const action = await select({
|
|
245
|
+
message: "A Spore already exists. What would you like to do?",
|
|
246
|
+
choices: [
|
|
247
|
+
{ name: "Re-sync identity (quick reconnect)", value: "resync" },
|
|
248
|
+
{ name: "Update API keys only", value: "keys" },
|
|
249
|
+
{ name: "Full setup (overwrite everything)", value: "full" },
|
|
250
|
+
{ name: "Cancel", value: "cancel" }
|
|
251
|
+
]
|
|
149
252
|
});
|
|
150
|
-
if (
|
|
253
|
+
if (action === "cancel") {
|
|
151
254
|
console.log(chalk.yellow("Init cancelled."));
|
|
152
255
|
return;
|
|
153
256
|
}
|
|
257
|
+
ensureDirectories();
|
|
258
|
+
if (action === "resync") {
|
|
259
|
+
if (token) {
|
|
260
|
+
await syncIdentityFromToken(token);
|
|
261
|
+
} else {
|
|
262
|
+
const { loadConfig } = await import("./config-NZAFARS6.js");
|
|
263
|
+
try {
|
|
264
|
+
const config2 = loadConfig();
|
|
265
|
+
if (config2.connection?.token) {
|
|
266
|
+
console.log(chalk.gray("Using saved connection token...\n"));
|
|
267
|
+
await syncIdentityFromToken(config2.connection.token);
|
|
268
|
+
} else {
|
|
269
|
+
console.log(chalk.yellow("No token provided and no saved token found."));
|
|
270
|
+
console.log(chalk.gray("Run with a token: npx spora init --token <YOUR_TOKEN>\n"));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
} catch {
|
|
274
|
+
console.log(chalk.yellow("No saved config found. Please provide a token."));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
console.log(chalk.gray("\nOpening chat interface...\n"));
|
|
279
|
+
try {
|
|
280
|
+
const { startWebChat } = await import("./web-chat-L5MVPVUR.js");
|
|
281
|
+
await startWebChat();
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.log(chalk.yellow(`\u26A0\uFE0F Could not start chat interface: ${error.message}
|
|
284
|
+
`));
|
|
285
|
+
console.log(chalk.gray("You can start it manually with: spora chat\n"));
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (action === "keys") {
|
|
290
|
+
await promptAndSaveKeys();
|
|
291
|
+
console.log(chalk.green("\n\u2713 Keys updated! Run `spora chat` to talk to your Spore.\n"));
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
ensureDirectories();
|
|
154
296
|
}
|
|
155
|
-
ensureDirectories();
|
|
156
297
|
if (token) {
|
|
157
298
|
console.log(chalk.bold("\n\u2501\u2501\u2501 Step 1: Connecting Your Spore \u2501\u2501\u2501\n"));
|
|
158
299
|
console.log(chalk.gray("Fetching your Spore identity from spora.dev...\n"));
|
|
@@ -347,4 +488,4 @@ async function runInit(token) {
|
|
|
347
488
|
export {
|
|
348
489
|
runInit
|
|
349
490
|
};
|
|
350
|
-
//# sourceMappingURL=init-
|
|
491
|
+
//# sourceMappingURL=init-3IIKE3AA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/init.ts","../src/x-client/profile-updater.ts"],"sourcesContent":["import { input, select, confirm, password as passwordPrompt } from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { sporaExists, ensureDirectories } from \"./utils/paths.js\";\nimport { createDefaultConfig, saveConfig } from \"./utils/config.js\";\nimport { saveCredentials, type XCredentials } from \"./utils/crypto.js\";\nimport { loadIdentity } from \"./identity/index.js\";\nimport { updateXProfile } from \"./x-client/profile-updater.js\";\n\n/**\n * Quick re-sync: fetch identity from token without full setup\n */\nasync function syncIdentityFromToken(token: string): Promise<void> {\n console.log(chalk.gray(\"Fetching your Spore identity from spora.dev...\\n\"));\n\n const apiUrl = process.env.SPORA_API_URL || \"https://www.spora.social\";\n const response = await fetch(`${apiUrl}/api/v1/connect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n throw new Error(`Connection failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data.identity) {\n throw new Error(\"No Spore identity found for this token\");\n }\n\n // Merge media fields\n if (data.media) {\n if (data.media.profileImage) data.identity.profileImage = data.media.profileImage;\n if (data.media.bannerImage) data.identity.bannerImage = data.media.bannerImage;\n }\n\n const { saveIdentity } = await import(\"./identity/index.js\");\n saveIdentity(data.identity);\n\n console.log(chalk.green(`✓ Synced Spore: ${data.identity.name} (@${data.identity.handle})\\n`));\n\n // Save README if provided\n if (data.readme) {\n const { writeFileSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n const { join, dirname } = await import(\"node:path\");\n const readmePath = join(dirname(paths.identity), \"IDENTITY.md\");\n writeFileSync(readmePath, data.readme, \"utf-8\");\n console.log(chalk.green(\"✓ Updated identity README\\n\"));\n }\n\n // Save connection token\n const { existsSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n if (existsSync(paths.config)) {\n const { loadConfig, saveConfig } = await import(\"./utils/config.js\");\n const config = loadConfig();\n config.connection = {\n token,\n apiEndpoint: process.env.SPORA_API_URL || \"https://www.spora.social/api/v1\",\n configVersion: config.connection?.configVersion ?? 0,\n };\n saveConfig(config);\n }\n}\n\n/**\n * Prompt for and save just the API keys (Anthropic + X)\n */\nasync function promptAndSaveKeys(): Promise<void> {\n // Anthropic key\n console.log(chalk.bold(\"\\n━━━ Anthropic API Key ━━━\\n\"));\n console.log(chalk.gray(\"Get your API key at: \") + chalk.cyan(\"https://console.anthropic.com/keys\\n\"));\n\n const llmKey = await passwordPrompt({\n message: \"Anthropic API Key:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API key is required\",\n });\n\n const { paths } = await import(\"./utils/paths.js\");\n const { writeFileSync } = await import(\"node:fs\");\n writeFileSync(paths.llmKey, llmKey, \"utf-8\");\n console.log(chalk.green(\"✓ Anthropic API key saved\\n\"));\n\n // X credentials\n const updateX = await confirm({\n message: \"Update X API credentials too?\",\n default: false,\n });\n\n if (updateX) {\n console.log(chalk.bold(\"\\n━━━ X API Credentials ━━━\\n\"));\n\n const apiKey = await passwordPrompt({\n message: \"X API Key (Consumer Key):\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API Key is required\",\n });\n\n const apiSecret = await passwordPrompt({\n message: \"X API Secret (Consumer Secret):\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API Secret is required\",\n });\n\n const accessToken = await passwordPrompt({\n message: \"X Access Token:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Access Token is required\",\n });\n\n const accessTokenSecret = await passwordPrompt({\n message: \"X Access Token Secret:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Access Token Secret is required\",\n });\n\n const bearerToken = await passwordPrompt({\n message: \"X Bearer Token:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Bearer Token is required\",\n });\n\n saveCredentials({\n method: \"api\",\n apiKey,\n apiSecret,\n accessToken,\n accessTokenSecret,\n bearerToken,\n });\n console.log(chalk.green(\"✓ X API credentials saved (encrypted)\\n\"));\n }\n}\n\nexport async function runInit(token?: string): Promise<void> {\n console.log(chalk.bold.cyan(\"\\n╔════════════════════════════════════════╗\"));\n console.log(chalk.bold.cyan(\"║ Welcome to Spora CLI Setup ║\"));\n console.log(chalk.bold.cyan(\"╚════════════════════════════════════════╝\\n\"));\n\n // If a Spore already exists, offer quick re-sync instead of full setup\n if (sporaExists()) {\n const action = await select({\n message: \"A Spore already exists. What would you like to do?\",\n choices: [\n { name: \"Re-sync identity (quick reconnect)\", value: \"resync\" },\n { name: \"Update API keys only\", value: \"keys\" },\n { name: \"Full setup (overwrite everything)\", value: \"full\" },\n { name: \"Cancel\", value: \"cancel\" },\n ],\n });\n\n if (action === \"cancel\") {\n console.log(chalk.yellow(\"Init cancelled.\"));\n return;\n }\n\n ensureDirectories();\n\n // Quick re-sync: just fetch identity from token and open chat\n if (action === \"resync\") {\n if (token) {\n await syncIdentityFromToken(token);\n } else {\n // Check if we have a saved token\n const { loadConfig } = await import(\"./utils/config.js\");\n try {\n const config = loadConfig();\n if (config.connection?.token) {\n console.log(chalk.gray(\"Using saved connection token...\\n\"));\n await syncIdentityFromToken(config.connection.token);\n } else {\n console.log(chalk.yellow(\"No token provided and no saved token found.\"));\n console.log(chalk.gray(\"Run with a token: npx spora init --token <YOUR_TOKEN>\\n\"));\n return;\n }\n } catch {\n console.log(chalk.yellow(\"No saved config found. Please provide a token.\"));\n return;\n }\n }\n\n // Open chat after re-sync\n console.log(chalk.gray(\"\\nOpening chat interface...\\n\"));\n try {\n const { startWebChat } = await import(\"./web-chat/index.js\");\n await startWebChat();\n } catch (error) {\n console.log(chalk.yellow(`⚠️ Could not start chat interface: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can start it manually with: spora chat\\n\"));\n }\n return;\n }\n\n // Update keys only: just the API key prompts, then done\n if (action === \"keys\") {\n await promptAndSaveKeys();\n console.log(chalk.green(\"\\n✓ Keys updated! Run `spora chat` to talk to your Spore.\\n\"));\n return;\n }\n\n // \"full\" falls through to the full setup below\n } else {\n ensureDirectories();\n }\n\n // ===== Token-based Auto-Connect =====\n if (token) {\n console.log(chalk.bold(\"\\n━━━ Step 1: Connecting Your Spore ━━━\\n\"));\n console.log(chalk.gray(\"Fetching your Spore identity from spora.dev...\\n\"));\n\n try {\n const apiUrl = process.env.SPORA_API_URL || \"https://www.spora.social\";\n const response = await fetch(`${apiUrl}/api/v1/connect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n throw new Error(`Connection failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data.identity) {\n throw new Error(\"No Spore identity found for this token\");\n }\n\n // Merge media fields (profileImage, bannerImage) into identity\n if (data.media) {\n if (data.media.profileImage) {\n data.identity.profileImage = data.media.profileImage;\n }\n if (data.media.bannerImage) {\n data.identity.bannerImage = data.media.bannerImage;\n }\n }\n\n // Save the identity\n const { saveIdentity } = await import(\"./identity/index.js\");\n saveIdentity(data.identity);\n\n console.log(chalk.green(`✓ Connected to Spore: ${data.identity.name} (@${data.identity.handle})\\n`));\n\n // Save comprehensive README if provided\n const { writeFileSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n const { existsSync } = await import(\"node:fs\");\n const { join, dirname } = await import(\"node:path\");\n\n if (data.readme) {\n const readmePath = join(dirname(paths.identity), \"IDENTITY.md\");\n writeFileSync(readmePath, data.readme, \"utf-8\");\n console.log(chalk.green(\"✓ Saved comprehensive identity README\\n\"));\n }\n\n // Save connection token to config\n\n if (existsSync(paths.config)) {\n const { loadConfig, saveConfig } = await import(\"./utils/config.js\");\n const config = loadConfig();\n config.connection = {\n token,\n apiEndpoint: process.env.SPORA_API_URL || \"https://www.spora.social/api/v1\",\n configVersion: 0,\n };\n saveConfig(config);\n }\n } catch (error) {\n console.log(chalk.red(`\\n✗ Connection failed: ${(error as Error).message}\\n`));\n console.log(chalk.yellow(\"Please check your token and try again.\\n\"));\n process.exit(1);\n }\n }\n\n // ===== Anthropic API Key Setup =====\n console.log(chalk.bold(\"\\n━━━ Step 1: Add Your Anthropic API Key ━━━\\n\"));\n console.log(chalk.gray(\"Your Spore uses Claude to make autonomous decisions.\"));\n console.log(chalk.gray(\"Get your API key at: \") + chalk.cyan(\"https://console.anthropic.com/keys\\n\"));\n\n const llmKey = await passwordPrompt({\n message: \"Anthropic API Key:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API key is required\",\n });\n\n // Save LLM key\n const { paths } = await import(\"./utils/paths.js\");\n const { writeFileSync } = await import(\"node:fs\");\n writeFileSync(paths.llmKey, llmKey, \"utf-8\");\n console.log(chalk.green(\"✓ Anthropic API key saved\\n\"));\n\n // ===== X API Credentials Setup =====\n console.log(chalk.bold(\"\\n━━━ Step 2: Connect Your X Account ━━━\\n\"));\n console.log(chalk.gray(\"Your Spore needs OAuth 1.0a credentials for full X API access.\"));\n console.log(chalk.gray(\"This gives your agent the power to read timelines, post tweets, reply, like, and follow.\\n\"));\n console.log(chalk.cyan(\"📋 How to get these credentials:\"));\n console.log(chalk.gray(\" 1. Go to: \") + chalk.cyan(\"https://developer.x.com/en/portal/dashboard\"));\n console.log(chalk.gray(\" 2. Create or select your app\"));\n console.log(chalk.gray(\" 3. Go to \\\"Keys and tokens\\\" tab\"));\n console.log(chalk.gray(\" 4. Copy all 4 credentials below\\n\"));\n console.log(chalk.yellow(\"⚠️ Note: You need X Pro account ($200/mo) for posting access.\\n\"));\n\n const apiKey = await passwordPrompt({\n message: \"X API Key (Consumer Key):\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API Key is required\",\n });\n\n const apiSecret = await passwordPrompt({\n message: \"X API Secret (Consumer Secret):\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API Secret is required\",\n });\n\n const accessToken = await passwordPrompt({\n message: \"X Access Token:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Access Token is required\",\n });\n\n const accessTokenSecret = await passwordPrompt({\n message: \"X Access Token Secret:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Access Token Secret is required\",\n });\n\n const bearerToken = await passwordPrompt({\n message: \"X Bearer Token:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Bearer Token is required\",\n });\n\n const xCredentials: XCredentials = {\n method: \"api\",\n apiKey,\n apiSecret,\n accessToken,\n accessTokenSecret,\n bearerToken,\n };\n\n saveCredentials(xCredentials);\n console.log(chalk.green(\"✓ X API credentials saved (encrypted)\\n\"));\n\n // ===== Update X Profile with Spore Identity =====\n console.log(chalk.bold(\"\\n━━━ Step 3: Updating Your X Profile ━━━\\n\"));\n console.log(chalk.gray(\"Setting up profile picture, banner, and bio to match your Spore...\\n\"));\n\n try {\n const identity = loadIdentity();\n const result = await updateXProfile(identity);\n\n if (result.success) {\n console.log(chalk.green(\"✓ Profile updated successfully!\\n\"));\n\n if (result.updated.length > 0) {\n console.log(chalk.cyan(\"Updated:\"));\n for (const field of result.updated) {\n console.log(chalk.gray(` • ${field}`));\n }\n console.log();\n }\n }\n\n if (result.errors.length > 0) {\n console.log(chalk.yellow(\"\\n⚠️ Some updates failed:\"));\n for (const error of result.errors) {\n console.log(chalk.gray(` • ${error}`));\n }\n console.log();\n\n console.log(chalk.gray(\"You can manually update your X profile with:\"));\n console.log(chalk.cyan(` Name: ${identity.name}`));\n console.log(chalk.cyan(` Bio: ${identity.bio}`));\n if (identity.profileImage) {\n console.log(chalk.cyan(` Profile pic: ${identity.profileImage}`));\n }\n if (identity.bannerImage) {\n console.log(chalk.cyan(` Banner: ${identity.bannerImage}`));\n }\n console.log();\n }\n } catch (error) {\n console.log(chalk.yellow(`⚠️ Could not update profile: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can manually update your X profile later.\\n\"));\n }\n\n const config = createDefaultConfig({\n xMethod: \"api\",\n xApiTier: \"basic\", // Always assume full access (Pro tier)\n });\n\n // Add LLM config\n config.llm = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-20250514\",\n };\n\n // Enable runtime by default\n config.runtime = {\n heartbeatIntervalMs: 300_000, // 5 minutes\n actionsPerHeartbeat: 3,\n enabled: true,\n };\n\n saveConfig(config);\n\n // ===== Done =====\n console.log(chalk.green(\"\\n╔═══════════════════════════════════════╗\"));\n console.log(chalk.green.bold(\"║ Setup Complete! 🎉 ║\"));\n console.log(chalk.green(\"╚═══════════════════════════════════════╝\\n\"));\n\n console.log(chalk.bold.cyan(\"━━━ Your Spore is Ready! ━━━\\n\"));\n console.log(chalk.gray(\"Opening chat interface...\\n\"));\n\n // Auto-open web chat interface\n try {\n const { startWebChat } = await import(\"./web-chat/index.js\");\n await startWebChat();\n } catch (error) {\n console.log(chalk.yellow(`⚠️ Could not start chat interface: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can start it manually with: spora chat\\n\"));\n }\n\n console.log(chalk.bold(\"Quick Start:\\n\"));\n console.log(chalk.cyan(\" spora chat\"));\n console.log(chalk.gray(\" → Talk to your Spore, tell it what to post, how to behave\\n\"));\n\n console.log(chalk.bold(\"Or start the autonomous agent:\\n\"));\n console.log(chalk.cyan(\" spora start\"));\n console.log(chalk.gray(\" → Your Spore will post and engage autonomously\\n\"));\n\n console.log(chalk.bold(\"Other commands:\\n\"));\n console.log(chalk.cyan(\" spora create \") + chalk.gray(\"# Create a personality\"));\n console.log(chalk.cyan(\" spora post <text> \") + chalk.gray(\"# Make your Spore post\"));\n console.log(chalk.cyan(\" spora agent-status \") + chalk.gray(\"# Check if agent is running\"));\n console.log(chalk.cyan(\" spora stop \") + chalk.gray(\"# Stop the agent\"));\n console.log(chalk.cyan(\" spora --help \") + chalk.gray(\"# See all commands\\n\"));\n}\n","/**\n * X Profile Updater\n * Updates X profile to match Spore identity (name, bio, profile pic, banner)\n */\n\nimport { TwitterApi } from \"twitter-api-v2\";\nimport sharp from \"sharp\";\nimport type { Identity } from \"../identity/schema.js\";\nimport { loadCredentials } from \"../utils/crypto.js\";\n\ninterface ProfileUpdateResult {\n success: boolean;\n updated: string[];\n errors: string[];\n}\n\n/**\n * Update X profile to match Spore identity\n * Requires OAuth 1.0a credentials\n */\nexport async function updateXProfile(identity: Identity): Promise<ProfileUpdateResult> {\n const result: ProfileUpdateResult = {\n success: false,\n updated: [],\n errors: [],\n };\n\n try {\n const creds = loadCredentials();\n if (creds.method !== \"api\") {\n result.errors.push(\"API credentials required\");\n return result;\n }\n\n // Create Twitter API client with OAuth 1.0a credentials\n const client = new TwitterApi({\n appKey: creds.apiKey!,\n appSecret: creds.apiSecret!,\n accessToken: creds.accessToken!,\n accessSecret: creds.accessTokenSecret!,\n });\n\n // Update profile name and bio (username separately to avoid breaking on failure)\n try {\n console.log(`Updating name to: ${identity.name}`);\n console.log(`Updating bio to: ${identity.bio.substring(0, 60)}...`);\n await client.v1.updateAccountProfile({\n name: identity.name,\n description: identity.bio,\n });\n result.updated.push(\"name\", \"bio\");\n console.log(\"Name and bio updated successfully\");\n } catch (error) {\n console.error(\"Name/bio update error:\", error);\n result.errors.push(`Failed to update name/bio: ${(error as Error).message}`);\n }\n\n // Try to update username separately (optional, may fail if taken or restricted)\n if (identity.handle) {\n try {\n console.log(`Attempting to update username to: @${identity.handle}`);\n await client.v1.updateAccountProfile({\n screen_name: identity.handle,\n });\n result.updated.push(\"username\");\n console.log(\"Username updated successfully\");\n } catch (error) {\n // Don't fail the whole update if username change fails\n console.warn(`Could not update username: ${(error as Error).message}`);\n }\n }\n\n // Update profile image if available\n if (identity.profileImage) {\n try {\n console.log(`Downloading profile image from: ${identity.profileImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.profileImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Check image dimensions - Twitter requires min 400x400\n const metadata = await sharp(imageBuffer).metadata();\n console.log(`Image dimensions: ${metadata.width}x${metadata.height}`);\n\n if (!metadata.width || !metadata.height || metadata.width < 400 || metadata.height < 400) {\n throw new Error(`Image too small (${metadata.width}x${metadata.height}). Twitter requires minimum 400x400 pixels.`);\n }\n\n // Compress if needed (Twitter profile image limit: 2MB)\n const MAX_PROFILE_SIZE = 2 * 1024 * 1024; // 2MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_PROFILE_SIZE, \"Profile\");\n\n console.log(`Uploading profile image to X...`);\n await client.v1.updateAccountProfileImage(imageBuffer);\n result.updated.push(\"profile_image\");\n console.log(\"Profile image updated successfully\");\n } catch (error) {\n console.error(\"Profile image error:\", error);\n result.errors.push(`Failed to update profile image: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No profile image URL in identity\");\n }\n\n // Update banner image if available\n if (identity.bannerImage) {\n try {\n console.log(`Downloading banner image from: ${identity.bannerImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.bannerImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Compress if needed (Twitter banner limit: 5MB)\n const MAX_BANNER_SIZE = 5 * 1024 * 1024; // 5MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_BANNER_SIZE, \"Banner\");\n\n console.log(`Uploading banner image to X...`);\n await client.v1.updateAccountProfileBanner(imageBuffer);\n result.updated.push(\"banner_image\");\n console.log(\"Banner image updated successfully\");\n } catch (error) {\n console.error(\"Banner image error:\", error);\n result.errors.push(`Failed to update banner: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No banner image URL in identity\");\n }\n\n result.success = result.updated.length > 0;\n return result;\n } catch (error) {\n result.errors.push((error as Error).message);\n return result;\n }\n}\n\n/**\n * Download image from URL and return as Buffer\n */\nasync function downloadImage(url: string): Promise<Buffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download image: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n}\n\n/**\n * Compress image if it exceeds size limit by resizing\n * @param buffer Original image buffer\n * @param maxSizeBytes Maximum allowed size in bytes\n * @param type \"profile\" or \"banner\" for logging\n */\nasync function compressImageIfNeeded(\n buffer: Buffer,\n maxSizeBytes: number,\n type: string\n): Promise<Buffer> {\n if (buffer.length <= maxSizeBytes) {\n return buffer;\n }\n\n console.log(\n `${type} image is ${(buffer.length / 1024 / 1024).toFixed(2)}MB, resizing to fit ${(maxSizeBytes / 1024 / 1024).toFixed(0)}MB limit...`\n );\n\n // Calculate scale factor to fit within size limit\n const scaleFactor = Math.sqrt(maxSizeBytes / buffer.length) * 0.85; // 85% of target for safety\n\n // Get current dimensions and calculate new size\n const metadata = await sharp(buffer).metadata();\n const newWidth = Math.floor((metadata.width || 1000) * scaleFactor);\n\n // Resize and convert to JPEG with good quality\n const compressed = await sharp(buffer)\n .resize(newWidth, null, { fit: \"inside\", withoutEnlargement: true })\n .jpeg({ quality: 90, progressive: true })\n .toBuffer();\n\n console.log(\n `Resized ${type} image from ${(buffer.length / 1024 / 1024).toFixed(2)}MB to ${(compressed.length / 1024 / 1024).toFixed(2)}MB`\n );\n\n return compressed;\n}\n"],"mappings":"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","names":["paths","saveConfig","config","writeFileSync"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init.ts","../src/x-client/profile-updater.ts"],"sourcesContent":["import { input, select, confirm, password as passwordPrompt } from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { sporaExists, ensureDirectories } from \"./utils/paths.js\";\nimport { createDefaultConfig, saveConfig } from \"./utils/config.js\";\nimport { saveCredentials, type XCredentials } from \"./utils/crypto.js\";\nimport { loadIdentity } from \"./identity/index.js\";\nimport { updateXProfile } from \"./x-client/profile-updater.js\";\n\nexport async function runInit(token?: string): Promise<void> {\n console.log(chalk.bold.cyan(\"\\n╔════════════════════════════════════════╗\"));\n console.log(chalk.bold.cyan(\"║ Welcome to Spora CLI Setup ║\"));\n console.log(chalk.bold.cyan(\"╚════════════════════════════════════════╝\\n\"));\n\n if (sporaExists() && !token) {\n const overwrite = await confirm({\n message: \"A Spore already exists. Overwrite credentials?\",\n default: false,\n });\n if (!overwrite) {\n console.log(chalk.yellow(\"Init cancelled.\"));\n return;\n }\n }\n\n ensureDirectories();\n\n // ===== Token-based Auto-Connect =====\n if (token) {\n console.log(chalk.bold(\"\\n━━━ Step 1: Connecting Your Spore ━━━\\n\"));\n console.log(chalk.gray(\"Fetching your Spore identity from spora.dev...\\n\"));\n\n try {\n const apiUrl = process.env.SPORA_API_URL || \"https://www.spora.social\";\n const response = await fetch(`${apiUrl}/api/v1/connect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n throw new Error(`Connection failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data.identity) {\n throw new Error(\"No Spore identity found for this token\");\n }\n\n // Merge media fields (profileImage, bannerImage) into identity\n if (data.media) {\n if (data.media.profileImage) {\n data.identity.profileImage = data.media.profileImage;\n }\n if (data.media.bannerImage) {\n data.identity.bannerImage = data.media.bannerImage;\n }\n }\n\n // Save the identity\n const { saveIdentity } = await import(\"./identity/index.js\");\n saveIdentity(data.identity);\n\n console.log(chalk.green(`✓ Connected to Spore: ${data.identity.name} (@${data.identity.handle})\\n`));\n\n // Save comprehensive README if provided\n const { writeFileSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n const { existsSync } = await import(\"node:fs\");\n const { join, dirname } = await import(\"node:path\");\n\n if (data.readme) {\n const readmePath = join(dirname(paths.identity), \"IDENTITY.md\");\n writeFileSync(readmePath, data.readme, \"utf-8\");\n console.log(chalk.green(\"✓ Saved comprehensive identity README\\n\"));\n }\n\n // Save connection token to config\n\n if (existsSync(paths.config)) {\n const { loadConfig, saveConfig } = await import(\"./utils/config.js\");\n const config = loadConfig();\n config.connection = {\n token,\n apiEndpoint: process.env.SPORA_API_URL || \"https://www.spora.social/api/v1\",\n configVersion: 0,\n };\n saveConfig(config);\n }\n } catch (error) {\n console.log(chalk.red(`\\n✗ Connection failed: ${(error as Error).message}\\n`));\n console.log(chalk.yellow(\"Please check your token and try again.\\n\"));\n process.exit(1);\n }\n }\n\n // ===== Anthropic API Key Setup =====\n console.log(chalk.bold(\"\\n━━━ Step 1: Add Your Anthropic API Key ━━━\\n\"));\n console.log(chalk.gray(\"Your Spore uses Claude to make autonomous decisions.\"));\n console.log(chalk.gray(\"Get your API key at: \") + chalk.cyan(\"https://console.anthropic.com/keys\\n\"));\n\n const llmKey = await passwordPrompt({\n message: \"Anthropic API Key:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API key is required\",\n });\n\n // Save LLM key\n const { paths } = await import(\"./utils/paths.js\");\n const { writeFileSync } = await import(\"node:fs\");\n writeFileSync(paths.llmKey, llmKey, \"utf-8\");\n console.log(chalk.green(\"✓ Anthropic API key saved\\n\"));\n\n // ===== X API Credentials Setup =====\n console.log(chalk.bold(\"\\n━━━ Step 2: Connect Your X Account ━━━\\n\"));\n console.log(chalk.gray(\"Your Spore needs OAuth 1.0a credentials for full X API access.\"));\n console.log(chalk.gray(\"This gives your agent the power to read timelines, post tweets, reply, like, and follow.\\n\"));\n console.log(chalk.cyan(\"📋 How to get these credentials:\"));\n console.log(chalk.gray(\" 1. Go to: \") + chalk.cyan(\"https://developer.x.com/en/portal/dashboard\"));\n console.log(chalk.gray(\" 2. Create or select your app\"));\n console.log(chalk.gray(\" 3. Go to \\\"Keys and tokens\\\" tab\"));\n console.log(chalk.gray(\" 4. Copy all 4 credentials below\\n\"));\n console.log(chalk.yellow(\"⚠️ Note: You need X Pro account ($200/mo) for posting access.\\n\"));\n\n const apiKey = await passwordPrompt({\n message: \"X API Key (Consumer Key):\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API Key is required\",\n });\n\n const apiSecret = await passwordPrompt({\n message: \"X API Secret (Consumer Secret):\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"API Secret is required\",\n });\n\n const accessToken = await passwordPrompt({\n message: \"X Access Token:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Access Token is required\",\n });\n\n const accessTokenSecret = await passwordPrompt({\n message: \"X Access Token Secret:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Access Token Secret is required\",\n });\n\n const bearerToken = await passwordPrompt({\n message: \"X Bearer Token:\",\n mask: \"*\",\n validate: (val) => val.length > 0 ? true : \"Bearer Token is required\",\n });\n\n const xCredentials: XCredentials = {\n method: \"api\",\n apiKey,\n apiSecret,\n accessToken,\n accessTokenSecret,\n bearerToken,\n };\n\n saveCredentials(xCredentials);\n console.log(chalk.green(\"✓ X API credentials saved (encrypted)\\n\"));\n\n // ===== Update X Profile with Spore Identity =====\n console.log(chalk.bold(\"\\n━━━ Step 3: Updating Your X Profile ━━━\\n\"));\n console.log(chalk.gray(\"Setting up profile picture, banner, and bio to match your Spore...\\n\"));\n\n try {\n const identity = loadIdentity();\n const result = await updateXProfile(identity);\n\n if (result.success) {\n console.log(chalk.green(\"✓ Profile updated successfully!\\n\"));\n\n if (result.updated.length > 0) {\n console.log(chalk.cyan(\"Updated:\"));\n for (const field of result.updated) {\n console.log(chalk.gray(` • ${field}`));\n }\n console.log();\n }\n }\n\n if (result.errors.length > 0) {\n console.log(chalk.yellow(\"\\n⚠️ Some updates failed:\"));\n for (const error of result.errors) {\n console.log(chalk.gray(` • ${error}`));\n }\n console.log();\n\n console.log(chalk.gray(\"You can manually update your X profile with:\"));\n console.log(chalk.cyan(` Name: ${identity.name}`));\n console.log(chalk.cyan(` Bio: ${identity.bio}`));\n if (identity.profileImage) {\n console.log(chalk.cyan(` Profile pic: ${identity.profileImage}`));\n }\n if (identity.bannerImage) {\n console.log(chalk.cyan(` Banner: ${identity.bannerImage}`));\n }\n console.log();\n }\n } catch (error) {\n console.log(chalk.yellow(`⚠️ Could not update profile: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can manually update your X profile later.\\n\"));\n }\n\n const config = createDefaultConfig({\n xMethod: \"api\",\n xApiTier: \"basic\", // Always assume full access (Pro tier)\n });\n\n // Add LLM config\n config.llm = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-20250514\",\n };\n\n // Enable runtime by default\n config.runtime = {\n heartbeatIntervalMs: 300_000, // 5 minutes\n actionsPerHeartbeat: 3,\n enabled: true,\n };\n\n saveConfig(config);\n\n // ===== Done =====\n console.log(chalk.green(\"\\n╔═══════════════════════════════════════╗\"));\n console.log(chalk.green.bold(\"║ Setup Complete! 🎉 ║\"));\n console.log(chalk.green(\"╚═══════════════════════════════════════╝\\n\"));\n\n console.log(chalk.bold.cyan(\"━━━ Your Spore is Ready! ━━━\\n\"));\n console.log(chalk.gray(\"Opening chat interface...\\n\"));\n\n // Auto-open web chat interface\n try {\n const { startWebChat } = await import(\"./web-chat/index.js\");\n await startWebChat();\n } catch (error) {\n console.log(chalk.yellow(`⚠️ Could not start chat interface: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can start it manually with: spora chat\\n\"));\n }\n\n console.log(chalk.bold(\"Quick Start:\\n\"));\n console.log(chalk.cyan(\" spora chat\"));\n console.log(chalk.gray(\" → Talk to your Spore, tell it what to post, how to behave\\n\"));\n\n console.log(chalk.bold(\"Or start the autonomous agent:\\n\"));\n console.log(chalk.cyan(\" spora start\"));\n console.log(chalk.gray(\" → Your Spore will post and engage autonomously\\n\"));\n\n console.log(chalk.bold(\"Other commands:\\n\"));\n console.log(chalk.cyan(\" spora create \") + chalk.gray(\"# Create a personality\"));\n console.log(chalk.cyan(\" spora post <text> \") + chalk.gray(\"# Make your Spore post\"));\n console.log(chalk.cyan(\" spora agent-status \") + chalk.gray(\"# Check if agent is running\"));\n console.log(chalk.cyan(\" spora stop \") + chalk.gray(\"# Stop the agent\"));\n console.log(chalk.cyan(\" spora --help \") + chalk.gray(\"# See all commands\\n\"));\n}\n","/**\n * X Profile Updater\n * Updates X profile to match Spore identity (name, bio, profile pic, banner)\n */\n\nimport { TwitterApi } from \"twitter-api-v2\";\nimport sharp from \"sharp\";\nimport type { Identity } from \"../identity/schema.js\";\nimport { loadCredentials } from \"../utils/crypto.js\";\n\ninterface ProfileUpdateResult {\n success: boolean;\n updated: string[];\n errors: string[];\n}\n\n/**\n * Update X profile to match Spore identity\n * Requires OAuth 1.0a credentials\n */\nexport async function updateXProfile(identity: Identity): Promise<ProfileUpdateResult> {\n const result: ProfileUpdateResult = {\n success: false,\n updated: [],\n errors: [],\n };\n\n try {\n const creds = loadCredentials();\n if (creds.method !== \"api\") {\n result.errors.push(\"API credentials required\");\n return result;\n }\n\n // Create Twitter API client with OAuth 1.0a credentials\n const client = new TwitterApi({\n appKey: creds.apiKey!,\n appSecret: creds.apiSecret!,\n accessToken: creds.accessToken!,\n accessSecret: creds.accessTokenSecret!,\n });\n\n // Update profile name and bio (username separately to avoid breaking on failure)\n try {\n console.log(`Updating name to: ${identity.name}`);\n console.log(`Updating bio to: ${identity.bio.substring(0, 60)}...`);\n await client.v1.updateAccountProfile({\n name: identity.name,\n description: identity.bio,\n });\n result.updated.push(\"name\", \"bio\");\n console.log(\"Name and bio updated successfully\");\n } catch (error) {\n console.error(\"Name/bio update error:\", error);\n result.errors.push(`Failed to update name/bio: ${(error as Error).message}`);\n }\n\n // Try to update username separately (optional, may fail if taken or restricted)\n if (identity.handle) {\n try {\n console.log(`Attempting to update username to: @${identity.handle}`);\n await client.v1.updateAccountProfile({\n screen_name: identity.handle,\n });\n result.updated.push(\"username\");\n console.log(\"Username updated successfully\");\n } catch (error) {\n // Don't fail the whole update if username change fails\n console.warn(`Could not update username: ${(error as Error).message}`);\n }\n }\n\n // Update profile image if available\n if (identity.profileImage) {\n try {\n console.log(`Downloading profile image from: ${identity.profileImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.profileImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Check image dimensions - Twitter requires min 400x400\n const metadata = await sharp(imageBuffer).metadata();\n console.log(`Image dimensions: ${metadata.width}x${metadata.height}`);\n\n if (!metadata.width || !metadata.height || metadata.width < 400 || metadata.height < 400) {\n throw new Error(`Image too small (${metadata.width}x${metadata.height}). Twitter requires minimum 400x400 pixels.`);\n }\n\n // Compress if needed (Twitter profile image limit: 2MB)\n const MAX_PROFILE_SIZE = 2 * 1024 * 1024; // 2MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_PROFILE_SIZE, \"Profile\");\n\n console.log(`Uploading profile image to X...`);\n await client.v1.updateAccountProfileImage(imageBuffer);\n result.updated.push(\"profile_image\");\n console.log(\"Profile image updated successfully\");\n } catch (error) {\n console.error(\"Profile image error:\", error);\n result.errors.push(`Failed to update profile image: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No profile image URL in identity\");\n }\n\n // Update banner image if available\n if (identity.bannerImage) {\n try {\n console.log(`Downloading banner image from: ${identity.bannerImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.bannerImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Compress if needed (Twitter banner limit: 5MB)\n const MAX_BANNER_SIZE = 5 * 1024 * 1024; // 5MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_BANNER_SIZE, \"Banner\");\n\n console.log(`Uploading banner image to X...`);\n await client.v1.updateAccountProfileBanner(imageBuffer);\n result.updated.push(\"banner_image\");\n console.log(\"Banner image updated successfully\");\n } catch (error) {\n console.error(\"Banner image error:\", error);\n result.errors.push(`Failed to update banner: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No banner image URL in identity\");\n }\n\n result.success = result.updated.length > 0;\n return result;\n } catch (error) {\n result.errors.push((error as Error).message);\n return result;\n }\n}\n\n/**\n * Download image from URL and return as Buffer\n */\nasync function downloadImage(url: string): Promise<Buffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download image: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n}\n\n/**\n * Compress image if it exceeds size limit by resizing\n * @param buffer Original image buffer\n * @param maxSizeBytes Maximum allowed size in bytes\n * @param type \"profile\" or \"banner\" for logging\n */\nasync function compressImageIfNeeded(\n buffer: Buffer,\n maxSizeBytes: number,\n type: string\n): Promise<Buffer> {\n if (buffer.length <= maxSizeBytes) {\n return buffer;\n }\n\n console.log(\n `${type} image is ${(buffer.length / 1024 / 1024).toFixed(2)}MB, resizing to fit ${(maxSizeBytes / 1024 / 1024).toFixed(0)}MB limit...`\n );\n\n // Calculate scale factor to fit within size limit\n const scaleFactor = Math.sqrt(maxSizeBytes / buffer.length) * 0.85; // 85% of target for safety\n\n // Get current dimensions and calculate new size\n const metadata = await sharp(buffer).metadata();\n const newWidth = Math.floor((metadata.width || 1000) * scaleFactor);\n\n // Resize and convert to JPEG with good quality\n const compressed = await sharp(buffer)\n .resize(newWidth, null, { fit: \"inside\", withoutEnlargement: true })\n .jpeg({ quality: 90, progressive: true })\n .toBuffer();\n\n console.log(\n `Resized ${type} image from ${(buffer.length / 1024 / 1024).toFixed(2)}MB to ${(compressed.length / 1024 / 1024).toFixed(2)}MB`\n );\n\n return compressed;\n}\n"],"mappings":"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","names":["writeFileSync","paths","saveConfig","config"]}
|