owpenwork 0.1.2 → 0.1.3

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
@@ -19,12 +19,10 @@ npm install -g owpenwork
19
19
  Quick run without install:
20
20
 
21
21
  ```bash
22
- npx owpenwork setup
23
- npx owpenwork whatsapp login
24
- npx owpenwork start
22
+ npx owpenwork
25
23
  ```
26
24
 
27
- Then follow the printed next steps (run `owpenbot setup`, link WhatsApp, start the bridge).
25
+ Then follow the prompts (setup, QR login, start).
28
26
 
29
27
  1) One-command setup (installs deps, builds, creates `.env` if missing):
30
28
 
@@ -43,25 +41,13 @@ Recommended:
43
41
  - `OPENCODE_SERVER_USERNAME`
44
42
  - `OPENCODE_SERVER_PASSWORD`
45
43
 
46
- 3) Run setup (writes `~/.owpenbot/owpenbot.json`):
44
+ 3) Run owpenwork and follow the guided setup:
47
45
 
48
46
  ```bash
49
- owpenwork setup
47
+ owpenwork
50
48
  ```
51
49
 
52
- 4) Link WhatsApp (QR):
53
-
54
- ```bash
55
- owpenwork whatsapp login
56
- ```
57
-
58
- 5) Start the bridge:
59
-
60
- ```bash
61
- owpenwork start
62
- ```
63
-
64
- Owpenbot keeps the WhatsApp session alive once connected.
50
+ Owpenwork keeps the WhatsApp session alive once connected.
65
51
 
66
52
  6) Pair a user with the bot (only if DM policy is pairing):
67
53
 
@@ -75,8 +61,8 @@ Owpenbot keeps the WhatsApp session alive once connected.
75
61
 
76
62
  Use your own WhatsApp account as the bot and test from a second number you control.
77
63
 
78
- 1) Run `owpenwork setup` and choose “personal number.”
79
- 2) Run `owpenwork whatsapp login` to scan the QR.
64
+ 1) Run `owpenwork` and choose “personal number.”
65
+ 2) Scan the QR when prompted.
80
66
  3) Message yourself or from a second number; your number is already allowlisted.
81
67
 
82
68
  Note: WhatsApp’s “message yourself” thread is not reliable for bot testing.
@@ -86,8 +72,8 @@ Note: WhatsApp’s “message yourself” thread is not reliable for bot testing
86
72
  Use a separate WhatsApp number as the bot account so it stays independent from your personal chat history.
87
73
 
88
74
  1) Create a new WhatsApp account for the dedicated number.
89
- 2) Run `owpenwork setup` and choose “dedicated number.”
90
- 3) Run `owpenwork whatsapp login` to scan the QR.
75
+ 2) Run `owpenwork` and choose “dedicated number.”
76
+ 3) Scan the QR when prompted.
91
77
  4) If DM policy is pairing, approve codes with `owpenwork pairing approve <code>`.
92
78
 
93
79
  ## Telegram (Untested)
@@ -99,9 +85,8 @@ Telegram support is wired but not E2E tested yet. To try it:
99
85
  ## Commands
100
86
 
101
87
  ```bash
102
- owpenwork setup
103
- owpenwork whatsapp login
104
- owpenwork start
88
+ owpenwork
89
+ owpenwork --non-interactive
105
90
  owpenwork pairing list
106
91
  owpenwork pairing approve <code>
107
92
  owpenwork status
@@ -110,7 +95,7 @@ owpenwork status
110
95
  ## Defaults
111
96
 
112
97
  - SQLite at `~/.owpenbot/owpenbot.db` unless overridden.
113
- - Config stored at `~/.owpenbot/owpenbot.json` (created by `owpenbot setup`).
98
+ - Config stored at `~/.owpenbot/owpenbot.json` (created by `owpenwork` or `owpenwork setup`).
114
99
  - DM policy defaults to `pairing` unless changed in setup.
115
100
  - Group chats are disabled unless `GROUPS_ENABLED=true`.
116
101
 
@@ -119,4 +104,6 @@ owpenwork status
119
104
  ```bash
120
105
  pnpm -C packages/owpenbot test:unit
121
106
  pnpm -C packages/owpenbot test:smoke
107
+ pnpm -C packages/owpenbot test:cli
108
+ pnpm -C packages/owpenbot test:npx
122
109
  ```
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "node:fs";
3
+ import path from "node:path";
3
4
  import { createInterface } from "node:readline/promises";
4
5
  import { Command } from "commander";
5
6
  import { startBridge } from "./bridge.js";
@@ -11,7 +12,9 @@ const program = new Command();
11
12
  program
12
13
  .name("owpenbot")
13
14
  .description("OpenCode WhatsApp + Telegram bridge")
14
- .argument("[path]");
15
+ .argument("[path]")
16
+ .option("--non-interactive", "Run setup defaults and exit", false)
17
+ .option("--check", "Validate config/auth and exit", false);
15
18
  const runStart = async (pathOverride) => {
16
19
  if (pathOverride?.trim()) {
17
20
  process.env.OPENCODE_DIRECTORY = pathOverride.trim();
@@ -22,7 +25,7 @@ const runStart = async (pathOverride) => {
22
25
  process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
23
26
  }
24
27
  const bridge = await startBridge(config, logger);
25
- logger.info("Commands: owpenbot whatsapp login, owpenbot pairing list, owpenbot status");
28
+ logger.info("Commands: owpenwork whatsapp login, owpenwork pairing list, owpenwork status");
26
29
  const shutdown = async () => {
27
30
  logger.info("shutting down");
28
31
  await bridge.stop();
@@ -31,26 +34,10 @@ const runStart = async (pathOverride) => {
31
34
  process.on("SIGINT", shutdown);
32
35
  process.on("SIGTERM", shutdown);
33
36
  };
34
- program
35
- .command("start")
36
- .description("Start the bridge")
37
- .action(() => runStart());
38
- program.action((pathArg) => {
39
- if (process.argv.includes("--help") || process.argv.includes("-h")) {
40
- program.outputHelp();
41
- return;
42
- }
43
- return runStart(pathArg);
44
- });
45
- program
46
- .command("setup")
47
- .description("Create or update owpenbot.json for WhatsApp")
48
- .option("--non-interactive", "Write defaults without prompts", false)
49
- .action(async (opts) => {
50
- const config = loadConfig(process.env, { requireOpencode: false });
37
+ async function runSetupWizard(config, nonInteractive) {
51
38
  const { config: existing } = readConfigFile(config.configPath);
52
39
  const next = existing ?? { version: 1 };
53
- if (opts.nonInteractive) {
40
+ if (nonInteractive) {
54
41
  next.version = 1;
55
42
  next.channels = next.channels ?? {};
56
43
  next.channels.whatsapp = {
@@ -125,6 +112,58 @@ program
125
112
  };
126
113
  writeConfigFile(config.configPath, next);
127
114
  console.log(`Wrote ${config.configPath}`);
115
+ }
116
+ async function runGuidedFlow(pathArg, opts) {
117
+ if (pathArg?.trim()) {
118
+ process.env.OPENCODE_DIRECTORY = pathArg.trim();
119
+ }
120
+ let config = loadConfig(process.env, { requireOpencode: false });
121
+ if (!process.env.OPENCODE_DIRECTORY) {
122
+ process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
123
+ }
124
+ if (opts.check) {
125
+ const authPath = path.join(config.whatsappAuthDir, "creds.json");
126
+ const linked = fs.existsSync(authPath);
127
+ const cfgExists = fs.existsSync(config.configPath);
128
+ console.log(`Config: ${cfgExists ? "yes" : "no"}`);
129
+ console.log(`WhatsApp linked: ${linked ? "yes" : "no"}`);
130
+ process.exit(linked && cfgExists ? 0 : 1);
131
+ }
132
+ const cfgExists = fs.existsSync(config.configPath);
133
+ const cfgHasWhatsApp = config.configFile.channels?.whatsapp;
134
+ if (!cfgExists || !cfgHasWhatsApp) {
135
+ await runSetupWizard(config, opts.nonInteractive);
136
+ if (opts.nonInteractive) {
137
+ console.log("Next: owpenwork whatsapp login");
138
+ return;
139
+ }
140
+ }
141
+ config = loadConfig(process.env, { requireOpencode: false });
142
+ const authPath = path.join(config.whatsappAuthDir, "creds.json");
143
+ if (!fs.existsSync(authPath)) {
144
+ await loginWhatsApp(config, createLogger(config.logLevel));
145
+ }
146
+ await runStart(pathArg);
147
+ }
148
+ program
149
+ .command("start")
150
+ .description("Start the bridge")
151
+ .action(() => runStart());
152
+ program.action((pathArg) => {
153
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
154
+ program.outputHelp();
155
+ return;
156
+ }
157
+ const opts = program.opts();
158
+ return runGuidedFlow(pathArg, { nonInteractive: Boolean(opts.nonInteractive), check: Boolean(opts.check) });
159
+ });
160
+ program
161
+ .command("setup")
162
+ .description("Create or update owpenbot.json for WhatsApp")
163
+ .option("--non-interactive", "Write defaults without prompts", false)
164
+ .action(async (opts) => {
165
+ const config = loadConfig(process.env, { requireOpencode: false });
166
+ await runSetupWizard(config, Boolean(opts.nonInteractive));
128
167
  });
129
168
  program
130
169
  .command("pairing-code")
package/install.sh CHANGED
@@ -140,9 +140,8 @@ cat <<EOF
140
140
  Owpenbot installed.
141
141
 
142
142
  Next steps:
143
- 1) Run setup: owpenwork setup
144
- 2) Link WhatsApp: owpenwork whatsapp login
145
- 3) Start bridge: owpenwork start
143
+ 1) Run owpenwork: owpenwork
144
+ 2) Follow the guided setup + QR login
146
145
 
147
146
  Owpenbot will print a QR code during login and keep the session alive.
148
147
  EOF
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owpenwork",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "WhatsApp bridge for a running OpenCode server",
5
5
  "private": false,
6
6
  "type": "module",
@@ -35,7 +35,9 @@
35
35
  "typecheck": "tsc -p tsconfig.json --noEmit",
36
36
  "setup": "node scripts/setup.mjs",
37
37
  "test:unit": "pnpm build && node --test test/*.test.js",
38
- "test:smoke": "node scripts/smoke.mjs"
38
+ "test:smoke": "node scripts/smoke.mjs",
39
+ "test:cli": "pnpm build && node scripts/test-cli.mjs",
40
+ "test:npx": "node scripts/test-npx.mjs"
39
41
  },
40
42
  "dependencies": {
41
43
  "@opencode-ai/sdk": "^1.1.19",