owpenwork 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,7 @@ Quick run without install:
22
22
  npx owpenwork
23
23
  ```
24
24
 
25
- Then follow the prompts (setup, QR login, start).
25
+ Then follow the guided setup (choose what to configure, link WhatsApp, start).
26
26
 
27
27
  1) One-command setup (installs deps, builds, creates `.env` if missing):
28
28
 
@@ -79,17 +79,20 @@ Use a separate WhatsApp number as the bot account so it stays independent from y
79
79
  ## Telegram (Untested)
80
80
 
81
81
  Telegram support is wired but not E2E tested yet. To try it:
82
- - Set `TELEGRAM_BOT_TOKEN`.
83
- - Optionally set `TELEGRAM_ENABLED=true`.
82
+ - Run `owpenwork login telegram --token <token>`.
83
+ - Or set `TELEGRAM_BOT_TOKEN` and `TELEGRAM_ENABLED=true`.
84
84
 
85
85
  ## Commands
86
86
 
87
87
  ```bash
88
88
  owpenwork
89
89
  owpenwork --non-interactive
90
+ owpenwork login whatsapp
91
+ owpenwork login telegram --token <token>
90
92
  owpenwork pairing list
91
93
  owpenwork pairing approve <code>
92
94
  owpenwork status
95
+ owpenwork doctor --reset
93
96
  ```
94
97
 
95
98
  ## Defaults
package/dist/cli.js CHANGED
@@ -1,50 +1,85 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
- import { createInterface } from "node:readline/promises";
4
+ import { cancel, confirm, intro, isCancel, log, multiselect, outro, select, spinner, text, } from "@clack/prompts";
5
5
  import { Command } from "commander";
6
6
  import { startBridge } from "./bridge.js";
7
7
  import { loadConfig, normalizeWhatsAppId, readConfigFile, writeConfigFile, } from "./config.js";
8
8
  import { BridgeStore } from "./db.js";
9
9
  import { createLogger } from "./logger.js";
10
10
  import { loginWhatsApp, unpairWhatsApp } from "./whatsapp.js";
11
- const program = new Command();
12
- program
13
- .name("owpenbot")
14
- .version("0.1.7")
15
- .description("OpenCode WhatsApp + Telegram bridge")
16
- .argument("[path]")
17
- .option("--non-interactive", "Run setup defaults and exit", false)
18
- .option("--check", "Validate config/auth and exit", false);
19
- const runStart = async (pathOverride) => {
20
- if (pathOverride?.trim()) {
21
- process.env.OPENCODE_DIRECTORY = pathOverride.trim();
22
- }
23
- const config = loadConfig();
24
- const logger = createLogger(config.logLevel);
25
- if (!process.env.OPENCODE_DIRECTORY) {
26
- process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
27
- }
28
- const bridge = await startBridge(config, logger);
29
- logger.info("Commands: owpenwork whatsapp login, owpenwork pairing list, owpenwork status");
30
- const shutdown = async () => {
31
- logger.info("shutting down");
32
- await bridge.stop();
11
+ const VERSION = "0.1.8";
12
+ const STEP_OPTIONS = [
13
+ {
14
+ value: "config",
15
+ label: "Setup configuration",
16
+ hint: "DM policy + allowlist",
17
+ },
18
+ {
19
+ value: "whatsapp",
20
+ label: "Link WhatsApp",
21
+ hint: "Scan QR",
22
+ },
23
+ {
24
+ value: "telegram",
25
+ label: "Link Telegram",
26
+ hint: "Optional",
27
+ },
28
+ {
29
+ value: "start",
30
+ label: "Start bridge",
31
+ hint: "Listen for messages",
32
+ },
33
+ ];
34
+ const STEP_SET = new Set(["config", "whatsapp", "telegram", "start"]);
35
+ function isInteractive() {
36
+ return Boolean(process.stdin.isTTY || process.env.OWPENWORK_FORCE_TUI === "1");
37
+ }
38
+ function unwrap(value) {
39
+ if (isCancel(value)) {
40
+ cancel("Setup cancelled");
33
41
  process.exit(0);
34
- };
35
- process.on("SIGINT", shutdown);
36
- process.on("SIGTERM", shutdown);
37
- };
38
- async function runSetupWizard(config, nonInteractive) {
39
- const { config: existing } = readConfigFile(config.configPath);
40
- const next = existing ?? { version: 1 };
41
- if (nonInteractive) {
42
- next.version = 1;
42
+ }
43
+ return value;
44
+ }
45
+ function parseSelections(raw) {
46
+ if (!raw)
47
+ return null;
48
+ const selections = raw
49
+ .split(",")
50
+ .map((item) => item.trim())
51
+ .filter(Boolean)
52
+ .filter((item) => STEP_SET.has(item));
53
+ return selections.length ? selections : [];
54
+ }
55
+ function defaultSelections(configExists, whatsappLinked) {
56
+ const selections = [];
57
+ if (!configExists)
58
+ selections.push("config");
59
+ if (!whatsappLinked)
60
+ selections.push("whatsapp");
61
+ selections.push("start");
62
+ return selections;
63
+ }
64
+ function updateConfig(configPath, updater) {
65
+ const { config } = readConfigFile(configPath);
66
+ const base = config ?? { version: 1 };
67
+ const next = updater(base);
68
+ next.version = next.version ?? 1;
69
+ writeConfigFile(configPath, next);
70
+ return next;
71
+ }
72
+ async function runSetupWizard(config, options) {
73
+ const testMode = process.env.OWPENWORK_TEST_SETUP;
74
+ const next = updateConfig(config.configPath, (cfg) => ({ ...cfg }));
75
+ if (options.nonInteractive || testMode) {
43
76
  next.channels = next.channels ?? {};
77
+ const mode = testMode === "dedicated" ? "dedicated" : "personal";
78
+ const allowFrom = mode === "personal" ? ["+15551234567"] : [];
44
79
  next.channels.whatsapp = {
45
- dmPolicy: "pairing",
46
- allowFrom: [],
47
- selfChatMode: false,
80
+ dmPolicy: mode === "personal" ? "allowlist" : "pairing",
81
+ allowFrom,
82
+ selfChatMode: mode === "personal",
48
83
  accounts: {
49
84
  [config.whatsappAccountId]: {
50
85
  authDir: config.whatsappAuthDir,
@@ -52,67 +87,126 @@ async function runSetupWizard(config, nonInteractive) {
52
87
  },
53
88
  };
54
89
  writeConfigFile(config.configPath, next);
55
- console.log(`Wrote ${config.configPath}`);
90
+ log.success(`Wrote ${config.configPath}`);
56
91
  return;
57
92
  }
58
- const rl = createInterface({ input: process.stdin, output: process.stdout });
59
- const phoneMode = await rl.question("WhatsApp setup: (1) Personal number (2) Dedicated number [1]: ");
60
- const mode = phoneMode.trim() === "2" ? "dedicated" : "personal";
61
- let dmPolicy = "pairing";
62
- let allowFrom = [];
63
- let selfChatMode = false;
64
- if (mode === "personal") {
65
- let normalized = "";
66
- while (!normalized) {
67
- const number = await rl.question("Your WhatsApp number (E.164, e.g. +15551234567): ");
68
- const candidate = normalizeWhatsAppId(number);
69
- if (!/^\+\d+$/.test(candidate)) {
70
- console.log("Invalid number. Try again.");
71
- continue;
93
+ if (options.useTui) {
94
+ const mode = unwrap(await select({
95
+ message: "WhatsApp number",
96
+ options: [
97
+ {
98
+ value: "personal",
99
+ label: "Personal number (no pairing)",
100
+ hint: "Allowlist your own number",
101
+ },
102
+ {
103
+ value: "dedicated",
104
+ label: "Dedicated number",
105
+ hint: "Pairing or allowlist",
106
+ },
107
+ ],
108
+ initialValue: "personal",
109
+ }));
110
+ let dmPolicy = "pairing";
111
+ let allowFrom = [];
112
+ let selfChatMode = false;
113
+ if (mode === "personal") {
114
+ const number = unwrap(await text({
115
+ message: "Your WhatsApp number (E.164)",
116
+ placeholder: "+15551234567",
117
+ validate: (value) => {
118
+ const normalized = normalizeWhatsAppId(String(value ?? ""));
119
+ return /^\+\d+$/.test(normalized) ? undefined : "Use E.164 format (+123...)";
120
+ },
121
+ }));
122
+ allowFrom = [normalizeWhatsAppId(number)];
123
+ dmPolicy = "allowlist";
124
+ selfChatMode = true;
125
+ }
126
+ else {
127
+ dmPolicy = unwrap(await select({
128
+ message: "Direct messages",
129
+ options: [
130
+ { value: "pairing", label: "Pairing (recommended)" },
131
+ { value: "allowlist", label: "Allowlist only" },
132
+ { value: "open", label: "Open (public)" },
133
+ { value: "disabled", label: "Disabled" },
134
+ ],
135
+ initialValue: "pairing",
136
+ }));
137
+ const listInput = unwrap(await text({
138
+ message: "Allowlist numbers (comma-separated, optional)",
139
+ placeholder: "+15551234567, +15551234568",
140
+ }));
141
+ if (listInput.trim()) {
142
+ allowFrom = listInput
143
+ .split(",")
144
+ .map((item) => normalizeWhatsAppId(item))
145
+ .filter(Boolean);
146
+ }
147
+ if (dmPolicy === "open") {
148
+ allowFrom = allowFrom.length ? allowFrom : ["*"];
72
149
  }
73
- normalized = candidate;
74
150
  }
75
- allowFrom = [normalized];
76
- dmPolicy = "allowlist";
77
- selfChatMode = true;
151
+ next.channels = next.channels ?? {};
152
+ next.channels.whatsapp = {
153
+ dmPolicy,
154
+ allowFrom,
155
+ selfChatMode,
156
+ accounts: {
157
+ [config.whatsappAccountId]: {
158
+ authDir: config.whatsappAuthDir,
159
+ },
160
+ },
161
+ };
162
+ writeConfigFile(config.configPath, next);
163
+ log.success(`Wrote ${config.configPath}`);
164
+ return;
78
165
  }
79
- else {
80
- const policyInput = await rl.question("DM policy: (1) Pairing (2) Allowlist (3) Open (4) Disabled [1]: ");
81
- const policyChoice = policyInput.trim();
82
- if (policyChoice === "2")
83
- dmPolicy = "allowlist";
84
- else if (policyChoice === "3")
85
- dmPolicy = "open";
86
- else if (policyChoice === "4")
87
- dmPolicy = "disabled";
88
- else
89
- dmPolicy = "pairing";
90
- const listInput = await rl.question("Allowlist numbers (comma-separated, optional): ");
91
- if (listInput.trim()) {
92
- allowFrom = listInput
93
- .split(",")
94
- .map((item) => normalizeWhatsAppId(item))
95
- .filter(Boolean);
96
- }
97
- if (dmPolicy === "open") {
98
- allowFrom = allowFrom.length ? allowFrom : ["*"];
166
+ }
167
+ async function runTelegramSetup(config, tokenOverride) {
168
+ const tokenFromEnv = tokenOverride ?? process.env.OWPENWORK_TEST_TELEGRAM_TOKEN;
169
+ let token = tokenFromEnv || config.telegramToken;
170
+ if (!token) {
171
+ if (!isInteractive()) {
172
+ log.warn("Telegram token missing. Provide TELEGRAM_BOT_TOKEN or use login command.");
173
+ return;
99
174
  }
175
+ token = unwrap(await text({
176
+ message: "Telegram bot token",
177
+ placeholder: "123456:ABCDEF...",
178
+ validate: (value) => (String(value ?? "").trim() ? undefined : "Token required"),
179
+ }));
100
180
  }
101
- rl.close();
102
- next.version = 1;
103
- next.channels = next.channels ?? {};
104
- next.channels.whatsapp = {
105
- dmPolicy,
106
- allowFrom,
107
- selfChatMode,
108
- accounts: {
109
- [config.whatsappAccountId]: {
110
- authDir: config.whatsappAuthDir,
111
- },
112
- },
181
+ updateConfig(config.configPath, (cfg) => {
182
+ const next = { ...cfg };
183
+ next.channels = next.channels ?? {};
184
+ next.channels.telegram = {
185
+ token,
186
+ enabled: true,
187
+ };
188
+ return next;
189
+ });
190
+ log.success("Telegram token saved.");
191
+ }
192
+ async function runStart(pathOverride) {
193
+ if (pathOverride?.trim()) {
194
+ process.env.OPENCODE_DIRECTORY = pathOverride.trim();
195
+ }
196
+ const config = loadConfig();
197
+ const logger = createLogger(config.logLevel);
198
+ if (!process.env.OPENCODE_DIRECTORY) {
199
+ process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
200
+ }
201
+ const bridge = await startBridge(config, logger);
202
+ logger.info("Commands: owpenwork whatsapp login, owpenwork pairing list, owpenwork status");
203
+ const shutdown = async () => {
204
+ logger.info("shutting down");
205
+ await bridge.stop();
206
+ process.exit(0);
113
207
  };
114
- writeConfigFile(config.configPath, next);
115
- console.log(`Wrote ${config.configPath}`);
208
+ process.on("SIGINT", shutdown);
209
+ process.on("SIGTERM", shutdown);
116
210
  }
117
211
  async function runGuidedFlow(pathArg, opts) {
118
212
  if (pathArg?.trim()) {
@@ -122,30 +216,95 @@ async function runGuidedFlow(pathArg, opts) {
122
216
  if (!process.env.OPENCODE_DIRECTORY) {
123
217
  process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
124
218
  }
219
+ const authPath = path.join(config.whatsappAuthDir, "creds.json");
220
+ const whatsappLinked = fs.existsSync(authPath);
221
+ const configExists = fs.existsSync(config.configPath);
125
222
  if (opts.check) {
126
- const authPath = path.join(config.whatsappAuthDir, "creds.json");
127
- const linked = fs.existsSync(authPath);
128
- const cfgExists = fs.existsSync(config.configPath);
129
- console.log(`Config: ${cfgExists ? "yes" : "no"}`);
130
- console.log(`WhatsApp linked: ${linked ? "yes" : "no"}`);
131
- process.exit(linked && cfgExists ? 0 : 1);
223
+ console.log(`Config: ${configExists ? "yes" : "no"}`);
224
+ console.log(`WhatsApp linked: ${whatsappLinked ? "yes" : "no"}`);
225
+ console.log(`Telegram configured: ${config.telegramToken ? "yes" : "no"}`);
226
+ process.exit(configExists && whatsappLinked ? 0 : 1);
132
227
  }
133
- const cfgExists = fs.existsSync(config.configPath);
134
- const cfgHasWhatsApp = config.configFile.channels?.whatsapp;
135
- if (!cfgExists || !cfgHasWhatsApp) {
136
- await runSetupWizard(config, opts.nonInteractive);
137
- if (opts.nonInteractive) {
138
- console.log("Next: owpenwork whatsapp login");
139
- return;
228
+ if (opts.nonInteractive) {
229
+ await runSetupWizard(config, { nonInteractive: true, useTui: false });
230
+ console.log("Next: owpenwork whatsapp login");
231
+ return;
232
+ }
233
+ if (!isInteractive()) {
234
+ console.log("Non-interactive shell. Run `owpenwork start` or `owpenwork --non-interactive`.");
235
+ return;
236
+ }
237
+ intro("Owpenwork Setup");
238
+ const selectedFromEnv = parseSelections(process.env.OWPENWORK_TEST_SELECTIONS);
239
+ const selections = selectedFromEnv ??
240
+ unwrap(await multiselect({
241
+ message: "Select what to set up",
242
+ options: STEP_OPTIONS,
243
+ initialValues: defaultSelections(configExists, whatsappLinked),
244
+ required: false,
245
+ }));
246
+ const selectedSteps = Array.isArray(selections) ? selections : [];
247
+ if (!selectedSteps.length) {
248
+ cancel("No steps selected");
249
+ process.exit(0);
250
+ }
251
+ const total = selectedSteps.length;
252
+ let index = 1;
253
+ const runStep = async (label, task) => {
254
+ const spin = spinner();
255
+ spin.start(`Step ${index}/${total}: ${label}`);
256
+ await task();
257
+ spin.stop(`Step ${index}/${total}: ${label} done`);
258
+ index += 1;
259
+ };
260
+ for (const step of selectedSteps) {
261
+ if (step === "config") {
262
+ await runStep("Setup configuration", async () => {
263
+ await runSetupWizard(config, { nonInteractive: false, useTui: true });
264
+ config = loadConfig(process.env, { requireOpencode: false });
265
+ });
266
+ continue;
267
+ }
268
+ if (step === "whatsapp") {
269
+ await runStep("Link WhatsApp", async () => {
270
+ const alreadyLinked = fs.existsSync(authPath);
271
+ if (alreadyLinked) {
272
+ const relink = unwrap(await confirm({
273
+ message: "WhatsApp already linked. Relink?",
274
+ initialValue: false,
275
+ }));
276
+ if (!relink)
277
+ return;
278
+ }
279
+ await loginWhatsApp(config, createLogger(config.logLevel));
280
+ });
281
+ continue;
282
+ }
283
+ if (step === "telegram") {
284
+ await runStep("Link Telegram", async () => {
285
+ await runTelegramSetup(config);
286
+ config = loadConfig(process.env, { requireOpencode: false });
287
+ });
288
+ continue;
289
+ }
290
+ if (step === "start") {
291
+ log.info("Starting bridge...");
292
+ outro("Owpenwork is running.");
293
+ await runStart(pathArg);
140
294
  }
141
295
  }
142
- config = loadConfig(process.env, { requireOpencode: false });
143
- const authPath = path.join(config.whatsappAuthDir, "creds.json");
144
- if (!fs.existsSync(authPath)) {
145
- await loginWhatsApp(config, createLogger(config.logLevel));
296
+ if (!selectedSteps.includes("start")) {
297
+ outro("Setup complete.");
146
298
  }
147
- await runStart(pathArg);
148
299
  }
300
+ const program = new Command();
301
+ program
302
+ .name("owpenbot")
303
+ .version(VERSION)
304
+ .description("OpenCode WhatsApp + Telegram bridge")
305
+ .argument("[path]")
306
+ .option("--non-interactive", "Run setup defaults and exit", false)
307
+ .option("--check", "Validate config/auth and exit", false);
149
308
  program
150
309
  .command("start")
151
310
  .description("Start the bridge")
@@ -164,7 +323,29 @@ program
164
323
  .option("--non-interactive", "Write defaults without prompts", false)
165
324
  .action(async (opts) => {
166
325
  const config = loadConfig(process.env, { requireOpencode: false });
167
- await runSetupWizard(config, Boolean(opts.nonInteractive));
326
+ if (!isInteractive() && !opts.nonInteractive) {
327
+ console.log("Non-interactive shell. Use --non-interactive.");
328
+ return;
329
+ }
330
+ intro("Owpenwork Setup");
331
+ await runSetupWizard(config, { nonInteractive: Boolean(opts.nonInteractive), useTui: true });
332
+ outro("Setup complete.");
333
+ });
334
+ const login = program.command("login").description("Link channels");
335
+ login
336
+ .command("whatsapp")
337
+ .description("Login to WhatsApp via QR code")
338
+ .action(async () => {
339
+ const config = loadConfig(process.env, { requireOpencode: false });
340
+ await loginWhatsApp(config, createLogger(config.logLevel));
341
+ });
342
+ login
343
+ .command("telegram")
344
+ .option("--token <token>", "Telegram bot token")
345
+ .description("Save Telegram bot token")
346
+ .action(async (opts) => {
347
+ const config = loadConfig(process.env, { requireOpencode: false });
348
+ await runTelegramSetup(config, opts.token);
168
349
  });
169
350
  program
170
351
  .command("pairing-code")
@@ -190,32 +371,28 @@ whatsapp
190
371
  .description("Login to WhatsApp via QR code")
191
372
  .action(async () => {
192
373
  const config = loadConfig(process.env, { requireOpencode: false });
193
- const logger = createLogger(config.logLevel);
194
- await loginWhatsApp(config, logger);
374
+ await loginWhatsApp(config, createLogger(config.logLevel));
195
375
  });
196
376
  whatsapp
197
377
  .command("logout")
198
378
  .description("Logout of WhatsApp and clear auth state")
199
379
  .action(() => {
200
380
  const config = loadConfig(process.env, { requireOpencode: false });
201
- const logger = createLogger(config.logLevel);
202
- unpairWhatsApp(config, logger);
381
+ unpairWhatsApp(config, createLogger(config.logLevel));
203
382
  });
204
383
  program
205
384
  .command("qr")
206
385
  .description("Print a WhatsApp QR code to pair")
207
386
  .action(async () => {
208
387
  const config = loadConfig(process.env, { requireOpencode: false });
209
- const logger = createLogger(config.logLevel);
210
- await loginWhatsApp(config, logger);
388
+ await loginWhatsApp(config, createLogger(config.logLevel));
211
389
  });
212
390
  program
213
391
  .command("unpair")
214
392
  .description("Clear WhatsApp pairing data")
215
393
  .action(() => {
216
394
  const config = loadConfig(process.env, { requireOpencode: false });
217
- const logger = createLogger(config.logLevel);
218
- unpairWhatsApp(config, logger);
395
+ unpairWhatsApp(config, createLogger(config.logLevel));
219
396
  });
220
397
  const pairing = program.command("pairing").description("Pairing requests");
221
398
  pairing
@@ -273,6 +450,7 @@ program
273
450
  const linked = fs.existsSync(authPath);
274
451
  console.log(`Config: ${config.configPath}`);
275
452
  console.log(`WhatsApp linked: ${linked ? "yes" : "no"}`);
453
+ console.log(`Telegram configured: ${config.telegramToken ? "yes" : "no"}`);
276
454
  console.log(`Auth dir: ${config.whatsappAuthDir}`);
277
455
  console.log(`OpenCode URL: ${config.opencodeUrl}`);
278
456
  });
@@ -296,10 +474,12 @@ program
296
474
  return;
297
475
  let confirmed = resetRequested;
298
476
  if (!resetRequested) {
299
- const rl = createInterface({ input: process.stdin, output: process.stdout });
300
- const answer = await rl.question("Reset owpenbot state (y/N)? ");
301
- rl.close();
302
- confirmed = answer.trim().toLowerCase() === "y";
477
+ const answer = await confirm({ message: "Reset owpenbot state?", initialValue: false });
478
+ if (isCancel(answer)) {
479
+ cancel("Reset cancelled");
480
+ return;
481
+ }
482
+ confirmed = Boolean(answer);
303
483
  }
304
484
  if (!confirmed)
305
485
  return;
@@ -309,7 +489,7 @@ program
309
489
  fs.rmSync(target, { recursive: true, force: true });
310
490
  }
311
491
  }
312
- console.log("Reset complete. Run: owpenwork setup");
492
+ console.log("Reset complete. Run: owpenwork");
313
493
  });
314
494
  program.parseAsync(process.argv).catch((error) => {
315
495
  console.error(error);
package/dist/config.js CHANGED
@@ -141,6 +141,7 @@ export function loadConfig(env = process.env, options = {}) {
141
141
  const whatsappAllowFrom = new Set([...fileAllowFrom, ...envAllowFrom]);
142
142
  const toolOutputLimit = parseInteger(env.TOOL_OUTPUT_LIMIT) ?? 1200;
143
143
  const permissionMode = env.PERMISSION_MODE?.toLowerCase() === "deny" ? "deny" : "allow";
144
+ const telegramToken = env.TELEGRAM_BOT_TOKEN?.trim() || configFile.channels?.telegram?.token || undefined;
144
145
  return {
145
146
  configPath,
146
147
  configFile,
@@ -148,8 +149,8 @@ export function loadConfig(env = process.env, options = {}) {
148
149
  opencodeDirectory: resolvedDirectory,
149
150
  opencodeUsername: env.OPENCODE_SERVER_USERNAME?.trim() || undefined,
150
151
  opencodePassword: env.OPENCODE_SERVER_PASSWORD?.trim() || undefined,
151
- telegramToken: env.TELEGRAM_BOT_TOKEN?.trim() || undefined,
152
- telegramEnabled: parseBoolean(env.TELEGRAM_ENABLED, Boolean(env.TELEGRAM_BOT_TOKEN?.trim())),
152
+ telegramToken,
153
+ telegramEnabled: parseBoolean(env.TELEGRAM_ENABLED, configFile.channels?.telegram?.enabled ?? Boolean(telegramToken)),
153
154
  whatsappAuthDir,
154
155
  whatsappAccountId,
155
156
  whatsappDmPolicy: dmPolicy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owpenwork",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "WhatsApp bridge for a running OpenCode server",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,6 +40,7 @@
40
40
  "test:npx": "node scripts/test-npx.mjs"
41
41
  },
42
42
  "dependencies": {
43
+ "@clack/prompts": "^0.11.0",
43
44
  "@opencode-ai/sdk": "^1.1.19",
44
45
  "@whiskeysockets/baileys": "7.0.0-rc.9",
45
46
  "better-sqlite3": "^11.7.0",