baychat 0.13.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/help-topics.js +197 -0
- package/dist/index.js +29 -1
- package/dist/runtimes.js +4 -22
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `baychat help <topic>` — the instructions a PERSON needs, in the terminal.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS FILE EXISTS. The group tools shipped on 2026-08-25 and were written up in
|
|
6
|
+
* five places: the connect guide (served at baychat.io/connect.md), the agent protocol,
|
|
7
|
+
* the npm README, the skill this CLI writes into a client, and the API's own tool
|
|
8
|
+
* descriptions. Every one of those is read by an AGENT, by a stranger evaluating
|
|
9
|
+
* BayChat, or by somebody with a browser open.
|
|
10
|
+
*
|
|
11
|
+
* None of them is reachable from the terminal the person is actually sitting in.
|
|
12
|
+
* `baychat --help` lists CLI SUBCOMMANDS, and `list_groups` is not one — it is an MCP
|
|
13
|
+
* tool their client calls. So the honest answer to "how do I make a group?" was: read a
|
|
14
|
+
* website. That is how a user ends up reporting that a capability does not exist when it
|
|
15
|
+
* shipped weeks ago.
|
|
16
|
+
*
|
|
17
|
+
* ONE SOURCE, NOT A SIXTH COPY. `ROOMS_TOPIC` below is spliced verbatim into the skill
|
|
18
|
+
* `runtimes.ts` writes, so the words a person reads here and the words their agent was
|
|
19
|
+
* given are the same words. A rule written twice is a rule that will one day be true in
|
|
20
|
+
* only one of the two places.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.HELP_TOPICS = exports.ROOMS_TOPIC = void 0;
|
|
24
|
+
exports.findTopic = findTopic;
|
|
25
|
+
exports.topicIndex = topicIndex;
|
|
26
|
+
/**
|
|
27
|
+
* The rooms guidance, shared with the skill in `runtimes.ts`.
|
|
28
|
+
*
|
|
29
|
+
* Kept as a plain string with no template placeholders precisely so it can be used in
|
|
30
|
+
* both places unchanged — the moment it needs interpolation it stops being one text.
|
|
31
|
+
*/
|
|
32
|
+
exports.ROOMS_TOPIC = `## Rooms — find one, or open one
|
|
33
|
+
|
|
34
|
+
\`list_groups\` prints the groups this login is in: the exact title, who is in
|
|
35
|
+
them, and the id. Reach for it whenever a title is uncertain — \`join_session\`
|
|
36
|
+
matches titles exactly and never guesses, so read the title from here and pass it
|
|
37
|
+
back verbatim rather than approximating it.
|
|
38
|
+
|
|
39
|
+
\`create_group\` (\`session\`, \`title\`, optional \`agents\`) opens a new room and
|
|
40
|
+
lands this session in it, with your owner as its admin — exactly as if they had
|
|
41
|
+
made it in the app. \`agents\` takes the exact names \`list_agents\` prints; an
|
|
42
|
+
unknown one is refused with the roster rather than nearest-matched.
|
|
43
|
+
|
|
44
|
+
**Only when the user asked for a new room, and only with the title they gave.**
|
|
45
|
+
That does not weaken the rule above — opening a room is still never your choice.
|
|
46
|
+
In particular, \`create_group\` is **not** how you recover from a join that missed:
|
|
47
|
+
a title that missed is a typo far more often than it is a new room, and creating
|
|
48
|
+
one would fork the conversation in two. Run \`list_groups\`, show the user what is
|
|
49
|
+
really there, and stop.
|
|
50
|
+
|
|
51
|
+
A title that already names one of their groups is refused, and that refusal is
|
|
52
|
+
correct: two rooms sharing one title make either of them impossible to join by
|
|
53
|
+
name until somebody renames one.`;
|
|
54
|
+
const GROUPS = {
|
|
55
|
+
name: "groups",
|
|
56
|
+
summary: "Make a group, or find the ones you are already in",
|
|
57
|
+
keywords: ["group", "groups", "room", "rooms", "create_group", "list_groups", "new group", "channel"],
|
|
58
|
+
body: `${exports.ROOMS_TOPIC}
|
|
59
|
+
|
|
60
|
+
## Where these tools live, and why yours may not have them
|
|
61
|
+
|
|
62
|
+
\`list_groups\` and \`create_group\` are NOT CLI subcommands — you never type them
|
|
63
|
+
into a shell. They are MCP tools your client (Claude Code, Codex, Cursor,
|
|
64
|
+
Desktop) calls on your behalf. You ask in words; the agent makes the call.
|
|
65
|
+
|
|
66
|
+
You: "make a group called Ad Review and put Codex in it"
|
|
67
|
+
→ create_group({ session: "<your session>", title: "Ad Review", agents: ["Codex"] })
|
|
68
|
+
|
|
69
|
+
They are on the SESSION branch only, which means they need a device credential —
|
|
70
|
+
a \`bay_u_\` token from \`baychat login\`. Every call also carries a required
|
|
71
|
+
\`session\` argument, because a terminal has no single agent identity: each call
|
|
72
|
+
names the session it is acting as.
|
|
73
|
+
|
|
74
|
+
**A standing agent gets neither tool, deliberately.** An agent authenticated with
|
|
75
|
+
a \`bay_\` token is a guest in a room somebody else composed. Letting it create
|
|
76
|
+
rooms would let it invent a room, put the agents it likes in it, and talk to them
|
|
77
|
+
unobserved — the escalation the security model exists to prevent. If your agent
|
|
78
|
+
says it cannot create a group, that is correct behaviour, not a bug: ask a person,
|
|
79
|
+
or run it as a session.
|
|
80
|
+
|
|
81
|
+
## If your client cannot see them
|
|
82
|
+
|
|
83
|
+
1. \`baychat login\` — mints the device credential and registers the MCP server.
|
|
84
|
+
Without this you are on the agent branch and the tools are genuinely absent.
|
|
85
|
+
2. Update: \`npx baychat@latest login\`. A client installed before 2026-08-28 was
|
|
86
|
+
written a skill listing ten tools, from a build published on 1 August that
|
|
87
|
+
predates these two entirely.
|
|
88
|
+
3. Restart your client. Tool lists are read once at connect — a running session
|
|
89
|
+
keeps the list it started with, however current the server is.
|
|
90
|
+
4. \`baychat help tools\` shows what each branch actually gets.`,
|
|
91
|
+
};
|
|
92
|
+
const TOOLS = {
|
|
93
|
+
name: "tools",
|
|
94
|
+
summary: "Every MCP tool, and which credential it needs",
|
|
95
|
+
keywords: ["tool", "tools", "mcp", "skills", "capabilities", "what can it do"],
|
|
96
|
+
body: `## The two branches
|
|
97
|
+
|
|
98
|
+
Which tools you get depends on WHAT YOU ARE, not on which client you use.
|
|
99
|
+
|
|
100
|
+
**Agent branch** — a standing agent holding a \`bay_\` token. Thirteen tools:
|
|
101
|
+
|
|
102
|
+
list_conversations get_room_context get_conversation_summary
|
|
103
|
+
get_messages send_message set_typing
|
|
104
|
+
react_to_message list_files get_file
|
|
105
|
+
web_search web_fetch list_agents
|
|
106
|
+
ask_connector
|
|
107
|
+
|
|
108
|
+
Plus the \`baychat://protocol\` resource, which serves the full agent protocol.
|
|
109
|
+
|
|
110
|
+
**Session branch** — a person's terminal, holding a \`bay_u_\` device credential
|
|
111
|
+
from \`baychat login\`. Gets all thirteen above, each with a REQUIRED \`session\`
|
|
112
|
+
argument, and these on top:
|
|
113
|
+
|
|
114
|
+
join_session list_sessions end_session
|
|
115
|
+
list_groups create_group
|
|
116
|
+
request_approval await_approval
|
|
117
|
+
create_upload_url whoami
|
|
118
|
+
|
|
119
|
+
The extra ones are things a PERSON does: name a terminal, park it, see their
|
|
120
|
+
rooms, open a new one, be asked a yes/no question on their phone. An agent token
|
|
121
|
+
never reaches them.
|
|
122
|
+
|
|
123
|
+
If you are counting tools and getting ten, your client is running a build from
|
|
124
|
+
before 2026-08-28 — see \`baychat help groups\`.`,
|
|
125
|
+
};
|
|
126
|
+
const SESSIONS = {
|
|
127
|
+
name: "sessions",
|
|
128
|
+
summary: "Name this terminal, join a room as it, park it when done",
|
|
129
|
+
keywords: ["session", "sessions", "join", "join_session", "attach", "terminal", "park", "end_session"],
|
|
130
|
+
body: `## Sessions
|
|
131
|
+
|
|
132
|
+
A session is one terminal, named by you. It appears in the app as an agent your
|
|
133
|
+
messages can reach, and it survives being parked.
|
|
134
|
+
|
|
135
|
+
join_session({ session: "Session-A" }) → a 1:1 with you
|
|
136
|
+
join_session({ session: "Session-A", group: "Ad Review" }) → that group INSTEAD
|
|
137
|
+
|
|
138
|
+
**The group form joins that group and NOT the 1:1** — this catches people out. A
|
|
139
|
+
message you send in the 1:1 lands somewhere a group-joined session cannot see, so
|
|
140
|
+
it reads as the agent ignoring you.
|
|
141
|
+
|
|
142
|
+
list_sessions() → name, live or idle, last seen
|
|
143
|
+
end_session(...) → park it; the chat and its history survive, and rejoining
|
|
144
|
+
the same name revives the same agent
|
|
145
|
+
|
|
146
|
+
**Never invent a session name.** The user names the session and the user names
|
|
147
|
+
the group. Given neither, run \`list_sessions\` and stop — do not derive a name
|
|
148
|
+
from the directory, the repo, the branch, or the hostname. Answering in the wrong
|
|
149
|
+
room is the worst failure this feature has.`,
|
|
150
|
+
};
|
|
151
|
+
const APPROVALS = {
|
|
152
|
+
name: "approvals",
|
|
153
|
+
summary: "Ask a yes/no question that lands on your phone",
|
|
154
|
+
keywords: ["approval", "approvals", "permission", "request_approval", "await_approval", "decision", "hook"],
|
|
155
|
+
body: `## Approvals
|
|
156
|
+
|
|
157
|
+
\`request_approval\` puts a decision card on the owner's phone; \`await_approval\`
|
|
158
|
+
blocks until they answer. Session branch only — a standing agent has no owner to
|
|
159
|
+
ask and no terminal to block.
|
|
160
|
+
|
|
161
|
+
There is no timeout by design. A question worth asking is worth waiting for, and
|
|
162
|
+
a decision that expires silently is worse than one that waits.
|
|
163
|
+
|
|
164
|
+
\`baychat approve-hook\` wires Claude Code's own permission prompts to the same
|
|
165
|
+
cards. It is NOT on by default and moves the last line between an agent and your
|
|
166
|
+
machine onto a phone — read docs/features/REMOTE_APPROVAL_HOOK.md before enabling
|
|
167
|
+
it. It fails CLOSED: every error denies.`,
|
|
168
|
+
};
|
|
169
|
+
exports.HELP_TOPICS = [GROUPS, SESSIONS, TOOLS, APPROVALS];
|
|
170
|
+
/** Exact name first, then keyword, then a substring of the body. */
|
|
171
|
+
function findTopic(query) {
|
|
172
|
+
const q = query.trim().toLowerCase();
|
|
173
|
+
if (!q)
|
|
174
|
+
return undefined;
|
|
175
|
+
const exact = exports.HELP_TOPICS.find((t) => t.name === q);
|
|
176
|
+
if (exact)
|
|
177
|
+
return exact;
|
|
178
|
+
const keyed = exports.HELP_TOPICS.find((t) => t.keywords.some((k) => k === q));
|
|
179
|
+
if (keyed)
|
|
180
|
+
return keyed;
|
|
181
|
+
// Substring over keywords, so "make a group" and "new room" both land.
|
|
182
|
+
const loose = exports.HELP_TOPICS.find((t) => t.keywords.some((k) => q.includes(k) || k.includes(q)));
|
|
183
|
+
if (loose)
|
|
184
|
+
return loose;
|
|
185
|
+
return exports.HELP_TOPICS.find((t) => t.body.toLowerCase().includes(q));
|
|
186
|
+
}
|
|
187
|
+
/** The index printed by `baychat help` with no topic, and on a miss. */
|
|
188
|
+
function topicIndex() {
|
|
189
|
+
const rows = exports.HELP_TOPICS.map((t) => ` baychat help ${t.name.padEnd(10)} ${t.summary}`);
|
|
190
|
+
return [
|
|
191
|
+
"Topics — how to actually use BayChat from a client:",
|
|
192
|
+
"",
|
|
193
|
+
...rows,
|
|
194
|
+
"",
|
|
195
|
+
"Any wording works: `baychat help \"make a new group\"` finds the groups topic.",
|
|
196
|
+
].join("\n");
|
|
197
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const connect_1 = require("./connect");
|
|
|
7
7
|
const mcp_1 = require("./mcp");
|
|
8
8
|
const mcp_config_1 = require("./mcp-config");
|
|
9
9
|
const commands_2 = require("./relay/commands");
|
|
10
|
+
const help_topics_1 = require("./help-topics");
|
|
10
11
|
const HELP = `baychat — BayChat connector CLI for agent sessions (Claude Code, Codex)
|
|
11
12
|
|
|
12
13
|
Usage:
|
|
@@ -27,6 +28,12 @@ Usage:
|
|
|
27
28
|
baychat pair <code> [--base <url>] Redeem a pairing code from the BayChat app
|
|
28
29
|
baychat link [--name <n>] [--base <url>]
|
|
29
30
|
Link this session via a QR you scan with your phone
|
|
31
|
+
baychat help [topic|question] How to USE BayChat from a client — making a
|
|
32
|
+
group, joining a room, which tools your
|
|
33
|
+
credential gets. Ask it however you like:
|
|
34
|
+
\`baychat help "make a new group"\`. These are
|
|
35
|
+
MCP tools your client calls, not subcommands,
|
|
36
|
+
so they are not in the list below
|
|
30
37
|
baychat whoami Show the connected agent identity
|
|
31
38
|
baychat conversations List conversations this agent is in
|
|
32
39
|
baychat send <conversationId> <text> Send a message
|
|
@@ -288,9 +295,30 @@ async function main() {
|
|
|
288
295
|
}
|
|
289
296
|
case "help":
|
|
290
297
|
case "--help":
|
|
291
|
-
case undefined:
|
|
298
|
+
case undefined: {
|
|
299
|
+
// `baychat help <anything>` answers a question about USING BayChat from a
|
|
300
|
+
// client — how to make a group, what tools you get, why yours are missing.
|
|
301
|
+
// Those are MCP tools, not subcommands, so they can never appear in the
|
|
302
|
+
// usage block above, and until this existed the only answer was "read a
|
|
303
|
+
// website" — which is how a shipped capability gets reported as absent.
|
|
304
|
+
const query = args.join(" ").trim();
|
|
305
|
+
if (query) {
|
|
306
|
+
const topic = (0, help_topics_1.findTopic)(query);
|
|
307
|
+
if (topic) {
|
|
308
|
+
console.log(topic.body);
|
|
309
|
+
return 0;
|
|
310
|
+
}
|
|
311
|
+
// A miss is not an error: they asked a real question and deserve the
|
|
312
|
+
// list rather than a usage dump.
|
|
313
|
+
console.error(`No help topic matches "${query}".\n`);
|
|
314
|
+
console.log((0, help_topics_1.topicIndex)());
|
|
315
|
+
return 1;
|
|
316
|
+
}
|
|
292
317
|
console.log(HELP);
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log((0, help_topics_1.topicIndex)());
|
|
293
320
|
return 0;
|
|
321
|
+
}
|
|
294
322
|
default:
|
|
295
323
|
console.error(`Unknown command: ${command}`);
|
|
296
324
|
console.log(HELP);
|
package/dist/runtimes.js
CHANGED
|
@@ -25,6 +25,9 @@ exports.isRuntime = isRuntime;
|
|
|
25
25
|
exports.runtimeSpec = runtimeSpec;
|
|
26
26
|
exports.commandContextFor = commandContextFor;
|
|
27
27
|
exports.renderCommandFor = renderCommandFor;
|
|
28
|
+
// The rooms guidance is shared with `baychat help groups`, so the words a person
|
|
29
|
+
// reads in their terminal and the words their agent was given are the same words.
|
|
30
|
+
const help_topics_1 = require("./help-topics");
|
|
28
31
|
exports.RUNTIMES = ["claude", "codex", "cursor", "desktop", "pi", "hermes", "generic"];
|
|
29
32
|
const GENERIC_RESUME_NOTE = `The relay can only wake this session while \`attach\` is running. Re-arm it after
|
|
30
33
|
every wake; a message that arrives while nothing is listening is recorded
|
|
@@ -94,28 +97,7 @@ misses; show the list the server returned and stop.
|
|
|
94
97
|
|
|
95
98
|
Answering in the wrong room is the worst failure this feature has.
|
|
96
99
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
\`list_groups\` prints the groups this login is in: the exact title, who is in
|
|
100
|
-
them, and the id. Reach for it whenever a title is uncertain — \`join_session\`
|
|
101
|
-
matches titles exactly and never guesses, so read the title from here and pass it
|
|
102
|
-
back verbatim rather than approximating it.
|
|
103
|
-
|
|
104
|
-
\`create_group\` (\`session\`, \`title\`, optional \`agents\`) opens a new room and
|
|
105
|
-
lands this session in it, with your owner as its admin — exactly as if they had
|
|
106
|
-
made it in the app. \`agents\` takes the exact names \`list_agents\` prints; an
|
|
107
|
-
unknown one is refused with the roster rather than nearest-matched.
|
|
108
|
-
|
|
109
|
-
**Only when the user asked for a new room, and only with the title they gave.**
|
|
110
|
-
That does not weaken the rule above — opening a room is still never your choice.
|
|
111
|
-
In particular, \`create_group\` is **not** how you recover from a join that missed:
|
|
112
|
-
a title that missed is a typo far more often than it is a new room, and creating
|
|
113
|
-
one would fork the conversation in two. Run \`list_groups\`, show the user what is
|
|
114
|
-
really there, and stop.
|
|
115
|
-
|
|
116
|
-
A title that already names one of their groups is refused, and that refusal is
|
|
117
|
-
correct: two rooms sharing one title make either of them impossible to join by
|
|
118
|
-
name until somebody renames one.
|
|
100
|
+
${help_topics_1.ROOMS_TOPIC}
|
|
119
101
|
|
|
120
102
|
## Steps
|
|
121
103
|
|