@wirecat/whatsapp-cli 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +204 -0
- package/README.md +282 -2
- package/dist/adapter/adapter.d.ts +9 -0
- package/dist/adapter/adapter.d.ts.map +1 -0
- package/dist/adapter/adapter.js +326 -0
- package/dist/adapter/adapter.js.map +1 -0
- package/dist/adapter/checks.d.ts +7 -0
- package/dist/adapter/checks.d.ts.map +1 -0
- package/dist/adapter/checks.js +3 -0
- package/dist/adapter/checks.js.map +1 -0
- package/dist/adapter/errors.d.ts +18 -0
- package/dist/adapter/errors.d.ts.map +1 -0
- package/dist/adapter/errors.js +40 -0
- package/dist/adapter/errors.js.map +1 -0
- package/dist/adapter/format-markdown.d.ts +8 -0
- package/dist/adapter/format-markdown.d.ts.map +1 -0
- package/dist/adapter/format-markdown.js +80 -0
- package/dist/adapter/format-markdown.js.map +1 -0
- package/dist/adapter/groups.d.ts +21 -0
- package/dist/adapter/groups.d.ts.map +1 -0
- package/dist/adapter/groups.js +210 -0
- package/dist/adapter/groups.js.map +1 -0
- package/dist/adapter/map.d.ts +9 -0
- package/dist/adapter/map.d.ts.map +1 -0
- package/dist/adapter/map.js +72 -0
- package/dist/adapter/map.js.map +1 -0
- package/dist/adapter/polls.d.ts +21 -0
- package/dist/adapter/polls.d.ts.map +1 -0
- package/dist/adapter/polls.js +103 -0
- package/dist/adapter/polls.js.map +1 -0
- package/dist/app.d.ts +6 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/wa.d.ts +3 -0
- package/dist/bin/wa.d.ts.map +1 -0
- package/dist/bin/wa.js +27 -0
- package/dist/bin/wa.js.map +1 -0
- package/dist/commands/answer.d.ts +7 -0
- package/dist/commands/answer.d.ts.map +1 -0
- package/dist/commands/answer.js +11 -0
- package/dist/commands/answer.js.map +1 -0
- package/dist/commands/session.d.ts +37 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +202 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +192 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +36 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/diagnose.d.ts +77 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +84 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/engine/contract.d.ts +617 -0
- package/dist/engine/contract.d.ts.map +1 -0
- package/dist/engine/contract.js +186 -0
- package/dist/engine/contract.js.map +1 -0
- package/dist/engine/events.d.ts +9 -0
- package/dist/engine/events.d.ts.map +1 -0
- package/dist/engine/events.js +23 -0
- package/dist/engine/events.js.map +1 -0
- package/dist/engine/go-engine.d.ts +23 -0
- package/dist/engine/go-engine.d.ts.map +1 -0
- package/dist/engine/go-engine.js +238 -0
- package/dist/engine/go-engine.js.map +1 -0
- package/dist/engine/groups.d.ts +159 -0
- package/dist/engine/groups.d.ts.map +1 -0
- package/dist/engine/groups.js +64 -0
- package/dist/engine/groups.js.map +1 -0
- package/dist/engine-binary.d.ts +5 -0
- package/dist/engine-binary.d.ts.map +1 -0
- package/dist/engine-binary.js +18 -0
- package/dist/engine-binary.js.map +1 -0
- package/dist/install/postinstall.d.ts +8 -0
- package/dist/install/postinstall.d.ts.map +1 -0
- package/dist/install/postinstall.js +62 -0
- package/dist/install/postinstall.js.map +1 -0
- package/dist/messenger.d.ts +64 -0
- package/dist/messenger.d.ts.map +1 -0
- package/dist/messenger.js +171 -0
- package/dist/messenger.js.map +1 -0
- package/dist/paths.d.ts +5 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +7 -0
- package/dist/paths.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +114 -0
- package/dist/program.js.map +1 -0
- package/dist/reasons.d.ts +4 -0
- package/dist/reasons.d.ts.map +1 -0
- package/dist/reasons.js +13 -0
- package/dist/reasons.js.map +1 -0
- package/dist/update.d.ts +8 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +26 -0
- package/dist/update.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/install/postinstall.mjs +3 -0
- package/install/windows.ps1 +161 -0
- package/package.json +89 -4
- package/skills/whatsapp-cli/SKILL.md +290 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { chmodSync, existsSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { CliError, indent, singleLine } from "@wirecat/cli-base";
|
|
4
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
5
|
+
import { qrPng, readSecret, terminalQr } from "@wirecat/cli-core";
|
|
6
|
+
import { asFirstWord, commandWords, environmentOf, inputPolicy, messengerContext, REMOTE_WRITE, refuseCommandName, rootOf, } from "@wirecat/cli-core/cli";
|
|
7
|
+
import { Argument, Command } from "commander";
|
|
8
|
+
import { linkDevice, WHATSAPP } from "../messenger.js";
|
|
9
|
+
import { privateStore } from "../paths.js";
|
|
10
|
+
import { printItem } from "./answer.js";
|
|
11
|
+
/** The phone pushes its history right after linking, once; how long to keep receiving it. */
|
|
12
|
+
export const HISTORY_WAIT = { firstMs: 120_000, quietMs: 45_000 };
|
|
13
|
+
/**
|
|
14
|
+
* Saves what the phone pushes until it goes quiet, Ctrl+C, or the caller's signal. Live messages that arrive
|
|
15
|
+
* meanwhile are saved too, through the same connection.
|
|
16
|
+
*/
|
|
17
|
+
const receiveHistory = async (adapter, wait, signal) => {
|
|
18
|
+
const received = { chats: 0, messages: 0, people: 0 };
|
|
19
|
+
const stop = new AbortController();
|
|
20
|
+
const end = () => stop.abort();
|
|
21
|
+
let timer = setTimeout(end, wait.firstMs);
|
|
22
|
+
signal?.addEventListener("abort", end, { once: true });
|
|
23
|
+
try {
|
|
24
|
+
await Promise.all([
|
|
25
|
+
adapter.feed?.((batch) => {
|
|
26
|
+
received.chats += batch.chats?.length ?? 0;
|
|
27
|
+
received.messages += batch.messages?.length ?? 0;
|
|
28
|
+
received.people += batch.people?.length ?? 0;
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
timer = setTimeout(end, wait.quietMs);
|
|
31
|
+
}, stop.signal),
|
|
32
|
+
adapter.watch?.(() => { }, stop.signal),
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
signal?.removeEventListener("abort", end);
|
|
38
|
+
}
|
|
39
|
+
return received;
|
|
40
|
+
};
|
|
41
|
+
// Linking and unlinking change the account without passing cli-core's send guard, so the lock is checked here.
|
|
42
|
+
const refuseUnderReadOnly = (context) => {
|
|
43
|
+
const lock = context.settings.readOnlyLock;
|
|
44
|
+
if (lock)
|
|
45
|
+
throw new CliError("permission_error", `this process is read-only (${lock}) — it cannot link or unlink the device`);
|
|
46
|
+
};
|
|
47
|
+
const linkedText = (profile, account, got) => {
|
|
48
|
+
const word = asFirstWord(profile);
|
|
49
|
+
const name = account.name === null ? "you" : singleLine(account.name);
|
|
50
|
+
return [
|
|
51
|
+
got
|
|
52
|
+
? `Linked as ${name} — profile ${profile}.`
|
|
53
|
+
: `Already linked as ${name} — profile ${profile}; nothing was asked. ` +
|
|
54
|
+
`\`wa ${word}session end\` first to link again.`,
|
|
55
|
+
...(got ? [`History: ${got.chats} chats, ${got.messages} messages kept from the phone.`] : []),
|
|
56
|
+
`Next: wa ${word}chats list · wa ${word}server install to keep receiving`,
|
|
57
|
+
].join("\n");
|
|
58
|
+
};
|
|
59
|
+
/** Links the profile's device unless it is linked already, then keeps the history the phone pushes once. */
|
|
60
|
+
export const startSession = async (command, context, { method, qrFile, command: typed = "wa session start", signal, indent: pad = 0, track }) => {
|
|
61
|
+
const input = context.stdin;
|
|
62
|
+
const terminal = input.isTTY === true && !inputPolicy(input).noInput;
|
|
63
|
+
if (qrFile !== undefined && method !== "qr")
|
|
64
|
+
throw new CliError("validation_error", "--qr-file is for a QR login", { param: "--qr-file" });
|
|
65
|
+
const unanswerable = () => new CliError("validation_error", `${typed} shows a code to scan or type — run it in a terminal, or pass --qr-file`, {
|
|
66
|
+
reason: "input.required",
|
|
67
|
+
});
|
|
68
|
+
// A device that is linked already asks nothing, so only a profile without one is refused before the engine starts.
|
|
69
|
+
if (!terminal && qrFile === undefined && !existsSync(privateStore(context.profile, context.env)))
|
|
70
|
+
throw unanswerable();
|
|
71
|
+
const qrPath = qrFile === undefined ? undefined : resolve(qrFile);
|
|
72
|
+
const environment = environmentOf(command);
|
|
73
|
+
// A cut command never reaches its own finally in time; the image links the account while it is valid.
|
|
74
|
+
if (qrPath)
|
|
75
|
+
environment.trackCloseable?.({ close: async () => rmSync(qrPath, { force: true }) });
|
|
76
|
+
try {
|
|
77
|
+
const linked = await linkDevice(command, context, {
|
|
78
|
+
method,
|
|
79
|
+
...(track ? { track } : {}),
|
|
80
|
+
beforeLink: () => {
|
|
81
|
+
signal?.throwIfAborted();
|
|
82
|
+
refuseUnderReadOnly(context);
|
|
83
|
+
if (!terminal && qrFile === undefined)
|
|
84
|
+
throw unanswerable();
|
|
85
|
+
},
|
|
86
|
+
phone: async () => {
|
|
87
|
+
if (!terminal)
|
|
88
|
+
throw new CliError("validation_error", `${typed} phone needs a terminal to ask for the number`, {
|
|
89
|
+
reason: "input.required",
|
|
90
|
+
});
|
|
91
|
+
return readSecret(`${" ".repeat(pad)}phone number, international format: `, {
|
|
92
|
+
input,
|
|
93
|
+
echo: true,
|
|
94
|
+
...(signal === undefined ? {} : { signal }),
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
onCode: ({ login, code }) => {
|
|
98
|
+
if (login === "pair") {
|
|
99
|
+
context.renderer.note(`pairing code: ${code}\n` +
|
|
100
|
+
"On the phone: tap the WhatsApp notification, or Settings > Linked devices > Link a device >\n" +
|
|
101
|
+
"Link with phone number instead, and type the code. It expires in about two minutes.");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
context.renderer.note("scan in WhatsApp → Settings → Linked devices → Link a device");
|
|
105
|
+
if (!qrPath) {
|
|
106
|
+
context.streams.diagnostic(`\n${indent(terminalQr(code).text, pad + 2)}`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
writeFileSync(qrPath, qrPng(code), { mode: 0o600 });
|
|
110
|
+
chmodSync(qrPath, 0o600);
|
|
111
|
+
context.renderer.note(`the QR code is in ${qrPath} — it is replaced when WhatsApp renews it`);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
if (qrPath)
|
|
115
|
+
rmSync(qrPath, { force: true });
|
|
116
|
+
signal?.throwIfAborted();
|
|
117
|
+
const session = { profile: context.profile, account: linked.account, alreadyLinked: linked.alreadyLinked };
|
|
118
|
+
if (!linked.alreadyLinked) {
|
|
119
|
+
context.renderer.note("receiving history from the phone; keep WhatsApp open on it. Ctrl+C stops — `serve` picks up the rest.");
|
|
120
|
+
const stop = AbortSignal.any([signal, environment.signal].filter((one) => one !== undefined));
|
|
121
|
+
session.received = await context.withMessenger((adapter) => {
|
|
122
|
+
track?.(adapter);
|
|
123
|
+
return receiveHistory(adapter, environment.historyWait ?? HISTORY_WAIT, stop);
|
|
124
|
+
}, { listen: true });
|
|
125
|
+
}
|
|
126
|
+
return session;
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
// The image links the account for as long as it is valid; it does not outlive the login.
|
|
130
|
+
if (qrPath)
|
|
131
|
+
rmSync(qrPath, { force: true });
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const end = async (command) => {
|
|
135
|
+
const context = messengerContext(command, WHATSAPP);
|
|
136
|
+
refuseUnderReadOnly(context);
|
|
137
|
+
// Run by serve for us, the logout would end serve's own connection and the keys would go from under it.
|
|
138
|
+
if (environmentOf(command).relayed)
|
|
139
|
+
throw new CliError("provider_unavailable", `serve holds this WhatsApp login — stop it first (\`wa ${asFirstWord(context.profile)}server stop\`, or Ctrl+C ` +
|
|
140
|
+
"where it runs), then end the session", { reason: "device.in-use", sent: false });
|
|
141
|
+
const store = privateStore(context.profile, context.env);
|
|
142
|
+
if (!existsSync(store)) {
|
|
143
|
+
printItem(context, { profile: context.profile, ended: false });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await context.withMessenger((adapter) => adapter.logout());
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
// The phone may have removed the device already; the keys here are then worth nothing, and still go.
|
|
151
|
+
if (!(error instanceof CliError && error.code === "authentication_error"))
|
|
152
|
+
throw error;
|
|
153
|
+
context.renderer.note("WhatsApp no longer knew this device; removing the keys here");
|
|
154
|
+
}
|
|
155
|
+
for (const suffix of ["", "-wal", "-shm", ".lock"])
|
|
156
|
+
rmSync(`${store}${suffix}`, { force: true });
|
|
157
|
+
printItem(context, { profile: context.profile, ended: true });
|
|
158
|
+
};
|
|
159
|
+
export const sessionCommand = () => {
|
|
160
|
+
// Linking waits for a person, and unlinking removes the owner's device: neither is an agent's call.
|
|
161
|
+
const session = annotate(new Command("session"), { mcp: false }).description("link this profile to WhatsApp as a device, or unlink it");
|
|
162
|
+
annotate(session.command("start"), {
|
|
163
|
+
effects: REMOTE_WRITE,
|
|
164
|
+
lifetime: "interactive",
|
|
165
|
+
examples: ["wa personal session start", "wa personal session start phone"],
|
|
166
|
+
})
|
|
167
|
+
.description("link by QR code (default) or a pairing code, then keep the pushed history")
|
|
168
|
+
.addArgument(new Argument("[method]", "how to link").choices(["qr", "phone"]).default("qr"))
|
|
169
|
+
.option("--qr-file <png>", "write the QR code to this PNG instead of drawing it, for an agent to pass on")
|
|
170
|
+
.addHelpText("after", "\nFirst time? Use `wa personal setup` for linking, a check of five chats and an agent skill.\n" +
|
|
171
|
+
"\nqr: scan the code in WhatsApp > Settings > Linked devices > Link a device.\n" +
|
|
172
|
+
"phone: type your number here, then type the code WhatsApp shows here into the phone.\n" +
|
|
173
|
+
"\nRight after linking, the phone pushes your history once; this command keeps it in the local store\n" +
|
|
174
|
+
"until the phone goes quiet. Then run `wa <profile> server install` to keep receiving.\n" +
|
|
175
|
+
"Agents: --qr-file writes the QR as a PNG (mode 600) and removes it after the login.\n")
|
|
176
|
+
.action(async function (method) {
|
|
177
|
+
const context = messengerContext(this, WHATSAPP);
|
|
178
|
+
refuseCommandName(context.profile, commandWords(rootOf(this)), "wa");
|
|
179
|
+
const { qrFile } = this.opts();
|
|
180
|
+
const session = await startSession(this, context, {
|
|
181
|
+
command: `wa ${asFirstWord(context.profile)}session start`,
|
|
182
|
+
method,
|
|
183
|
+
...(qrFile === undefined ? {} : { qrFile }),
|
|
184
|
+
});
|
|
185
|
+
if (context.format === "pretty")
|
|
186
|
+
context.streams.data(linkedText(context.profile, session.account, session.received));
|
|
187
|
+
else
|
|
188
|
+
printItem(context, {
|
|
189
|
+
profile: session.profile,
|
|
190
|
+
account: session.account,
|
|
191
|
+
already_linked: session.alreadyLinked,
|
|
192
|
+
...(session.received ? { received: session.received } : {}),
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
annotate(session.command("end"), { effects: REMOTE_WRITE, examples: ["wa personal session end"] })
|
|
196
|
+
.description("unlink this device on WhatsApp's side and delete its keys here")
|
|
197
|
+
.action(async function () {
|
|
198
|
+
await end(this);
|
|
199
|
+
});
|
|
200
|
+
return session;
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/commands/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AA+D3C,eAAO,MAAM,YAAY,eA2KnB,CAAA"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { CliError, indent, renderPretty, singleLine } from "@wirecat/cli-base";
|
|
3
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
4
|
+
import { installSkill } from "@wirecat/cli-base/skill";
|
|
5
|
+
import { readSecret } from "@wirecat/cli-core";
|
|
6
|
+
import { asFirstWord, commandWords, environmentOf, inputPolicy, messengerContext, REMOTE_WRITE, refuseCommandName, rootOf, runtime, withDeadline, } from "@wirecat/cli-core/cli";
|
|
7
|
+
import { levelFor } from "@wirecat/cli-core/sends";
|
|
8
|
+
import { Command, Option } from "commander";
|
|
9
|
+
import { WA } from "../app.js";
|
|
10
|
+
import { SKILL, WHATSAPP } from "../messenger.js";
|
|
11
|
+
import { pathsFor, privateStore } from "../paths.js";
|
|
12
|
+
import { installer, PACKAGE } from "../update.js";
|
|
13
|
+
import { printItem } from "./answer.js";
|
|
14
|
+
import { startSession } from "./session.js";
|
|
15
|
+
const AGENTS = ["none", "codex", "cursor", "claude", "gemini", "all"];
|
|
16
|
+
const STEPS = 5;
|
|
17
|
+
const chatCount = (count) => `${count} ${count === 1 ? "chat" : "chats"}`;
|
|
18
|
+
const DETAIL = 6;
|
|
19
|
+
/**
|
|
20
|
+
* A person sees each step as a heading with its details indented under it. `--quiet` hides both, as it
|
|
21
|
+
* hides notes; a machine mode keeps the plain notes it always had, since stderr there is a log.
|
|
22
|
+
*/
|
|
23
|
+
const screenFor = (context, quiet) => {
|
|
24
|
+
const person = context.format === "pretty";
|
|
25
|
+
const say = (text) => {
|
|
26
|
+
if (!quiet)
|
|
27
|
+
context.streams.diagnostic(text);
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
step: (index, title) => person ? say(`\n[${index}/${STEPS}] ${title}`) : context.renderer.note(`${index}/${STEPS} — ${title}`),
|
|
31
|
+
detail: (text) => (person ? say(indent(text, DETAIL)) : context.renderer.note(text)),
|
|
32
|
+
title: (text) => (person ? say(text) : context.renderer.note(text)),
|
|
33
|
+
indent: person ? DETAIL : 0,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const agentFor = async (context, given, pad, signal) => {
|
|
37
|
+
if (given)
|
|
38
|
+
return given;
|
|
39
|
+
if (context.format !== "pretty" || !context.stdin.isTTY || inputPolicy(context.stdin).noInput)
|
|
40
|
+
return "none";
|
|
41
|
+
const answer = (await readSecret(`${" ".repeat(pad)}Agent [codex/cursor/claude/gemini/all/none] (none): `, {
|
|
42
|
+
input: context.stdin,
|
|
43
|
+
echo: true,
|
|
44
|
+
...(signal === undefined ? {} : { signal }),
|
|
45
|
+
}))
|
|
46
|
+
.trim()
|
|
47
|
+
.toLowerCase() || "none";
|
|
48
|
+
const agent = AGENTS.find((known) => known === answer);
|
|
49
|
+
if (agent === undefined)
|
|
50
|
+
throw new CliError("validation_error", `unknown agent — choose ${AGENTS.join(", ")} with --agent`);
|
|
51
|
+
return agent;
|
|
52
|
+
};
|
|
53
|
+
export const setupCommand = () => annotate(new Command("setup"), {
|
|
54
|
+
effects: REMOTE_WRITE,
|
|
55
|
+
lifetime: "interactive",
|
|
56
|
+
mcp: false,
|
|
57
|
+
examples: ["wa personal setup", "wa personal setup --agent codex", "wa personal setup --qr-file login.png --json"],
|
|
58
|
+
})
|
|
59
|
+
.description("set up WhatsApp and connect your agent")
|
|
60
|
+
.configureHelp({ showGlobalOptions: true })
|
|
61
|
+
.addHelpText("after", "\nExamples:\n" +
|
|
62
|
+
" wa personal setup Guided setup of profile personal in your local terminal\n" +
|
|
63
|
+
" wa personal setup --agent codex Install the skill for Codex\n" +
|
|
64
|
+
" wa work setup --agent claude Set up a separate work profile\n" +
|
|
65
|
+
" wa personal setup --method phone Link with a pairing code instead of QR\n" +
|
|
66
|
+
"\nThe first word names the profile; every later command names it too.\n" +
|
|
67
|
+
"\nAllow about 5 minutes: the phone pushes your recent history once, right after linking.\n" +
|
|
68
|
+
"Scan the QR in WhatsApp: Settings > Linked devices > Link a device.\n" +
|
|
69
|
+
"Type your phone number only in the terminal.\n" +
|
|
70
|
+
"\nAgents: read `wa skill show` first. Without a terminal, an agent can use:\n" +
|
|
71
|
+
" wa personal setup --qr-file login.png --agent codex --json\n" +
|
|
72
|
+
"and pass the image on to be scanned. The QR image is removed when linking ends.\n" +
|
|
73
|
+
"Machine mode skips agent installation unless --agent is given.\n" +
|
|
74
|
+
"A device linked before is checked without linking again.\n" +
|
|
75
|
+
"\nSetup reads five chats from the local store. To keep receiving messages:\n" +
|
|
76
|
+
" wa personal server install\n")
|
|
77
|
+
.addOption(new Option("--agent <agent>", "install the skill for this agent; asks at a terminal, otherwise none").choices(AGENTS))
|
|
78
|
+
.addOption(new Option("--method <method>", "how to log in when there is no session").choices(["qr", "phone"]).default("qr"))
|
|
79
|
+
.option("--qr-file <png>", "write a temporary QR image for an agent to pass on; works without a terminal")
|
|
80
|
+
.action(async function () {
|
|
81
|
+
const context = messengerContext(this, WHATSAPP);
|
|
82
|
+
refuseCommandName(context.profile, commandWords(rootOf(this)), "wa");
|
|
83
|
+
const options = this.opts();
|
|
84
|
+
if (context.settings.offline)
|
|
85
|
+
throw new CliError("validation_error", "wa setup verifies WhatsApp — remove --offline");
|
|
86
|
+
if (options.qrFile && options.method !== "qr")
|
|
87
|
+
throw new CliError("validation_error", "--qr-file is for a QR login", { param: "--qr-file" });
|
|
88
|
+
for (const permission of ["account.show", "chats.list"]) {
|
|
89
|
+
if (levelFor(context.settings.permissions, permission).level === "deny")
|
|
90
|
+
throw new CliError("permission_error", `profile ${context.profile} denies ${permission} — setup cannot verify it`, { permission });
|
|
91
|
+
}
|
|
92
|
+
const devicePath = privateStore(context.profile, context.env);
|
|
93
|
+
if (!existsSync(devicePath) && !context.stdin.isTTY && !options.qrFile)
|
|
94
|
+
throw new CliError("validation_error", "wa setup needs a terminal to link a device — run it locally, or pass --qr-file for an agent", { reason: "input.required" });
|
|
95
|
+
const prefix = `wa ${asFirstWord(context.profile)}`;
|
|
96
|
+
const command = installer(environmentOf(this).update) === "npx"
|
|
97
|
+
? `npm${process.platform === "win32" ? ".cmd" : ""} exec --yes --package=${PACKAGE} -- ${prefix}`
|
|
98
|
+
: prefix;
|
|
99
|
+
const cancellation = new AbortController();
|
|
100
|
+
const closeables = [
|
|
101
|
+
{
|
|
102
|
+
close: async () => {
|
|
103
|
+
cancellation.abort();
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
const track = (closeable) => {
|
|
108
|
+
closeables.push(closeable);
|
|
109
|
+
};
|
|
110
|
+
const screen = screenFor(context, this.optsWithGlobals().quiet === true);
|
|
111
|
+
const linkContext = { ...context, renderer: { ...context.renderer, note: screen.detail } };
|
|
112
|
+
const answer = await withDeadline(context.settings.commandTimeoutMs, closeables, async () => {
|
|
113
|
+
screen.title(`WhatsApp setup — profile ${context.profile}. Allow about 5 minutes; the phone sends recent history once.`);
|
|
114
|
+
screen.step(1, "This computer");
|
|
115
|
+
const paths = pathsFor(context.env);
|
|
116
|
+
for (const path of [paths.config, paths.state, paths.cache]) {
|
|
117
|
+
mkdirSync(path, { recursive: true });
|
|
118
|
+
accessSync(path, constants.W_OK);
|
|
119
|
+
}
|
|
120
|
+
screen.detail("✓ local directories ready");
|
|
121
|
+
if (process.platform === "win32")
|
|
122
|
+
screen.detail("Windows: use wa.cmd or npm.cmd if PowerShell blocks scripts. Open a new terminal after installing Node.js.");
|
|
123
|
+
screen.step(2, existsSync(devicePath) ? "Link" : "Link: scan the QR code or type the pairing code");
|
|
124
|
+
const session = await startSession(this, linkContext, {
|
|
125
|
+
signal: cancellation.signal,
|
|
126
|
+
method: options.method,
|
|
127
|
+
...(options.qrFile === undefined ? {} : { qrFile: options.qrFile }),
|
|
128
|
+
command: `${prefix}setup`,
|
|
129
|
+
indent: screen.indent,
|
|
130
|
+
track,
|
|
131
|
+
});
|
|
132
|
+
const reused = session.alreadyLinked;
|
|
133
|
+
const history = session.received;
|
|
134
|
+
screen.detail(history
|
|
135
|
+
? `✓ linked; ${chatCount(history.chats)} and ${history.messages} messages kept from the phone`
|
|
136
|
+
: "✓ existing device, no new link");
|
|
137
|
+
screen.step(3, "Account");
|
|
138
|
+
const account = await context.withMessenger(async (adapter) => {
|
|
139
|
+
track(adapter);
|
|
140
|
+
cancellation.signal.throwIfAborted();
|
|
141
|
+
return adapter.me();
|
|
142
|
+
});
|
|
143
|
+
screen.detail(`✓ ${account.name === null ? "verified" : singleLine(account.name)}`);
|
|
144
|
+
screen.step(4, "A few chats");
|
|
145
|
+
// WhatsApp has no chat list to ask for: the store holds what the phone pushed and what serve received.
|
|
146
|
+
const chats = await context.withStore((store, key) => store.forAccount(key).chats.chats({ limit: 5, offset: 0 }));
|
|
147
|
+
screen.detail(`✓ ${chatCount(chats.items.length)} read from the local store`);
|
|
148
|
+
if (chats.items.length === 0)
|
|
149
|
+
screen.detail(`nothing kept yet — \`${command}server install\` starts receiving`);
|
|
150
|
+
screen.step(5, "Agent");
|
|
151
|
+
const agent = await agentFor(context, options.agent, screen.indent, cancellation.signal);
|
|
152
|
+
screen.detail(agent === "none" ? "✓ no agent skill installed" : `✓ ${agent}`);
|
|
153
|
+
const targets = agent === "all" ? ["claude", "agents"] : [agent === "claude" ? "claude" : "agents"];
|
|
154
|
+
cancellation.signal.throwIfAborted();
|
|
155
|
+
const written = agent === "none" ? [] : installSkill(WA, SKILL, { targets, env: context.env });
|
|
156
|
+
const next = {
|
|
157
|
+
instructions: `${command}skill show`,
|
|
158
|
+
inbox: `${command}inbox --limit 5`,
|
|
159
|
+
chats: `${command}chats list --limit 5`,
|
|
160
|
+
receive: `${command}server install`,
|
|
161
|
+
history_status: `${command}store status`,
|
|
162
|
+
...(agent === "none" ? { skill: `${command}skill install`, mcp: `${command}mcp config` } : {}),
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
profile: context.profile,
|
|
166
|
+
runtime: runtime(),
|
|
167
|
+
paths,
|
|
168
|
+
device: { path: devicePath, reused },
|
|
169
|
+
account: { id: account.id, name: account.name },
|
|
170
|
+
...(history ? { history } : {}),
|
|
171
|
+
chats: { checked: chats.items.length, has_more: chats.hasMore },
|
|
172
|
+
agent: { name: agent, written },
|
|
173
|
+
next,
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
const { agent, next, chats } = answer;
|
|
177
|
+
if (context.format !== "pretty")
|
|
178
|
+
printItem(context, answer);
|
|
179
|
+
else {
|
|
180
|
+
const rows = {
|
|
181
|
+
"Try now": next.inbox,
|
|
182
|
+
"Keep receiving": `${next.receive} (a background server saves new messages)`,
|
|
183
|
+
"Agent skill": agent.name === "none"
|
|
184
|
+
? `skipped — install later: ${next.skill}`
|
|
185
|
+
: `installed for ${agent.name}; start a new agent session if it is not found`,
|
|
186
|
+
"For an agent": next.instructions,
|
|
187
|
+
};
|
|
188
|
+
context.streams.data(`\n✓ WhatsApp is ready — profile ${context.profile}, ${chatCount(chats.checked)} checked\n\n` +
|
|
189
|
+
indent(renderPretty(rows, { color: context.color }), 2));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,cAAc,mCAexB,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
2
|
+
import { environmentOf, outputFor, servingProfiles, upgradeCommand as sharedUpgradeCommand, usableProfileName, } from "@wirecat/cli-core/cli";
|
|
3
|
+
import { WA } from "../app.js";
|
|
4
|
+
import { installer, latest, PACKAGE, restartServer, runUpdate } from "../update.js";
|
|
5
|
+
export const upgradeCommand = () => annotate(sharedUpgradeCommand(WA, PACKAGE, (command) => {
|
|
6
|
+
const context = environmentOf(command);
|
|
7
|
+
const environment = context.update ?? {};
|
|
8
|
+
const env = context.env ?? process.env;
|
|
9
|
+
return {
|
|
10
|
+
...outputFor(command),
|
|
11
|
+
installer: () => installer(environment),
|
|
12
|
+
latest: () => latest(environment),
|
|
13
|
+
install: (argv) => runUpdate(argv, environment),
|
|
14
|
+
afterUpdate: () => restartServers(env, environment),
|
|
15
|
+
};
|
|
16
|
+
}), { examples: ["wa upgrade --check", "wa upgrade"] });
|
|
17
|
+
/**
|
|
18
|
+
* A running serve keeps the code it started with; the update replaced the files under it. Each is
|
|
19
|
+
* restarted by the new wa — `server restart` refuses a serve started by hand, which is then named.
|
|
20
|
+
*/
|
|
21
|
+
const restartServers = (env, environment) => {
|
|
22
|
+
const restarted = [];
|
|
23
|
+
const left = [];
|
|
24
|
+
for (const profile of servingProfiles(WA, env)) {
|
|
25
|
+
try {
|
|
26
|
+
usableProfileName(profile);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const code = restartServer(profile, env, environment);
|
|
32
|
+
(code === 0 ? restarted : left).push(profile);
|
|
33
|
+
}
|
|
34
|
+
return { restarted, left };
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AACrD,OAAO,EACL,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,IAAI,oBAAoB,EACtC,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAE9B,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAA0B,MAAM,cAAc,CAAA;AAE3G,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CACjC,QAAQ,CACN,oBAAoB,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;IAC5C,MAAM,OAAO,GAAG,aAAa,CAAc,OAAO,CAAC,CAAA;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAA;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;IACtC,OAAO;QACL,GAAG,SAAS,CAAC,OAAO,CAAC;QACrB,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC;QACvC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;QACjC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC;QAC/C,WAAW,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC;KACpD,CAAA;AACH,CAAC,CAAC,EACF,EAAE,QAAQ,EAAE,CAAC,oBAAoB,EAAE,YAAY,CAAC,EAAE,CACnD,CAAA;AAEH;;;GAGG;AACH,MAAM,cAAc,GAAG,CAAC,GAAsB,EAAE,WAA8B,EAAE,EAAE;IAChF,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,KAAK,MAAM,OAAO,IAAI,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,iBAAiB,CAAC,OAAO,CAAC,CAAA;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,CAAC,CACpD;QAAA,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;AAC5B,CAAC,CAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type UpdateEnvironment } from "./update.js";
|
|
2
|
+
/** Whether the engine binary is there to start — never started here. */
|
|
3
|
+
export declare const engineState: (env: NodeJS.ProcessEnv, update?: UpdateEnvironment) => {
|
|
4
|
+
path: string;
|
|
5
|
+
found: boolean;
|
|
6
|
+
hint?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
path: string;
|
|
9
|
+
found: boolean;
|
|
10
|
+
hint: string;
|
|
11
|
+
};
|
|
12
|
+
/** The device keys' file modes, from `stat` alone: the keys are a credential and are never opened here. */
|
|
13
|
+
export declare const deviceModes: (storePath: string, platform?: NodeJS.Platform) => {
|
|
14
|
+
checked: boolean;
|
|
15
|
+
reason: string;
|
|
16
|
+
ok?: undefined;
|
|
17
|
+
problems?: undefined;
|
|
18
|
+
} | {
|
|
19
|
+
reason?: undefined;
|
|
20
|
+
checked: boolean;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
problems: {
|
|
23
|
+
path: string;
|
|
24
|
+
mode: string;
|
|
25
|
+
want: string;
|
|
26
|
+
fix: string;
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Who last held the device's lock, from the name the engine writes into it. The engine never clears that name, so
|
|
31
|
+
* the holder counts as running only while a process with its pid is.
|
|
32
|
+
*/
|
|
33
|
+
export declare const lockState: (lockPath: string) => {
|
|
34
|
+
path: string;
|
|
35
|
+
holder: string | null;
|
|
36
|
+
pid: number | null;
|
|
37
|
+
running: boolean;
|
|
38
|
+
};
|
|
39
|
+
/** `doctor`'s WhatsApp block: the engine, the device keys and the lock, read from disk without starting anything. */
|
|
40
|
+
export declare const diagnoseWhatsApp: (profile: string, env: NodeJS.ProcessEnv, update?: UpdateEnvironment) => {
|
|
41
|
+
engine: {
|
|
42
|
+
path: string;
|
|
43
|
+
found: boolean;
|
|
44
|
+
hint?: undefined;
|
|
45
|
+
} | {
|
|
46
|
+
path: string;
|
|
47
|
+
found: boolean;
|
|
48
|
+
hint: string;
|
|
49
|
+
};
|
|
50
|
+
device: {
|
|
51
|
+
path: string;
|
|
52
|
+
exists: boolean;
|
|
53
|
+
files: {
|
|
54
|
+
checked: boolean;
|
|
55
|
+
reason: string;
|
|
56
|
+
ok?: undefined;
|
|
57
|
+
problems?: undefined;
|
|
58
|
+
} | {
|
|
59
|
+
reason?: undefined;
|
|
60
|
+
checked: boolean;
|
|
61
|
+
ok: boolean;
|
|
62
|
+
problems: {
|
|
63
|
+
path: string;
|
|
64
|
+
mode: string;
|
|
65
|
+
want: string;
|
|
66
|
+
fix: string;
|
|
67
|
+
}[];
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
lock: {
|
|
71
|
+
path: string;
|
|
72
|
+
holder: string | null;
|
|
73
|
+
pid: number | null;
|
|
74
|
+
running: boolean;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../src/diagnose.ts"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAI/D,wEAAwE;AACxE,eAAO,MAAM,WAAW,QAAS,MAAM,CAAC,UAAU,WAAU,iBAAiB;;;;;;;;CAY5E,CAAA;AAED,2GAA2G;AAC3G,eAAO,MAAM,WAAW,cAAe,MAAM,aAAY,MAAM,CAAC,QAAQ;;;;;;;;;;;;;;;CAoBvE,CAAA;AAWD;;;GAGG;AACH,eAAO,MAAM,SAAS,aAAc,MAAM;;;;;CAazC,CAAA;AAED,qHAAqH;AACrH,eAAO,MAAM,gBAAgB,YAAa,MAAM,OAAO,MAAM,CAAC,UAAU,WAAW,iBAAiB;IAGhG,MAAM;;;;;;;;;IACN,MAAM;QAAI,IAAI;QAAS,MAAM;QAAqB,KAAK;;;;;;;;;;;;;;;;;IACvD,IAAI;;;;;;CAEP,CAAA"}
|