@stage-labs/metro 0.1.0-beta.202 → 0.1.0-beta.204
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/package.json +1 -1
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +1 -1
- package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +2 -1
- package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +6 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +13 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +8 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +1 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +10 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +1 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +9 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +5 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +1 -0
- package/runtime/runtime.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.204",
|
|
4
4
|
"description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bonustrack",
|
|
@@ -133,6 +133,8 @@ const PRIOR_WORKER: ReadonlySet<string> = new Set(['08a0cd8710df285d6512245246bb
|
|
|
133
133
|
const PRIOR_SKILL: ReadonlySet<string> = new Set([
|
|
134
134
|
'0b3d122ed95beff09d579cf912cd4238e1db524c41fce4b314de57d6ff5908ad',
|
|
135
135
|
'36f4fb57f231a119d717b5e3d6ccb654f94960fcca708683f376679aead8df25',
|
|
136
|
+
'3840bc50253e51f431691376cf29a925b8245d87b77b8b20804a159e378a6e67',
|
|
137
|
+
'e6b59eba825b4568dfa9ace5049fd9568a2e10d731719976ad2657084fd4e5f9',
|
|
136
138
|
]);
|
|
137
139
|
|
|
138
140
|
const digest = (text: string): string => createHash('sha256').update(text).digest('hex');
|
|
@@ -186,9 +186,15 @@ function makeVerbHandler(verb: string, spec: VerbSpec): MessageHandler {
|
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
const handleTyping = async ({ line, ctx }: MessageArgs): Promise<ToolResult> => {
|
|
190
|
+
await ctx.call('typing', { line });
|
|
191
|
+
return ok('typing shown');
|
|
192
|
+
};
|
|
193
|
+
|
|
189
194
|
const MESSAGE_HANDLERS: Record<string, MessageHandler> = {
|
|
190
195
|
send: handleSend,
|
|
191
196
|
read: handleRead,
|
|
197
|
+
typing: handleTyping,
|
|
192
198
|
...Object.fromEntries(
|
|
193
199
|
Object.entries(MESSAGE_VERBS).map(([verb, spec]) => [verb, makeVerbHandler(verb, spec)]),
|
|
194
200
|
),
|
|
@@ -85,6 +85,19 @@ export const COMMON_TOOLS: ToolDef[] = [
|
|
|
85
85
|
required: ['line', 'message_id', 'emoji'],
|
|
86
86
|
},
|
|
87
87
|
},
|
|
88
|
+
{
|
|
89
|
+
name: 'typing',
|
|
90
|
+
group: 'write',
|
|
91
|
+
description:
|
|
92
|
+
'Show "typing…" once in a chat while you prepare an answer. The network clears it by itself after its own time (about 5 s on the Telegram bot, 10 s on Discord, 25 s on WhatsApp) or when you send. Call it again to show it again. Args: line.',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
line: lineProp,
|
|
97
|
+
},
|
|
98
|
+
required: ['line'],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
88
101
|
{
|
|
89
102
|
name: 'unreact',
|
|
90
103
|
group: 'write',
|
|
@@ -92,6 +92,13 @@ function listAccounts(id: string): void {
|
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
async function typing(id: string, args: Record<string, unknown>): Promise<void> {
|
|
96
|
+
const { line, account } = args as { line: string; account?: string };
|
|
97
|
+
const { accountId, channelId } = routeOf(line, account);
|
|
98
|
+
await rest(accountId, 'POST', `/channels/${channelId}/typing`);
|
|
99
|
+
respond(id, { result: { ok: true, account: accountId } });
|
|
100
|
+
}
|
|
101
|
+
|
|
95
102
|
async function react(id: string, args: Record<string, unknown>): Promise<void> {
|
|
96
103
|
const { line, messageId, emoji, account } = args as {
|
|
97
104
|
line: string;
|
|
@@ -198,6 +205,7 @@ const HANDLERS: Record<string, StationHandler> = {
|
|
|
198
205
|
groupRemoveMembers: groupRemoveHandler,
|
|
199
206
|
send,
|
|
200
207
|
react,
|
|
208
|
+
typing,
|
|
201
209
|
edit,
|
|
202
210
|
delete: remove,
|
|
203
211
|
read,
|
|
@@ -157,6 +157,15 @@ async function react(id: string, args: Record<string, unknown>): Promise<void> {
|
|
|
157
157
|
respond(id, { result: { ok: true, account: accountId } });
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
async function typing(id: string, args: Record<string, unknown>): Promise<void> {
|
|
161
|
+
const { line, account } = args as { line: string; account?: string };
|
|
162
|
+
const { accountId, chatId, topicId } = targetOf(line, account);
|
|
163
|
+
const body: Record<string, unknown> = { chat_id: chatId, action: 'typing' };
|
|
164
|
+
if (topicId !== undefined) body.message_thread_id = topicId;
|
|
165
|
+
await tg(accountId, 'sendChatAction', body);
|
|
166
|
+
respond(id, { result: { ok: true, account: accountId } });
|
|
167
|
+
}
|
|
168
|
+
|
|
160
169
|
async function edit(id: string, args: Record<string, unknown>): Promise<void> {
|
|
161
170
|
const { line, messageId, text, account } = args as {
|
|
162
171
|
line: string;
|
|
@@ -217,6 +226,7 @@ const HANDLERS: Record<string, StationHandler> = {
|
|
|
217
226
|
accounts: (id) => listAccounts(id),
|
|
218
227
|
send,
|
|
219
228
|
react,
|
|
229
|
+
typing,
|
|
220
230
|
edit,
|
|
221
231
|
delete: remove,
|
|
222
232
|
listMembers,
|
|
@@ -127,6 +127,14 @@ function makeReact(clientFor: ClientFor): StationHandler {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
function makeTyping(clientFor: ClientFor): StationHandler {
|
|
131
|
+
return async (id, args) => {
|
|
132
|
+
const { accountId, client, jid } = resolve(args, clientFor);
|
|
133
|
+
await guard(() => client.showTyping(jid));
|
|
134
|
+
respond(id, { result: { ok: true, account: accountId } });
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
130
138
|
function makeEdit(clientFor: ClientFor): StationHandler {
|
|
131
139
|
return async (id, args) => {
|
|
132
140
|
const { accountId, client, jid } = resolve(args, clientFor);
|
|
@@ -201,6 +209,7 @@ export function makeHandleCall(
|
|
|
201
209
|
accounts: makeAccounts(clientFor),
|
|
202
210
|
send: makeSend(clientFor),
|
|
203
211
|
react: makeReact(clientFor),
|
|
212
|
+
typing: makeTyping(clientFor),
|
|
204
213
|
edit: makeEdit(clientFor),
|
|
205
214
|
delete: makeDelete(clientFor),
|
|
206
215
|
resolve_sender: makeResolveSender(clientFor),
|
|
@@ -50,6 +50,7 @@ export interface WAClient {
|
|
|
50
50
|
sendText(jid: string, text: string, quotedId?: string): Promise<string>;
|
|
51
51
|
sendMedia(jid: string, media: WAMedia, quotedId?: string): Promise<string>;
|
|
52
52
|
sendReaction(jid: string, messageId: string, emoji: string): Promise<void>;
|
|
53
|
+
showTyping(jid: string): Promise<void>;
|
|
53
54
|
editMessage(jid: string, messageId: string, text: string): Promise<void>;
|
|
54
55
|
deleteMessage(jid: string, messageId: string): Promise<void>;
|
|
55
56
|
reuploadMedia(m: WAMessage): Promise<WAMessage>;
|
|
@@ -339,6 +340,10 @@ export function createClient(account: WhatsAppAccount): WAClient {
|
|
|
339
340
|
quotedId ? quotedOpts(st, jid, quotedId) : undefined,
|
|
340
341
|
);
|
|
341
342
|
},
|
|
343
|
+
async showTyping(jid) {
|
|
344
|
+
const sock = await ready(st);
|
|
345
|
+
await sock.sendPresenceUpdate('composing', jid);
|
|
346
|
+
},
|
|
342
347
|
async sendReaction(jid, messageId, emoji) {
|
|
343
348
|
const target = targetKey(st.keys, jid, messageId, 'react to');
|
|
344
349
|
await send(st, jid, { react: { text: emoji, key: target } });
|
package/runtime/runtime.json
CHANGED