towns-bot 0.0.266

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/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 River Association
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # towns-bot
2
+
3
+ CLI for creating and managing Towns Protocol bot projects.
4
+
5
+ ## Usage
6
+
7
+ ### Create a new bot project
8
+
9
+ ```bash
10
+ npx towns-bot init my-bot
11
+ # or
12
+ bunx towns-bot init my-bot
13
+ # or
14
+ yarn dlx towns-bot init my-bot
15
+ # or
16
+ pnpm dlx towns-bot init my-bot
17
+ ```
18
+
19
+ This will create a new bot project with the default quickstart template.
20
+
21
+ ### Available templates
22
+
23
+ Any template from the [examples](https://github.com/towns-protocol/towns/tree/main/packages/examples) directory can be used.
24
+
25
+ Here's a few examples:
26
+
27
+ - `quickstart` (default) - Simple starter bot with basic commands
28
+ - `thread-ai` - AI-powered conversational bot using OpenAI
29
+ - `poll` - Interactive poll bot for creating votes
30
+
31
+ To use a specific template:
32
+
33
+ ```bash
34
+ npx towns-bot init my-ai-bot --template thread-ai
35
+ ```
36
+
37
+ ### Update dependencies
38
+
39
+ Update all `@towns-protocol/*` dependencies to their latest versions:
40
+
41
+ ```bash
42
+ npx towns-bot update
43
+ ```
44
+
45
+ This command should be run from within a Towns Protocol bot project directory.
46
+
47
+ ## Commands
48
+
49
+ ### `towns-bot init [project-name]`
50
+
51
+ Create a new bot project.
52
+
53
+ Options:
54
+
55
+ - `-t, --template <name>` - Template to use (quickstart, thread-ai, poll)
56
+
57
+ ### `towns-bot update`
58
+
59
+ Update `@towns-protocol/*` dependencies to latest versions.
60
+
61
+ ### `towns-bot help`
package/dist/index.js ADDED
@@ -0,0 +1,493 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/index.ts
27
+ var src_exports = {};
28
+ module.exports = __toCommonJS(src_exports);
29
+ var import_minimist = __toESM(require("minimist"));
30
+ var import_picocolors4 = require("picocolors");
31
+
32
+ // src/modules/init.ts
33
+ var fs2 = __toESM(require("fs"));
34
+ var path2 = __toESM(require("path"));
35
+ var import_prompts = __toESM(require("prompts"));
36
+ var import_picocolors2 = require("picocolors");
37
+ var jsonc = __toESM(require("jsonc-parser"));
38
+
39
+ // src/modules/utils.ts
40
+ var fs = __toESM(require("fs"));
41
+ var path = __toESM(require("path"));
42
+ var import_cross_spawn = __toESM(require("cross-spawn"));
43
+ var import_picocolors = __toESM(require("picocolors"));
44
+ var getPackageManager = () => {
45
+ if (process.env.npm_config_user_agent) {
46
+ const agent = process.env.npm_config_user_agent;
47
+ if (agent.startsWith("yarn")) return "yarn";
48
+ if (agent.startsWith("npm")) return "npm";
49
+ if (agent.startsWith("pnpm")) return "pnpm";
50
+ if (agent.startsWith("bun")) return "bun";
51
+ }
52
+ return "npm";
53
+ };
54
+ function getInstallCommand(packageManager) {
55
+ switch (packageManager) {
56
+ case "bun":
57
+ return "bun install";
58
+ case "yarn":
59
+ return "yarn";
60
+ case "pnpm":
61
+ return "pnpm install";
62
+ default:
63
+ return "npm install";
64
+ }
65
+ }
66
+ function getRunCommand(packageManager, script) {
67
+ switch (packageManager) {
68
+ case "bun":
69
+ return `bun run ${script}`;
70
+ case "yarn":
71
+ return `yarn ${script}`;
72
+ case "pnpm":
73
+ return `pnpm ${script}`;
74
+ default:
75
+ return `npm run ${script}`;
76
+ }
77
+ }
78
+ function runCommand(command, args, cwd) {
79
+ return new Promise((resolve2, reject) => {
80
+ const child = (0, import_cross_spawn.default)(command, args, {
81
+ stdio: "inherit",
82
+ cwd,
83
+ shell: process.platform === "win32"
84
+ });
85
+ child.on("close", (code) => {
86
+ if (code !== 0) {
87
+ reject(new Error(`Command failed with exit code ${code}`));
88
+ } else {
89
+ resolve2();
90
+ }
91
+ });
92
+ child.on("error", reject);
93
+ });
94
+ }
95
+ async function getLatestTownsProtocolVersion() {
96
+ return new Promise((resolve2, reject) => {
97
+ const child = (0, import_cross_spawn.default)("npm", ["view", "@towns-protocol/bot", "version"], {
98
+ stdio: ["ignore", "pipe", "ignore"]
99
+ });
100
+ let output = "";
101
+ child.stdout?.on("data", (data) => {
102
+ output += data.toString();
103
+ });
104
+ child.on("close", (code) => {
105
+ if (code !== 0) {
106
+ reject(new Error("Failed to fetch latest @towns-protocol/bot version"));
107
+ } else {
108
+ resolve2(output.trim());
109
+ }
110
+ });
111
+ child.on("error", reject);
112
+ });
113
+ }
114
+ function getLatestSdkTag() {
115
+ const tagsResult = import_cross_spawn.default.sync(
116
+ "git",
117
+ ["ls-remote", "--tags", "https://github.com/towns-protocol/towns.git", "sdk-*"],
118
+ { encoding: "utf8" }
119
+ );
120
+ if (tagsResult.status !== 0 || !tagsResult.stdout) return null;
121
+ const tags = tagsResult.stdout.split("\n").filter(Boolean).map((line) => {
122
+ const [_hash, ref] = line.split(" ");
123
+ const tag = ref.replace("refs/tags/", "").replace(/\^{}$/, "");
124
+ const match = tag.match(/^sdk-[0-9a-f]+-(\d+)\.(\d+)\.(\d+)$/);
125
+ if (!match) return null;
126
+ return {
127
+ tag,
128
+ version: [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]
129
+ };
130
+ }).filter(
131
+ (item) => item !== null && Array.isArray(item.version) && item.version.length === 3
132
+ ).sort((a, b) => {
133
+ for (let i = 0; i < 3; i++) {
134
+ if (a.version[i] !== b.version[i]) {
135
+ return b.version[i] - a.version[i];
136
+ }
137
+ }
138
+ return 0;
139
+ });
140
+ return tags.length > 0 ? tags[0].tag : null;
141
+ }
142
+ async function cloneTemplate(packagePath, targetDir) {
143
+ console.log(import_picocolors.default.blue("Cloning template from GitHub..."));
144
+ const tempDir = `${targetDir}-temp`;
145
+ const fullTemplatePath = `packages/examples/${packagePath}`;
146
+ const latestSdkTag = getLatestSdkTag();
147
+ if (!latestSdkTag) {
148
+ console.error(import_picocolors.default.red("Failed to get latest SDK tag."));
149
+ return false;
150
+ }
151
+ const cloneResult = import_cross_spawn.default.sync(
152
+ "git",
153
+ [
154
+ "clone",
155
+ "--no-checkout",
156
+ "--depth",
157
+ "1",
158
+ "--sparse",
159
+ "--branch",
160
+ latestSdkTag,
161
+ "https://github.com/towns-protocol/towns.git",
162
+ tempDir
163
+ ],
164
+ { stdio: "pipe" }
165
+ );
166
+ if (cloneResult.status !== 0) return false;
167
+ const sparseResult = import_cross_spawn.default.sync("git", ["sparse-checkout", "set", fullTemplatePath], {
168
+ stdio: "pipe",
169
+ cwd: tempDir
170
+ });
171
+ if (sparseResult.status !== 0) {
172
+ fs.rmSync(tempDir, { recursive: true, force: true });
173
+ return false;
174
+ }
175
+ const checkoutResult = import_cross_spawn.default.sync("git", ["checkout"], {
176
+ stdio: "pipe",
177
+ cwd: tempDir
178
+ });
179
+ if (checkoutResult.status !== 0) {
180
+ fs.rmSync(tempDir, { recursive: true, force: true });
181
+ return false;
182
+ }
183
+ const sourceDir = path.join(tempDir, fullTemplatePath);
184
+ if (!fs.existsSync(sourceDir)) {
185
+ console.error(import_picocolors.default.red(`
186
+ Template directory not found at ${sourceDir}`));
187
+ fs.rmSync(tempDir, { recursive: true, force: true });
188
+ return false;
189
+ }
190
+ fs.mkdirSync(targetDir, { recursive: true });
191
+ fs.cpSync(sourceDir, targetDir, {
192
+ recursive: true,
193
+ filter: () => {
194
+ return true;
195
+ }
196
+ });
197
+ fs.rmSync(tempDir, { recursive: true, force: true });
198
+ console.log(import_picocolors.default.green("\u2713"), "Template cloned successfully!");
199
+ return true;
200
+ }
201
+ function applyReplacements(targetDir, replacements) {
202
+ function processDirectory(dir) {
203
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
204
+ for (const entry of entries) {
205
+ const fullPath = path.join(dir, entry.name);
206
+ if (entry.isDirectory()) {
207
+ if (entry.name === "node_modules" || entry.name === "dist") {
208
+ continue;
209
+ }
210
+ processDirectory(fullPath);
211
+ } else {
212
+ let content = fs.readFileSync(fullPath, "utf-8");
213
+ let modified = false;
214
+ if (entry.name === "package.json" || entry.name.endsWith(".ts") || entry.name.endsWith(".js")) {
215
+ for (const [search, replace] of replacements) {
216
+ const regex = new RegExp(search, "g");
217
+ if (regex.test(content)) {
218
+ content = content.replace(regex, replace);
219
+ modified = true;
220
+ }
221
+ }
222
+ if (modified) {
223
+ fs.writeFileSync(fullPath, content);
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ processDirectory(targetDir);
230
+ }
231
+ function printSuccess(projectName, packageManager) {
232
+ console.log(import_picocolors.default.green("\u2713"), "Bot project created successfully!");
233
+ console.log();
234
+ console.log("Next steps:");
235
+ console.log(import_picocolors.default.cyan(` cd ${projectName}`));
236
+ console.log(import_picocolors.default.cyan(` ${getInstallCommand(packageManager)}`));
237
+ console.log("Set up your environment variables:");
238
+ console.log(import_picocolors.default.cyan(" cp .env.sample .env"));
239
+ console.log(" Edit .env with your bot credentials");
240
+ console.log("Start your bot:");
241
+ console.log(import_picocolors.default.cyan(` ${getRunCommand(packageManager, "dev")}`));
242
+ }
243
+
244
+ // src/modules/init.ts
245
+ var TEMPLATES = {
246
+ quickstart: {
247
+ name: "Bot Quickstart",
248
+ description: "Simple starter bot with basic commands",
249
+ packagePath: "bot-quickstart"
250
+ },
251
+ "thread-ai": {
252
+ name: "Thread AI Bot",
253
+ description: "AI-powered conversational bot using OpenAI",
254
+ packagePath: "bot-thread-ai"
255
+ },
256
+ poll: {
257
+ name: "Poll Bot",
258
+ description: "Interactive poll bot for creating votes",
259
+ packagePath: "bot-ask-poll"
260
+ }
261
+ };
262
+ async function init(argv2) {
263
+ const projectName = argv2._[1];
264
+ const template = argv2.template || "quickstart";
265
+ if (!projectName) {
266
+ console.error((0, import_picocolors2.red)("Error: Please provide a project name"));
267
+ console.log((0, import_picocolors2.yellow)("Usage: towns-bot init <project-name>"));
268
+ process.exit(1);
269
+ }
270
+ if (!TEMPLATES[template]) {
271
+ console.error((0, import_picocolors2.red)(`Error: Unknown template "${template}"`));
272
+ console.log((0, import_picocolors2.yellow)("Available templates:"), Object.keys(TEMPLATES).join(", "));
273
+ process.exit(1);
274
+ }
275
+ const targetDir = path2.resolve(process.cwd(), projectName);
276
+ if (fs2.existsSync(targetDir)) {
277
+ const { overwrite } = await (0, import_prompts.default)({
278
+ type: "confirm",
279
+ name: "overwrite",
280
+ message: `Directory ${projectName} already exists. Overwrite?`,
281
+ initial: false
282
+ });
283
+ if (!overwrite) {
284
+ console.log((0, import_picocolors2.yellow)("Operation cancelled"));
285
+ process.exit(0);
286
+ }
287
+ fs2.rmSync(targetDir, { recursive: true, force: true });
288
+ }
289
+ console.log((0, import_picocolors2.cyan)(`Creating a new Towns Protocol bot in ${targetDir}`));
290
+ if (template !== "quickstart") {
291
+ console.log((0, import_picocolors2.cyan)(`Using template: ${TEMPLATES[template].name}`));
292
+ }
293
+ const packageManager = getPackageManager();
294
+ const selectedTemplate = TEMPLATES[template];
295
+ try {
296
+ const success = await cloneTemplate(selectedTemplate.packagePath, targetDir);
297
+ if (!success) {
298
+ console.error((0, import_picocolors2.red)("Failed to clone template"));
299
+ process.exit(1);
300
+ }
301
+ const latestVersion = await getLatestTownsProtocolVersion();
302
+ const replacements = /* @__PURE__ */ new Map([
303
+ ["workspace:\\^", `^${latestVersion}`],
304
+ ["workspace:\\*", `^${latestVersion}`]
305
+ ]);
306
+ applyReplacements(targetDir, replacements);
307
+ const packageJsonPath = path2.join(targetDir, "package.json");
308
+ if (fs2.existsSync(packageJsonPath)) {
309
+ const content = fs2.readFileSync(packageJsonPath, "utf-8");
310
+ const edits = [
311
+ jsonc.modify(content, ["name"], projectName, {}),
312
+ jsonc.modify(content, ["version"], "0.0.1", {})
313
+ ];
314
+ let modifiedContent = jsonc.applyEdits(content, edits.flat());
315
+ const parsed = jsonc.parse(modifiedContent);
316
+ delete parsed.private;
317
+ modifiedContent = JSON.stringify(parsed, null, 2);
318
+ fs2.writeFileSync(packageJsonPath, modifiedContent);
319
+ }
320
+ printSuccess(projectName, packageManager);
321
+ } catch (error) {
322
+ console.error((0, import_picocolors2.red)("Error:"), error instanceof Error ? error.message : error);
323
+ console.error((0, import_picocolors2.red)(`Please delete the directory ${targetDir} and try again.`));
324
+ process.exit(1);
325
+ }
326
+ }
327
+
328
+ // src/modules/update.ts
329
+ var import_fs = __toESM(require("fs"));
330
+ var import_path = __toESM(require("path"));
331
+ var import_cross_spawn2 = __toESM(require("cross-spawn"));
332
+ var import_picocolors3 = require("picocolors");
333
+ var jsonc2 = __toESM(require("jsonc-parser"));
334
+ async function update(_argv) {
335
+ const packageJsonPath = import_path.default.join(process.cwd(), "package.json");
336
+ if (!import_fs.default.existsSync(packageJsonPath)) {
337
+ console.error((0, import_picocolors3.red)("Error: No package.json found in the current directory"));
338
+ console.log((0, import_picocolors3.yellow)("Please run this command from a Towns Protocol bot project directory"));
339
+ process.exit(1);
340
+ }
341
+ const packageJson = jsonc2.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
342
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
343
+ const townsPackages = Object.keys(dependencies).filter(
344
+ (pkg) => pkg.startsWith("@towns-protocol/")
345
+ );
346
+ if (townsPackages.length === 0) {
347
+ console.log((0, import_picocolors3.yellow)("No @towns-protocol packages found in this project"));
348
+ process.exit(0);
349
+ }
350
+ console.log((0, import_picocolors3.cyan)("Found Towns Protocol packages:"));
351
+ townsPackages.forEach((pkg) => {
352
+ console.log(` - ${pkg}@${dependencies[pkg]}`);
353
+ });
354
+ console.log();
355
+ console.log((0, import_picocolors3.cyan)("Fetching latest versions..."));
356
+ const latestVersions = {};
357
+ for (const pkg of townsPackages) {
358
+ try {
359
+ const version = await getLatestVersion(pkg);
360
+ latestVersions[pkg] = version;
361
+ console.log((0, import_picocolors3.green)("\u2713"), `${pkg}: ${version}`);
362
+ } catch {
363
+ console.error((0, import_picocolors3.red)("\u2717"), `Failed to fetch version for ${pkg}`);
364
+ }
365
+ }
366
+ console.log();
367
+ console.log((0, import_picocolors3.cyan)("Updating package.json..."));
368
+ const content = import_fs.default.readFileSync(packageJsonPath, "utf-8");
369
+ const edits = [];
370
+ for (const [pkg, version] of Object.entries(latestVersions)) {
371
+ const currentVersion = dependencies[pkg];
372
+ if (currentVersion !== `^${version}`) {
373
+ if (packageJson.dependencies?.[pkg]) {
374
+ edits.push(...jsonc2.modify(content, ["dependencies", pkg], `^${version}`, {}));
375
+ }
376
+ if (packageJson.devDependencies?.[pkg]) {
377
+ edits.push(...jsonc2.modify(content, ["devDependencies", pkg], `^${version}`, {}));
378
+ }
379
+ }
380
+ }
381
+ if (edits.length > 0) {
382
+ const modifiedContent = jsonc2.applyEdits(content, edits);
383
+ import_fs.default.writeFileSync(packageJsonPath, modifiedContent);
384
+ console.log((0, import_picocolors3.green)("\u2713"), "Updated package.json");
385
+ const packageManager = getPackageManager();
386
+ console.log();
387
+ console.log((0, import_picocolors3.cyan)(`Installing dependencies with ${packageManager}...`));
388
+ try {
389
+ await runCommand(packageManager, [
390
+ getInstallCommand(packageManager).split(" ")[1] || "install"
391
+ ]);
392
+ console.log();
393
+ console.log((0, import_picocolors3.green)("\u2713"), "Dependencies updated successfully!");
394
+ } catch {
395
+ console.error((0, import_picocolors3.red)("Error:"), "Failed to install dependencies");
396
+ console.log(
397
+ (0, import_picocolors3.yellow)("Please run"),
398
+ (0, import_picocolors3.cyan)(getInstallCommand(packageManager)),
399
+ (0, import_picocolors3.yellow)("manually")
400
+ );
401
+ }
402
+ } else {
403
+ console.log((0, import_picocolors3.green)("\u2713"), "All packages are already up to date!");
404
+ }
405
+ }
406
+ async function getLatestVersion(packageName) {
407
+ return new Promise((resolve2, reject) => {
408
+ const child = (0, import_cross_spawn2.default)("npm", ["view", packageName, "version"], {
409
+ stdio: ["ignore", "pipe", "ignore"]
410
+ });
411
+ let output = "";
412
+ child.stdout?.on("data", (data) => {
413
+ output += data.toString();
414
+ });
415
+ child.on("close", (code) => {
416
+ if (code !== 0) {
417
+ reject(new Error(`Failed to fetch version for ${packageName}`));
418
+ } else {
419
+ resolve2(output.trim());
420
+ }
421
+ });
422
+ child.on("error", reject);
423
+ });
424
+ }
425
+
426
+ // src/index.ts
427
+ var argv = (0, import_minimist.default)(process.argv.slice(2), {
428
+ string: ["template"],
429
+ boolean: ["help"],
430
+ alias: {
431
+ h: "help",
432
+ t: "template"
433
+ }
434
+ });
435
+ async function main() {
436
+ const command = argv._[0];
437
+ if (argv.help || !command) {
438
+ showHelp();
439
+ return;
440
+ }
441
+ try {
442
+ switch (command) {
443
+ case "init":
444
+ await init(argv);
445
+ break;
446
+ case "update":
447
+ await update(argv);
448
+ break;
449
+ default:
450
+ console.error((0, import_picocolors4.red)(`Unknown command: ${command}`));
451
+ showHelp();
452
+ process.exit(1);
453
+ }
454
+ } catch (error) {
455
+ console.error((0, import_picocolors4.red)("Error:"), error instanceof Error ? error.message : error);
456
+ process.exit(1);
457
+ }
458
+ }
459
+ function showHelp() {
460
+ console.log(`
461
+ ${(0, import_picocolors4.cyan)("towns-bot")} - CLI for creating and managing Towns Protocol bot projects
462
+
463
+ ${(0, import_picocolors4.yellow)("Usage:")}
464
+ towns-bot <command> [options]
465
+
466
+ ${(0, import_picocolors4.yellow)("Commands:")}
467
+ ${(0, import_picocolors4.green)("init")} [project-name] Create a new bot project
468
+ ${(0, import_picocolors4.green)("update")} Update @towns-protocol dependencies to latest versions
469
+
470
+ ${(0, import_picocolors4.yellow)("Options:")}
471
+ -t, --template <name> Template to use:
472
+ ${Object.entries(TEMPLATES).map(
473
+ ([key, template]) => ` ${key} - ${template.description}`
474
+ ).join("\n")}
475
+ Default: quickstart
476
+ -h, --help Show this help message
477
+
478
+ ${(0, import_picocolors4.yellow)("Examples:")}
479
+ ${(0, import_picocolors4.cyan)("# Create a new bot project with the default template")}
480
+ towns-bot init my-bot
481
+
482
+ ${(0, import_picocolors4.cyan)("# Create an AI bot project")}
483
+ towns-bot init my-ai-bot --template thread-ai
484
+
485
+ ${(0, import_picocolors4.cyan)("# Update dependencies in current project")}
486
+ towns-bot update
487
+ `);
488
+ }
489
+ main().catch((error) => {
490
+ console.error((0, import_picocolors4.red)("Unexpected error:"), error);
491
+ process.exit(1);
492
+ });
493
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/modules/init.ts","../src/modules/utils.ts","../src/modules/update.ts"],"sourcesContent":["import minimist from 'minimist'\nimport { green, red, yellow, cyan } from 'picocolors'\nimport { init, TEMPLATES, type Template } from './modules/init.js'\nimport { update } from './modules/update.js'\n\nexport type Argv = typeof argv\n\nconst argv = minimist(process.argv.slice(2), {\n string: ['template'],\n boolean: ['help'],\n alias: {\n h: 'help',\n t: 'template',\n },\n})\n\nasync function main() {\n const command = argv._[0]\n\n if (argv.help || !command) {\n showHelp()\n return\n }\n\n try {\n switch (command) {\n case 'init':\n await init(argv)\n break\n case 'update':\n await update(argv)\n break\n default:\n console.error(red(`Unknown command: ${command}`))\n showHelp()\n process.exit(1)\n }\n } catch (error) {\n console.error(red('Error:'), error instanceof Error ? error.message : error)\n process.exit(1)\n }\n}\n\nfunction showHelp() {\n console.log(`\n${cyan('towns-bot')} - CLI for creating and managing Towns Protocol bot projects\n\n${yellow('Usage:')}\n towns-bot <command> [options]\n\n${yellow('Commands:')}\n ${green('init')} [project-name] Create a new bot project\n ${green('update')} Update @towns-protocol dependencies to latest versions\n\n${yellow('Options:')}\n -t, --template <name> Template to use:\n${Object.entries(TEMPLATES)\n .map(\n ([key, template]: [string, Template]) =>\n ` ${key} - ${template.description}`,\n )\n .join('\\n')}\n Default: quickstart\n -h, --help Show this help message\n\n${yellow('Examples:')}\n ${cyan('# Create a new bot project with the default template')}\n towns-bot init my-bot\n\n ${cyan('# Create an AI bot project')}\n towns-bot init my-ai-bot --template thread-ai\n\n ${cyan('# Update dependencies in current project')}\n towns-bot update\n`)\n}\n\nmain().catch((error) => {\n console.error(red('Unexpected error:'), error)\n process.exit(1)\n})\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { default as prompts } from 'prompts'\nimport { red, yellow, cyan } from 'picocolors'\nimport * as jsonc from 'jsonc-parser'\nimport {\n getPackageManager,\n getLatestTownsProtocolVersion,\n cloneTemplate,\n applyReplacements,\n printSuccess,\n type PackageJson,\n} from './utils.js'\nimport type { Argv } from '../index.js'\n\nexport type Template = (typeof TEMPLATES)[keyof typeof TEMPLATES]\nexport const TEMPLATES = {\n quickstart: {\n name: 'Bot Quickstart',\n description: 'Simple starter bot with basic commands',\n packagePath: 'bot-quickstart',\n },\n 'thread-ai': {\n name: 'Thread AI Bot',\n description: 'AI-powered conversational bot using OpenAI',\n packagePath: 'bot-thread-ai',\n },\n poll: {\n name: 'Poll Bot',\n description: 'Interactive poll bot for creating votes',\n packagePath: 'bot-ask-poll',\n },\n} as const\n\nexport async function init(argv: Argv) {\n const projectName = argv._[1]\n const template = argv.template || 'quickstart'\n\n if (!projectName) {\n console.error(red('Error: Please provide a project name'))\n console.log(yellow('Usage: towns-bot init <project-name>'))\n process.exit(1)\n }\n\n if (!TEMPLATES[template as keyof typeof TEMPLATES]) {\n console.error(red(`Error: Unknown template \"${template}\"`))\n console.log(yellow('Available templates:'), Object.keys(TEMPLATES).join(', '))\n process.exit(1)\n }\n\n const targetDir = path.resolve(process.cwd(), projectName)\n\n if (fs.existsSync(targetDir)) {\n const { overwrite } = await prompts({\n type: 'confirm',\n name: 'overwrite',\n message: `Directory ${projectName} already exists. Overwrite?`,\n initial: false,\n })\n\n if (!overwrite) {\n console.log(yellow('Operation cancelled'))\n process.exit(0)\n }\n\n fs.rmSync(targetDir, { recursive: true, force: true })\n }\n\n console.log(cyan(`Creating a new Towns Protocol bot in ${targetDir}`))\n if (template !== 'quickstart') {\n console.log(cyan(`Using template: ${TEMPLATES[template as keyof typeof TEMPLATES].name}`))\n }\n\n const packageManager = getPackageManager()\n const selectedTemplate = TEMPLATES[template as keyof typeof TEMPLATES]\n\n try {\n // Clone template from GitHub\n const success = await cloneTemplate(selectedTemplate.packagePath, targetDir)\n if (!success) {\n console.error(red('Failed to clone template'))\n process.exit(1)\n }\n const latestVersion = await getLatestTownsProtocolVersion()\n // Replace workspace dependencies in package.json and other files\n const replacements = new Map([\n ['workspace:\\\\^', `^${latestVersion}`],\n ['workspace:\\\\*', `^${latestVersion}`],\n ])\n\n // Apply replacements to all relevant files\n applyReplacements(targetDir, replacements)\n\n const packageJsonPath = path.join(targetDir, 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const content = fs.readFileSync(packageJsonPath, 'utf-8')\n const edits = [\n jsonc.modify(content, ['name'], projectName, {}),\n jsonc.modify(content, ['version'], '0.0.1', {}),\n ]\n\n let modifiedContent = jsonc.applyEdits(content, edits.flat())\n\n const parsed = jsonc.parse(modifiedContent) as PackageJson\n delete parsed.private\n\n modifiedContent = JSON.stringify(parsed, null, 2)\n fs.writeFileSync(packageJsonPath, modifiedContent)\n }\n\n printSuccess(projectName, packageManager)\n } catch (error) {\n console.error(red('Error:'), error instanceof Error ? error.message : error)\n console.error(red(`Please delete the directory ${targetDir} and try again.`))\n process.exit(1)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { default as spawn } from 'cross-spawn'\nimport picocolors from 'picocolors'\n\nexport type PackageJson = {\n private?: boolean\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n}\n\nexport const getPackageManager = () => {\n if (process.env.npm_config_user_agent) {\n const agent = process.env.npm_config_user_agent\n if (agent.startsWith('yarn')) return 'yarn'\n if (agent.startsWith('npm')) return 'npm'\n if (agent.startsWith('pnpm')) return 'pnpm'\n if (agent.startsWith('bun')) return 'bun'\n }\n // Default to npm if no user agent is found\n return 'npm'\n}\n\nexport function getInstallCommand(packageManager: string): string {\n switch (packageManager) {\n case 'bun':\n return 'bun install'\n case 'yarn':\n return 'yarn'\n case 'pnpm':\n return 'pnpm install'\n default:\n return 'npm install'\n }\n}\n\nexport function getRunCommand(packageManager: string, script: string): string {\n switch (packageManager) {\n case 'bun':\n return `bun run ${script}`\n case 'yarn':\n return `yarn ${script}`\n case 'pnpm':\n return `pnpm ${script}`\n default:\n return `npm run ${script}`\n }\n}\n\nexport function runCommand(command: string, args: string[], cwd?: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: 'inherit',\n cwd,\n shell: process.platform === 'win32',\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error(`Command failed with exit code ${code}`))\n } else {\n resolve()\n }\n })\n\n child.on('error', reject)\n })\n}\n\nexport async function getLatestTownsProtocolVersion(): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['view', '@towns-protocol/bot', 'version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n\n let output = ''\n child.stdout?.on('data', (data) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n output += data.toString()\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error('Failed to fetch latest @towns-protocol/bot version'))\n } else {\n resolve(output.trim())\n }\n })\n\n child.on('error', reject)\n })\n}\n\nexport function copyDirectory(src: string, dest: string, replacements?: Map<string, string>) {\n if (!fs.existsSync(dest)) {\n fs.mkdirSync(dest, { recursive: true })\n }\n\n const entries = fs.readdirSync(src, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') {\n continue\n }\n copyDirectory(srcPath, destPath, replacements)\n } else {\n let content = fs.readFileSync(srcPath, 'utf-8')\n\n if (\n replacements &&\n (entry.name === 'package.json' ||\n entry.name.endsWith('.ts') ||\n entry.name.endsWith('.js'))\n ) {\n for (const [search, replace] of replacements) {\n content = content.replace(new RegExp(search, 'g'), replace)\n }\n }\n\n fs.writeFileSync(destPath, content)\n }\n }\n}\n\nexport function getLatestSdkTag(): string | null {\n const tagsResult = spawn.sync(\n 'git',\n ['ls-remote', '--tags', 'https://github.com/towns-protocol/towns.git', 'sdk-*'],\n { encoding: 'utf8' },\n )\n\n if (tagsResult.status !== 0 || !tagsResult.stdout) return null\n\n const tags = tagsResult.stdout\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const [_hash, ref] = line.split('\\t')\n const tag = ref.replace('refs/tags/', '').replace(/\\^{}$/, '')\n\n // Extract version numbers from tags like sdk-hash-1.2.3\n const match = tag.match(/^sdk-[0-9a-f]+-(\\d+)\\.(\\d+)\\.(\\d+)$/)\n if (!match) return null\n\n return {\n tag,\n version: [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])],\n }\n })\n .filter(\n (item): item is { tag: string; version: number[] } =>\n item !== null && Array.isArray(item.version) && item.version.length === 3,\n )\n .sort((a, b) => {\n // Compare version numbers\n for (let i = 0; i < 3; i++) {\n if (a.version[i] !== b.version[i]) {\n return b.version[i] - a.version[i]\n }\n }\n return 0\n })\n\n return tags.length > 0 ? tags[0].tag : null\n}\n\nexport async function cloneTemplate(packagePath: string, targetDir: string): Promise<boolean> {\n console.log(picocolors.blue('Cloning template from GitHub...'))\n\n const tempDir = `${targetDir}-temp`\n const fullTemplatePath = `packages/examples/${packagePath}`\n\n // Get latest SDK tag\n const latestSdkTag = getLatestSdkTag()\n if (!latestSdkTag) {\n console.error(picocolors.red('Failed to get latest SDK tag.'))\n return false\n }\n\n // Clone with minimal data to a temporary directory\n const cloneResult = spawn.sync(\n 'git',\n [\n 'clone',\n '--no-checkout',\n '--depth',\n '1',\n '--sparse',\n '--branch',\n latestSdkTag,\n 'https://github.com/towns-protocol/towns.git',\n tempDir,\n ],\n { stdio: 'pipe' },\n )\n if (cloneResult.status !== 0) return false\n\n // Set up sparse checkout for the specific template\n const sparseResult = spawn.sync('git', ['sparse-checkout', 'set', fullTemplatePath], {\n stdio: 'pipe',\n cwd: tempDir,\n })\n if (sparseResult.status !== 0) {\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Checkout the content\n const checkoutResult = spawn.sync('git', ['checkout'], {\n stdio: 'pipe',\n cwd: tempDir,\n })\n if (checkoutResult.status !== 0) {\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Verify template directory exists\n const sourceDir = path.join(tempDir, fullTemplatePath)\n if (!fs.existsSync(sourceDir)) {\n console.error(picocolors.red(`\\nTemplate directory not found at ${sourceDir}`))\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Copy template contents to target directory\n fs.mkdirSync(targetDir, { recursive: true })\n // Use filter to ensure all files (including hidden) are copied\n fs.cpSync(sourceDir, targetDir, {\n recursive: true,\n filter: () => {\n // Copy all files, including hidden ones\n return true\n },\n })\n\n // Clean up temporary directory\n fs.rmSync(tempDir, { recursive: true, force: true })\n\n console.log(picocolors.green('✓'), 'Template cloned successfully!')\n return true\n}\n\nexport function applyReplacements(targetDir: string, replacements: Map<string, string>) {\n function processDirectory(dir: string) {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') {\n continue\n }\n processDirectory(fullPath)\n } else {\n let content = fs.readFileSync(fullPath, 'utf-8')\n let modified = false\n\n if (\n entry.name === 'package.json' ||\n entry.name.endsWith('.ts') ||\n entry.name.endsWith('.js')\n ) {\n for (const [search, replace] of replacements) {\n const regex = new RegExp(search, 'g')\n if (regex.test(content)) {\n content = content.replace(regex, replace)\n modified = true\n }\n }\n\n if (modified) {\n fs.writeFileSync(fullPath, content)\n }\n }\n }\n }\n }\n\n processDirectory(targetDir)\n}\n\nexport function printSuccess(projectName: string, packageManager: string) {\n console.log(picocolors.green('✓'), 'Bot project created successfully!')\n console.log()\n console.log('Next steps:')\n console.log(picocolors.cyan(` cd ${projectName}`))\n console.log(picocolors.cyan(` ${getInstallCommand(packageManager)}`))\n console.log('Set up your environment variables:')\n console.log(picocolors.cyan(' cp .env.sample .env'))\n console.log(' Edit .env with your bot credentials')\n console.log('Start your bot:')\n console.log(picocolors.cyan(` ${getRunCommand(packageManager, 'dev')}`))\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { default as spawn } from 'cross-spawn'\nimport { green, red, yellow, cyan } from 'picocolors'\nimport * as jsonc from 'jsonc-parser'\nimport { getPackageManager, getInstallCommand, runCommand, type PackageJson } from './utils.js'\nimport type { Argv } from '../index.js'\n\ninterface PackageVersions {\n [key: string]: string\n}\n\nexport async function update(_argv: Argv) {\n const packageJsonPath = path.join(process.cwd(), 'package.json')\n\n if (!fs.existsSync(packageJsonPath)) {\n console.error(red('Error: No package.json found in the current directory'))\n console.log(yellow('Please run this command from a Towns Protocol bot project directory'))\n process.exit(1)\n }\n\n const packageJson = jsonc.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as PackageJson\n const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies }\n\n const townsPackages = Object.keys(dependencies).filter((pkg) =>\n pkg.startsWith('@towns-protocol/'),\n )\n\n if (townsPackages.length === 0) {\n console.log(yellow('No @towns-protocol packages found in this project'))\n process.exit(0)\n }\n\n console.log(cyan('Found Towns Protocol packages:'))\n townsPackages.forEach((pkg) => {\n console.log(` - ${pkg}@${dependencies[pkg]}`)\n })\n console.log()\n\n console.log(cyan('Fetching latest versions...'))\n const latestVersions: PackageVersions = {}\n\n for (const pkg of townsPackages) {\n try {\n const version = await getLatestVersion(pkg)\n latestVersions[pkg] = version\n console.log(green('✓'), `${pkg}: ${version}`)\n } catch {\n console.error(red('✗'), `Failed to fetch version for ${pkg}`)\n }\n }\n\n console.log()\n console.log(cyan('Updating package.json...'))\n\n const content = fs.readFileSync(packageJsonPath, 'utf-8')\n const edits: jsonc.Edit[] = []\n\n for (const [pkg, version] of Object.entries(latestVersions)) {\n const currentVersion = dependencies[pkg]\n if (currentVersion !== `^${version}`) {\n if (packageJson.dependencies?.[pkg]) {\n edits.push(...jsonc.modify(content, ['dependencies', pkg], `^${version}`, {}))\n }\n if (packageJson.devDependencies?.[pkg]) {\n edits.push(...jsonc.modify(content, ['devDependencies', pkg], `^${version}`, {}))\n }\n }\n }\n\n if (edits.length > 0) {\n const modifiedContent = jsonc.applyEdits(content, edits)\n fs.writeFileSync(packageJsonPath, modifiedContent)\n console.log(green('✓'), 'Updated package.json')\n\n const packageManager = getPackageManager()\n console.log()\n console.log(cyan(`Installing dependencies with ${packageManager}...`))\n\n try {\n await runCommand(packageManager, [\n getInstallCommand(packageManager).split(' ')[1] || 'install',\n ])\n console.log()\n console.log(green('✓'), 'Dependencies updated successfully!')\n } catch {\n console.error(red('Error:'), 'Failed to install dependencies')\n console.log(\n yellow('Please run'),\n cyan(getInstallCommand(packageManager)),\n yellow('manually'),\n )\n }\n } else {\n console.log(green('✓'), 'All packages are already up to date!')\n }\n}\n\nasync function getLatestVersion(packageName: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['view', packageName, 'version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n\n let output = ''\n child.stdout?.on('data', (data) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n output += data.toString()\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error(`Failed to fetch version for ${packageName}`))\n } else {\n resolve(output.trim())\n }\n })\n\n child.on('error', reject)\n })\n}\n"],"mappings":"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","names":["import_picocolors","fs","path","import_picocolors","resolve","spawn","spawn","picocolors","argv","prompts","import_cross_spawn","import_picocolors","jsonc","path","fs","resolve","spawn","minimist"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,466 @@
1
+ // src/index.ts
2
+ import minimist from "minimist";
3
+ import { green as green2, red as red3, yellow as yellow3, cyan as cyan3 } from "picocolors";
4
+
5
+ // src/modules/init.ts
6
+ import * as fs2 from "node:fs";
7
+ import * as path2 from "node:path";
8
+ import { default as prompts } from "prompts";
9
+ import { red, yellow, cyan } from "picocolors";
10
+ import * as jsonc from "jsonc-parser";
11
+
12
+ // src/modules/utils.ts
13
+ import * as fs from "node:fs";
14
+ import * as path from "node:path";
15
+ import { default as spawn } from "cross-spawn";
16
+ import picocolors from "picocolors";
17
+ var getPackageManager = () => {
18
+ if (process.env.npm_config_user_agent) {
19
+ const agent = process.env.npm_config_user_agent;
20
+ if (agent.startsWith("yarn")) return "yarn";
21
+ if (agent.startsWith("npm")) return "npm";
22
+ if (agent.startsWith("pnpm")) return "pnpm";
23
+ if (agent.startsWith("bun")) return "bun";
24
+ }
25
+ return "npm";
26
+ };
27
+ function getInstallCommand(packageManager) {
28
+ switch (packageManager) {
29
+ case "bun":
30
+ return "bun install";
31
+ case "yarn":
32
+ return "yarn";
33
+ case "pnpm":
34
+ return "pnpm install";
35
+ default:
36
+ return "npm install";
37
+ }
38
+ }
39
+ function getRunCommand(packageManager, script) {
40
+ switch (packageManager) {
41
+ case "bun":
42
+ return `bun run ${script}`;
43
+ case "yarn":
44
+ return `yarn ${script}`;
45
+ case "pnpm":
46
+ return `pnpm ${script}`;
47
+ default:
48
+ return `npm run ${script}`;
49
+ }
50
+ }
51
+ function runCommand(command, args, cwd) {
52
+ return new Promise((resolve2, reject) => {
53
+ const child = spawn(command, args, {
54
+ stdio: "inherit",
55
+ cwd,
56
+ shell: process.platform === "win32"
57
+ });
58
+ child.on("close", (code) => {
59
+ if (code !== 0) {
60
+ reject(new Error(`Command failed with exit code ${code}`));
61
+ } else {
62
+ resolve2();
63
+ }
64
+ });
65
+ child.on("error", reject);
66
+ });
67
+ }
68
+ async function getLatestTownsProtocolVersion() {
69
+ return new Promise((resolve2, reject) => {
70
+ const child = spawn("npm", ["view", "@towns-protocol/bot", "version"], {
71
+ stdio: ["ignore", "pipe", "ignore"]
72
+ });
73
+ let output = "";
74
+ child.stdout?.on("data", (data) => {
75
+ output += data.toString();
76
+ });
77
+ child.on("close", (code) => {
78
+ if (code !== 0) {
79
+ reject(new Error("Failed to fetch latest @towns-protocol/bot version"));
80
+ } else {
81
+ resolve2(output.trim());
82
+ }
83
+ });
84
+ child.on("error", reject);
85
+ });
86
+ }
87
+ function getLatestSdkTag() {
88
+ const tagsResult = spawn.sync(
89
+ "git",
90
+ ["ls-remote", "--tags", "https://github.com/towns-protocol/towns.git", "sdk-*"],
91
+ { encoding: "utf8" }
92
+ );
93
+ if (tagsResult.status !== 0 || !tagsResult.stdout) return null;
94
+ const tags = tagsResult.stdout.split("\n").filter(Boolean).map((line) => {
95
+ const [_hash, ref] = line.split(" ");
96
+ const tag = ref.replace("refs/tags/", "").replace(/\^{}$/, "");
97
+ const match = tag.match(/^sdk-[0-9a-f]+-(\d+)\.(\d+)\.(\d+)$/);
98
+ if (!match) return null;
99
+ return {
100
+ tag,
101
+ version: [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]
102
+ };
103
+ }).filter(
104
+ (item) => item !== null && Array.isArray(item.version) && item.version.length === 3
105
+ ).sort((a, b) => {
106
+ for (let i = 0; i < 3; i++) {
107
+ if (a.version[i] !== b.version[i]) {
108
+ return b.version[i] - a.version[i];
109
+ }
110
+ }
111
+ return 0;
112
+ });
113
+ return tags.length > 0 ? tags[0].tag : null;
114
+ }
115
+ async function cloneTemplate(packagePath, targetDir) {
116
+ console.log(picocolors.blue("Cloning template from GitHub..."));
117
+ const tempDir = `${targetDir}-temp`;
118
+ const fullTemplatePath = `packages/examples/${packagePath}`;
119
+ const latestSdkTag = getLatestSdkTag();
120
+ if (!latestSdkTag) {
121
+ console.error(picocolors.red("Failed to get latest SDK tag."));
122
+ return false;
123
+ }
124
+ const cloneResult = spawn.sync(
125
+ "git",
126
+ [
127
+ "clone",
128
+ "--no-checkout",
129
+ "--depth",
130
+ "1",
131
+ "--sparse",
132
+ "--branch",
133
+ latestSdkTag,
134
+ "https://github.com/towns-protocol/towns.git",
135
+ tempDir
136
+ ],
137
+ { stdio: "pipe" }
138
+ );
139
+ if (cloneResult.status !== 0) return false;
140
+ const sparseResult = spawn.sync("git", ["sparse-checkout", "set", fullTemplatePath], {
141
+ stdio: "pipe",
142
+ cwd: tempDir
143
+ });
144
+ if (sparseResult.status !== 0) {
145
+ fs.rmSync(tempDir, { recursive: true, force: true });
146
+ return false;
147
+ }
148
+ const checkoutResult = spawn.sync("git", ["checkout"], {
149
+ stdio: "pipe",
150
+ cwd: tempDir
151
+ });
152
+ if (checkoutResult.status !== 0) {
153
+ fs.rmSync(tempDir, { recursive: true, force: true });
154
+ return false;
155
+ }
156
+ const sourceDir = path.join(tempDir, fullTemplatePath);
157
+ if (!fs.existsSync(sourceDir)) {
158
+ console.error(picocolors.red(`
159
+ Template directory not found at ${sourceDir}`));
160
+ fs.rmSync(tempDir, { recursive: true, force: true });
161
+ return false;
162
+ }
163
+ fs.mkdirSync(targetDir, { recursive: true });
164
+ fs.cpSync(sourceDir, targetDir, {
165
+ recursive: true,
166
+ filter: () => {
167
+ return true;
168
+ }
169
+ });
170
+ fs.rmSync(tempDir, { recursive: true, force: true });
171
+ console.log(picocolors.green("\u2713"), "Template cloned successfully!");
172
+ return true;
173
+ }
174
+ function applyReplacements(targetDir, replacements) {
175
+ function processDirectory(dir) {
176
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
177
+ for (const entry of entries) {
178
+ const fullPath = path.join(dir, entry.name);
179
+ if (entry.isDirectory()) {
180
+ if (entry.name === "node_modules" || entry.name === "dist") {
181
+ continue;
182
+ }
183
+ processDirectory(fullPath);
184
+ } else {
185
+ let content = fs.readFileSync(fullPath, "utf-8");
186
+ let modified = false;
187
+ if (entry.name === "package.json" || entry.name.endsWith(".ts") || entry.name.endsWith(".js")) {
188
+ for (const [search, replace] of replacements) {
189
+ const regex = new RegExp(search, "g");
190
+ if (regex.test(content)) {
191
+ content = content.replace(regex, replace);
192
+ modified = true;
193
+ }
194
+ }
195
+ if (modified) {
196
+ fs.writeFileSync(fullPath, content);
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+ processDirectory(targetDir);
203
+ }
204
+ function printSuccess(projectName, packageManager) {
205
+ console.log(picocolors.green("\u2713"), "Bot project created successfully!");
206
+ console.log();
207
+ console.log("Next steps:");
208
+ console.log(picocolors.cyan(` cd ${projectName}`));
209
+ console.log(picocolors.cyan(` ${getInstallCommand(packageManager)}`));
210
+ console.log("Set up your environment variables:");
211
+ console.log(picocolors.cyan(" cp .env.sample .env"));
212
+ console.log(" Edit .env with your bot credentials");
213
+ console.log("Start your bot:");
214
+ console.log(picocolors.cyan(` ${getRunCommand(packageManager, "dev")}`));
215
+ }
216
+
217
+ // src/modules/init.ts
218
+ var TEMPLATES = {
219
+ quickstart: {
220
+ name: "Bot Quickstart",
221
+ description: "Simple starter bot with basic commands",
222
+ packagePath: "bot-quickstart"
223
+ },
224
+ "thread-ai": {
225
+ name: "Thread AI Bot",
226
+ description: "AI-powered conversational bot using OpenAI",
227
+ packagePath: "bot-thread-ai"
228
+ },
229
+ poll: {
230
+ name: "Poll Bot",
231
+ description: "Interactive poll bot for creating votes",
232
+ packagePath: "bot-ask-poll"
233
+ }
234
+ };
235
+ async function init(argv2) {
236
+ const projectName = argv2._[1];
237
+ const template = argv2.template || "quickstart";
238
+ if (!projectName) {
239
+ console.error(red("Error: Please provide a project name"));
240
+ console.log(yellow("Usage: towns-bot init <project-name>"));
241
+ process.exit(1);
242
+ }
243
+ if (!TEMPLATES[template]) {
244
+ console.error(red(`Error: Unknown template "${template}"`));
245
+ console.log(yellow("Available templates:"), Object.keys(TEMPLATES).join(", "));
246
+ process.exit(1);
247
+ }
248
+ const targetDir = path2.resolve(process.cwd(), projectName);
249
+ if (fs2.existsSync(targetDir)) {
250
+ const { overwrite } = await prompts({
251
+ type: "confirm",
252
+ name: "overwrite",
253
+ message: `Directory ${projectName} already exists. Overwrite?`,
254
+ initial: false
255
+ });
256
+ if (!overwrite) {
257
+ console.log(yellow("Operation cancelled"));
258
+ process.exit(0);
259
+ }
260
+ fs2.rmSync(targetDir, { recursive: true, force: true });
261
+ }
262
+ console.log(cyan(`Creating a new Towns Protocol bot in ${targetDir}`));
263
+ if (template !== "quickstart") {
264
+ console.log(cyan(`Using template: ${TEMPLATES[template].name}`));
265
+ }
266
+ const packageManager = getPackageManager();
267
+ const selectedTemplate = TEMPLATES[template];
268
+ try {
269
+ const success = await cloneTemplate(selectedTemplate.packagePath, targetDir);
270
+ if (!success) {
271
+ console.error(red("Failed to clone template"));
272
+ process.exit(1);
273
+ }
274
+ const latestVersion = await getLatestTownsProtocolVersion();
275
+ const replacements = /* @__PURE__ */ new Map([
276
+ ["workspace:\\^", `^${latestVersion}`],
277
+ ["workspace:\\*", `^${latestVersion}`]
278
+ ]);
279
+ applyReplacements(targetDir, replacements);
280
+ const packageJsonPath = path2.join(targetDir, "package.json");
281
+ if (fs2.existsSync(packageJsonPath)) {
282
+ const content = fs2.readFileSync(packageJsonPath, "utf-8");
283
+ const edits = [
284
+ jsonc.modify(content, ["name"], projectName, {}),
285
+ jsonc.modify(content, ["version"], "0.0.1", {})
286
+ ];
287
+ let modifiedContent = jsonc.applyEdits(content, edits.flat());
288
+ const parsed = jsonc.parse(modifiedContent);
289
+ delete parsed.private;
290
+ modifiedContent = JSON.stringify(parsed, null, 2);
291
+ fs2.writeFileSync(packageJsonPath, modifiedContent);
292
+ }
293
+ printSuccess(projectName, packageManager);
294
+ } catch (error) {
295
+ console.error(red("Error:"), error instanceof Error ? error.message : error);
296
+ console.error(red(`Please delete the directory ${targetDir} and try again.`));
297
+ process.exit(1);
298
+ }
299
+ }
300
+
301
+ // src/modules/update.ts
302
+ import fs3 from "fs";
303
+ import path3 from "path";
304
+ import { default as spawn2 } from "cross-spawn";
305
+ import { green, red as red2, yellow as yellow2, cyan as cyan2 } from "picocolors";
306
+ import * as jsonc2 from "jsonc-parser";
307
+ async function update(_argv) {
308
+ const packageJsonPath = path3.join(process.cwd(), "package.json");
309
+ if (!fs3.existsSync(packageJsonPath)) {
310
+ console.error(red2("Error: No package.json found in the current directory"));
311
+ console.log(yellow2("Please run this command from a Towns Protocol bot project directory"));
312
+ process.exit(1);
313
+ }
314
+ const packageJson = jsonc2.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
315
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
316
+ const townsPackages = Object.keys(dependencies).filter(
317
+ (pkg) => pkg.startsWith("@towns-protocol/")
318
+ );
319
+ if (townsPackages.length === 0) {
320
+ console.log(yellow2("No @towns-protocol packages found in this project"));
321
+ process.exit(0);
322
+ }
323
+ console.log(cyan2("Found Towns Protocol packages:"));
324
+ townsPackages.forEach((pkg) => {
325
+ console.log(` - ${pkg}@${dependencies[pkg]}`);
326
+ });
327
+ console.log();
328
+ console.log(cyan2("Fetching latest versions..."));
329
+ const latestVersions = {};
330
+ for (const pkg of townsPackages) {
331
+ try {
332
+ const version = await getLatestVersion(pkg);
333
+ latestVersions[pkg] = version;
334
+ console.log(green("\u2713"), `${pkg}: ${version}`);
335
+ } catch {
336
+ console.error(red2("\u2717"), `Failed to fetch version for ${pkg}`);
337
+ }
338
+ }
339
+ console.log();
340
+ console.log(cyan2("Updating package.json..."));
341
+ const content = fs3.readFileSync(packageJsonPath, "utf-8");
342
+ const edits = [];
343
+ for (const [pkg, version] of Object.entries(latestVersions)) {
344
+ const currentVersion = dependencies[pkg];
345
+ if (currentVersion !== `^${version}`) {
346
+ if (packageJson.dependencies?.[pkg]) {
347
+ edits.push(...jsonc2.modify(content, ["dependencies", pkg], `^${version}`, {}));
348
+ }
349
+ if (packageJson.devDependencies?.[pkg]) {
350
+ edits.push(...jsonc2.modify(content, ["devDependencies", pkg], `^${version}`, {}));
351
+ }
352
+ }
353
+ }
354
+ if (edits.length > 0) {
355
+ const modifiedContent = jsonc2.applyEdits(content, edits);
356
+ fs3.writeFileSync(packageJsonPath, modifiedContent);
357
+ console.log(green("\u2713"), "Updated package.json");
358
+ const packageManager = getPackageManager();
359
+ console.log();
360
+ console.log(cyan2(`Installing dependencies with ${packageManager}...`));
361
+ try {
362
+ await runCommand(packageManager, [
363
+ getInstallCommand(packageManager).split(" ")[1] || "install"
364
+ ]);
365
+ console.log();
366
+ console.log(green("\u2713"), "Dependencies updated successfully!");
367
+ } catch {
368
+ console.error(red2("Error:"), "Failed to install dependencies");
369
+ console.log(
370
+ yellow2("Please run"),
371
+ cyan2(getInstallCommand(packageManager)),
372
+ yellow2("manually")
373
+ );
374
+ }
375
+ } else {
376
+ console.log(green("\u2713"), "All packages are already up to date!");
377
+ }
378
+ }
379
+ async function getLatestVersion(packageName) {
380
+ return new Promise((resolve2, reject) => {
381
+ const child = spawn2("npm", ["view", packageName, "version"], {
382
+ stdio: ["ignore", "pipe", "ignore"]
383
+ });
384
+ let output = "";
385
+ child.stdout?.on("data", (data) => {
386
+ output += data.toString();
387
+ });
388
+ child.on("close", (code) => {
389
+ if (code !== 0) {
390
+ reject(new Error(`Failed to fetch version for ${packageName}`));
391
+ } else {
392
+ resolve2(output.trim());
393
+ }
394
+ });
395
+ child.on("error", reject);
396
+ });
397
+ }
398
+
399
+ // src/index.ts
400
+ var argv = minimist(process.argv.slice(2), {
401
+ string: ["template"],
402
+ boolean: ["help"],
403
+ alias: {
404
+ h: "help",
405
+ t: "template"
406
+ }
407
+ });
408
+ async function main() {
409
+ const command = argv._[0];
410
+ if (argv.help || !command) {
411
+ showHelp();
412
+ return;
413
+ }
414
+ try {
415
+ switch (command) {
416
+ case "init":
417
+ await init(argv);
418
+ break;
419
+ case "update":
420
+ await update(argv);
421
+ break;
422
+ default:
423
+ console.error(red3(`Unknown command: ${command}`));
424
+ showHelp();
425
+ process.exit(1);
426
+ }
427
+ } catch (error) {
428
+ console.error(red3("Error:"), error instanceof Error ? error.message : error);
429
+ process.exit(1);
430
+ }
431
+ }
432
+ function showHelp() {
433
+ console.log(`
434
+ ${cyan3("towns-bot")} - CLI for creating and managing Towns Protocol bot projects
435
+
436
+ ${yellow3("Usage:")}
437
+ towns-bot <command> [options]
438
+
439
+ ${yellow3("Commands:")}
440
+ ${green2("init")} [project-name] Create a new bot project
441
+ ${green2("update")} Update @towns-protocol dependencies to latest versions
442
+
443
+ ${yellow3("Options:")}
444
+ -t, --template <name> Template to use:
445
+ ${Object.entries(TEMPLATES).map(
446
+ ([key, template]) => ` ${key} - ${template.description}`
447
+ ).join("\n")}
448
+ Default: quickstart
449
+ -h, --help Show this help message
450
+
451
+ ${yellow3("Examples:")}
452
+ ${cyan3("# Create a new bot project with the default template")}
453
+ towns-bot init my-bot
454
+
455
+ ${cyan3("# Create an AI bot project")}
456
+ towns-bot init my-ai-bot --template thread-ai
457
+
458
+ ${cyan3("# Update dependencies in current project")}
459
+ towns-bot update
460
+ `);
461
+ }
462
+ main().catch((error) => {
463
+ console.error(red3("Unexpected error:"), error);
464
+ process.exit(1);
465
+ });
466
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/modules/init.ts","../src/modules/utils.ts","../src/modules/update.ts"],"sourcesContent":["import minimist from 'minimist'\nimport { green, red, yellow, cyan } from 'picocolors'\nimport { init, TEMPLATES, type Template } from './modules/init.js'\nimport { update } from './modules/update.js'\n\nexport type Argv = typeof argv\n\nconst argv = minimist(process.argv.slice(2), {\n string: ['template'],\n boolean: ['help'],\n alias: {\n h: 'help',\n t: 'template',\n },\n})\n\nasync function main() {\n const command = argv._[0]\n\n if (argv.help || !command) {\n showHelp()\n return\n }\n\n try {\n switch (command) {\n case 'init':\n await init(argv)\n break\n case 'update':\n await update(argv)\n break\n default:\n console.error(red(`Unknown command: ${command}`))\n showHelp()\n process.exit(1)\n }\n } catch (error) {\n console.error(red('Error:'), error instanceof Error ? error.message : error)\n process.exit(1)\n }\n}\n\nfunction showHelp() {\n console.log(`\n${cyan('towns-bot')} - CLI for creating and managing Towns Protocol bot projects\n\n${yellow('Usage:')}\n towns-bot <command> [options]\n\n${yellow('Commands:')}\n ${green('init')} [project-name] Create a new bot project\n ${green('update')} Update @towns-protocol dependencies to latest versions\n\n${yellow('Options:')}\n -t, --template <name> Template to use:\n${Object.entries(TEMPLATES)\n .map(\n ([key, template]: [string, Template]) =>\n ` ${key} - ${template.description}`,\n )\n .join('\\n')}\n Default: quickstart\n -h, --help Show this help message\n\n${yellow('Examples:')}\n ${cyan('# Create a new bot project with the default template')}\n towns-bot init my-bot\n\n ${cyan('# Create an AI bot project')}\n towns-bot init my-ai-bot --template thread-ai\n\n ${cyan('# Update dependencies in current project')}\n towns-bot update\n`)\n}\n\nmain().catch((error) => {\n console.error(red('Unexpected error:'), error)\n process.exit(1)\n})\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { default as prompts } from 'prompts'\nimport { red, yellow, cyan } from 'picocolors'\nimport * as jsonc from 'jsonc-parser'\nimport {\n getPackageManager,\n getLatestTownsProtocolVersion,\n cloneTemplate,\n applyReplacements,\n printSuccess,\n type PackageJson,\n} from './utils.js'\nimport type { Argv } from '../index.js'\n\nexport type Template = (typeof TEMPLATES)[keyof typeof TEMPLATES]\nexport const TEMPLATES = {\n quickstart: {\n name: 'Bot Quickstart',\n description: 'Simple starter bot with basic commands',\n packagePath: 'bot-quickstart',\n },\n 'thread-ai': {\n name: 'Thread AI Bot',\n description: 'AI-powered conversational bot using OpenAI',\n packagePath: 'bot-thread-ai',\n },\n poll: {\n name: 'Poll Bot',\n description: 'Interactive poll bot for creating votes',\n packagePath: 'bot-ask-poll',\n },\n} as const\n\nexport async function init(argv: Argv) {\n const projectName = argv._[1]\n const template = argv.template || 'quickstart'\n\n if (!projectName) {\n console.error(red('Error: Please provide a project name'))\n console.log(yellow('Usage: towns-bot init <project-name>'))\n process.exit(1)\n }\n\n if (!TEMPLATES[template as keyof typeof TEMPLATES]) {\n console.error(red(`Error: Unknown template \"${template}\"`))\n console.log(yellow('Available templates:'), Object.keys(TEMPLATES).join(', '))\n process.exit(1)\n }\n\n const targetDir = path.resolve(process.cwd(), projectName)\n\n if (fs.existsSync(targetDir)) {\n const { overwrite } = await prompts({\n type: 'confirm',\n name: 'overwrite',\n message: `Directory ${projectName} already exists. Overwrite?`,\n initial: false,\n })\n\n if (!overwrite) {\n console.log(yellow('Operation cancelled'))\n process.exit(0)\n }\n\n fs.rmSync(targetDir, { recursive: true, force: true })\n }\n\n console.log(cyan(`Creating a new Towns Protocol bot in ${targetDir}`))\n if (template !== 'quickstart') {\n console.log(cyan(`Using template: ${TEMPLATES[template as keyof typeof TEMPLATES].name}`))\n }\n\n const packageManager = getPackageManager()\n const selectedTemplate = TEMPLATES[template as keyof typeof TEMPLATES]\n\n try {\n // Clone template from GitHub\n const success = await cloneTemplate(selectedTemplate.packagePath, targetDir)\n if (!success) {\n console.error(red('Failed to clone template'))\n process.exit(1)\n }\n const latestVersion = await getLatestTownsProtocolVersion()\n // Replace workspace dependencies in package.json and other files\n const replacements = new Map([\n ['workspace:\\\\^', `^${latestVersion}`],\n ['workspace:\\\\*', `^${latestVersion}`],\n ])\n\n // Apply replacements to all relevant files\n applyReplacements(targetDir, replacements)\n\n const packageJsonPath = path.join(targetDir, 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const content = fs.readFileSync(packageJsonPath, 'utf-8')\n const edits = [\n jsonc.modify(content, ['name'], projectName, {}),\n jsonc.modify(content, ['version'], '0.0.1', {}),\n ]\n\n let modifiedContent = jsonc.applyEdits(content, edits.flat())\n\n const parsed = jsonc.parse(modifiedContent) as PackageJson\n delete parsed.private\n\n modifiedContent = JSON.stringify(parsed, null, 2)\n fs.writeFileSync(packageJsonPath, modifiedContent)\n }\n\n printSuccess(projectName, packageManager)\n } catch (error) {\n console.error(red('Error:'), error instanceof Error ? error.message : error)\n console.error(red(`Please delete the directory ${targetDir} and try again.`))\n process.exit(1)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { default as spawn } from 'cross-spawn'\nimport picocolors from 'picocolors'\n\nexport type PackageJson = {\n private?: boolean\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n}\n\nexport const getPackageManager = () => {\n if (process.env.npm_config_user_agent) {\n const agent = process.env.npm_config_user_agent\n if (agent.startsWith('yarn')) return 'yarn'\n if (agent.startsWith('npm')) return 'npm'\n if (agent.startsWith('pnpm')) return 'pnpm'\n if (agent.startsWith('bun')) return 'bun'\n }\n // Default to npm if no user agent is found\n return 'npm'\n}\n\nexport function getInstallCommand(packageManager: string): string {\n switch (packageManager) {\n case 'bun':\n return 'bun install'\n case 'yarn':\n return 'yarn'\n case 'pnpm':\n return 'pnpm install'\n default:\n return 'npm install'\n }\n}\n\nexport function getRunCommand(packageManager: string, script: string): string {\n switch (packageManager) {\n case 'bun':\n return `bun run ${script}`\n case 'yarn':\n return `yarn ${script}`\n case 'pnpm':\n return `pnpm ${script}`\n default:\n return `npm run ${script}`\n }\n}\n\nexport function runCommand(command: string, args: string[], cwd?: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: 'inherit',\n cwd,\n shell: process.platform === 'win32',\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error(`Command failed with exit code ${code}`))\n } else {\n resolve()\n }\n })\n\n child.on('error', reject)\n })\n}\n\nexport async function getLatestTownsProtocolVersion(): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['view', '@towns-protocol/bot', 'version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n\n let output = ''\n child.stdout?.on('data', (data) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n output += data.toString()\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error('Failed to fetch latest @towns-protocol/bot version'))\n } else {\n resolve(output.trim())\n }\n })\n\n child.on('error', reject)\n })\n}\n\nexport function copyDirectory(src: string, dest: string, replacements?: Map<string, string>) {\n if (!fs.existsSync(dest)) {\n fs.mkdirSync(dest, { recursive: true })\n }\n\n const entries = fs.readdirSync(src, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') {\n continue\n }\n copyDirectory(srcPath, destPath, replacements)\n } else {\n let content = fs.readFileSync(srcPath, 'utf-8')\n\n if (\n replacements &&\n (entry.name === 'package.json' ||\n entry.name.endsWith('.ts') ||\n entry.name.endsWith('.js'))\n ) {\n for (const [search, replace] of replacements) {\n content = content.replace(new RegExp(search, 'g'), replace)\n }\n }\n\n fs.writeFileSync(destPath, content)\n }\n }\n}\n\nexport function getLatestSdkTag(): string | null {\n const tagsResult = spawn.sync(\n 'git',\n ['ls-remote', '--tags', 'https://github.com/towns-protocol/towns.git', 'sdk-*'],\n { encoding: 'utf8' },\n )\n\n if (tagsResult.status !== 0 || !tagsResult.stdout) return null\n\n const tags = tagsResult.stdout\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const [_hash, ref] = line.split('\\t')\n const tag = ref.replace('refs/tags/', '').replace(/\\^{}$/, '')\n\n // Extract version numbers from tags like sdk-hash-1.2.3\n const match = tag.match(/^sdk-[0-9a-f]+-(\\d+)\\.(\\d+)\\.(\\d+)$/)\n if (!match) return null\n\n return {\n tag,\n version: [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])],\n }\n })\n .filter(\n (item): item is { tag: string; version: number[] } =>\n item !== null && Array.isArray(item.version) && item.version.length === 3,\n )\n .sort((a, b) => {\n // Compare version numbers\n for (let i = 0; i < 3; i++) {\n if (a.version[i] !== b.version[i]) {\n return b.version[i] - a.version[i]\n }\n }\n return 0\n })\n\n return tags.length > 0 ? tags[0].tag : null\n}\n\nexport async function cloneTemplate(packagePath: string, targetDir: string): Promise<boolean> {\n console.log(picocolors.blue('Cloning template from GitHub...'))\n\n const tempDir = `${targetDir}-temp`\n const fullTemplatePath = `packages/examples/${packagePath}`\n\n // Get latest SDK tag\n const latestSdkTag = getLatestSdkTag()\n if (!latestSdkTag) {\n console.error(picocolors.red('Failed to get latest SDK tag.'))\n return false\n }\n\n // Clone with minimal data to a temporary directory\n const cloneResult = spawn.sync(\n 'git',\n [\n 'clone',\n '--no-checkout',\n '--depth',\n '1',\n '--sparse',\n '--branch',\n latestSdkTag,\n 'https://github.com/towns-protocol/towns.git',\n tempDir,\n ],\n { stdio: 'pipe' },\n )\n if (cloneResult.status !== 0) return false\n\n // Set up sparse checkout for the specific template\n const sparseResult = spawn.sync('git', ['sparse-checkout', 'set', fullTemplatePath], {\n stdio: 'pipe',\n cwd: tempDir,\n })\n if (sparseResult.status !== 0) {\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Checkout the content\n const checkoutResult = spawn.sync('git', ['checkout'], {\n stdio: 'pipe',\n cwd: tempDir,\n })\n if (checkoutResult.status !== 0) {\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Verify template directory exists\n const sourceDir = path.join(tempDir, fullTemplatePath)\n if (!fs.existsSync(sourceDir)) {\n console.error(picocolors.red(`\\nTemplate directory not found at ${sourceDir}`))\n fs.rmSync(tempDir, { recursive: true, force: true })\n return false\n }\n\n // Copy template contents to target directory\n fs.mkdirSync(targetDir, { recursive: true })\n // Use filter to ensure all files (including hidden) are copied\n fs.cpSync(sourceDir, targetDir, {\n recursive: true,\n filter: () => {\n // Copy all files, including hidden ones\n return true\n },\n })\n\n // Clean up temporary directory\n fs.rmSync(tempDir, { recursive: true, force: true })\n\n console.log(picocolors.green('✓'), 'Template cloned successfully!')\n return true\n}\n\nexport function applyReplacements(targetDir: string, replacements: Map<string, string>) {\n function processDirectory(dir: string) {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') {\n continue\n }\n processDirectory(fullPath)\n } else {\n let content = fs.readFileSync(fullPath, 'utf-8')\n let modified = false\n\n if (\n entry.name === 'package.json' ||\n entry.name.endsWith('.ts') ||\n entry.name.endsWith('.js')\n ) {\n for (const [search, replace] of replacements) {\n const regex = new RegExp(search, 'g')\n if (regex.test(content)) {\n content = content.replace(regex, replace)\n modified = true\n }\n }\n\n if (modified) {\n fs.writeFileSync(fullPath, content)\n }\n }\n }\n }\n }\n\n processDirectory(targetDir)\n}\n\nexport function printSuccess(projectName: string, packageManager: string) {\n console.log(picocolors.green('✓'), 'Bot project created successfully!')\n console.log()\n console.log('Next steps:')\n console.log(picocolors.cyan(` cd ${projectName}`))\n console.log(picocolors.cyan(` ${getInstallCommand(packageManager)}`))\n console.log('Set up your environment variables:')\n console.log(picocolors.cyan(' cp .env.sample .env'))\n console.log(' Edit .env with your bot credentials')\n console.log('Start your bot:')\n console.log(picocolors.cyan(` ${getRunCommand(packageManager, 'dev')}`))\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { default as spawn } from 'cross-spawn'\nimport { green, red, yellow, cyan } from 'picocolors'\nimport * as jsonc from 'jsonc-parser'\nimport { getPackageManager, getInstallCommand, runCommand, type PackageJson } from './utils.js'\nimport type { Argv } from '../index.js'\n\ninterface PackageVersions {\n [key: string]: string\n}\n\nexport async function update(_argv: Argv) {\n const packageJsonPath = path.join(process.cwd(), 'package.json')\n\n if (!fs.existsSync(packageJsonPath)) {\n console.error(red('Error: No package.json found in the current directory'))\n console.log(yellow('Please run this command from a Towns Protocol bot project directory'))\n process.exit(1)\n }\n\n const packageJson = jsonc.parse(fs.readFileSync(packageJsonPath, 'utf-8')) as PackageJson\n const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies }\n\n const townsPackages = Object.keys(dependencies).filter((pkg) =>\n pkg.startsWith('@towns-protocol/'),\n )\n\n if (townsPackages.length === 0) {\n console.log(yellow('No @towns-protocol packages found in this project'))\n process.exit(0)\n }\n\n console.log(cyan('Found Towns Protocol packages:'))\n townsPackages.forEach((pkg) => {\n console.log(` - ${pkg}@${dependencies[pkg]}`)\n })\n console.log()\n\n console.log(cyan('Fetching latest versions...'))\n const latestVersions: PackageVersions = {}\n\n for (const pkg of townsPackages) {\n try {\n const version = await getLatestVersion(pkg)\n latestVersions[pkg] = version\n console.log(green('✓'), `${pkg}: ${version}`)\n } catch {\n console.error(red('✗'), `Failed to fetch version for ${pkg}`)\n }\n }\n\n console.log()\n console.log(cyan('Updating package.json...'))\n\n const content = fs.readFileSync(packageJsonPath, 'utf-8')\n const edits: jsonc.Edit[] = []\n\n for (const [pkg, version] of Object.entries(latestVersions)) {\n const currentVersion = dependencies[pkg]\n if (currentVersion !== `^${version}`) {\n if (packageJson.dependencies?.[pkg]) {\n edits.push(...jsonc.modify(content, ['dependencies', pkg], `^${version}`, {}))\n }\n if (packageJson.devDependencies?.[pkg]) {\n edits.push(...jsonc.modify(content, ['devDependencies', pkg], `^${version}`, {}))\n }\n }\n }\n\n if (edits.length > 0) {\n const modifiedContent = jsonc.applyEdits(content, edits)\n fs.writeFileSync(packageJsonPath, modifiedContent)\n console.log(green('✓'), 'Updated package.json')\n\n const packageManager = getPackageManager()\n console.log()\n console.log(cyan(`Installing dependencies with ${packageManager}...`))\n\n try {\n await runCommand(packageManager, [\n getInstallCommand(packageManager).split(' ')[1] || 'install',\n ])\n console.log()\n console.log(green('✓'), 'Dependencies updated successfully!')\n } catch {\n console.error(red('Error:'), 'Failed to install dependencies')\n console.log(\n yellow('Please run'),\n cyan(getInstallCommand(packageManager)),\n yellow('manually'),\n )\n }\n } else {\n console.log(green('✓'), 'All packages are already up to date!')\n }\n}\n\nasync function getLatestVersion(packageName: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const child = spawn('npm', ['view', packageName, 'version'], {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n\n let output = ''\n child.stdout?.on('data', (data) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n output += data.toString()\n })\n\n child.on('close', (code) => {\n if (code !== 0) {\n reject(new Error(`Failed to fetch version for ${packageName}`))\n } else {\n resolve(output.trim())\n }\n })\n\n child.on('error', reject)\n })\n}\n"],"mappings":"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","names":["green","red","yellow","cyan","fs","path","resolve","argv","fs","path","spawn","red","yellow","cyan","jsonc","path","fs","red","yellow","cyan","resolve","spawn","red","cyan","yellow","green"]}
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('./dist/index.js')
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "towns-bot",
3
+ "version": "0.0.266",
4
+ "description": "CLI for creating and managing Towns Protocol bot projects",
5
+ "keywords": [
6
+ "towns",
7
+ "protocol",
8
+ "bot",
9
+ "cli",
10
+ "scaffold"
11
+ ],
12
+ "author": "Towns Protocol",
13
+ "bin": "index.js",
14
+ "engines": {
15
+ "node": "^18.0.0 || >=20.0.0"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "files": [
21
+ "index.js",
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "watch": "tsup --watch",
27
+ "dev": "tsx src/index.ts",
28
+ "lint": "eslint src --ext .ts",
29
+ "lint:fix": "eslint src --ext .ts --fix"
30
+ },
31
+ "devDependencies": {
32
+ "@types/cross-spawn": "^6.0.6",
33
+ "@types/minimist": "^1.2.5",
34
+ "@types/node": "^20.14.8",
35
+ "@types/prompts": "^2.4.9",
36
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
37
+ "@typescript-eslint/parser": "^8.29.0",
38
+ "eslint": "^8.57.1",
39
+ "eslint-import-resolver-typescript": "^4.3.2",
40
+ "eslint-plugin-import-x": "^4.10.2",
41
+ "tsup": "^8.3.5",
42
+ "tsx": "^4.7.1",
43
+ "typescript": "^5.8.2"
44
+ },
45
+ "dependencies": {
46
+ "cross-spawn": "^7.0.5",
47
+ "jsonc-parser": "^3.3.1",
48
+ "minimist": "^1.2.8",
49
+ "picocolors": "^1.1.1",
50
+ "prompts": "^2.4.2"
51
+ },
52
+ "gitHead": "8848d4888253d499e4d0f007c03edfa0982b102b"
53
+ }