@stage-labs/metro 0.1.0-beta.201 → 0.1.0-beta.202
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/claude.js +4 -15
- package/dist/cli.js +5 -3
- package/dist/hold.js +1 -2
- package/dist/runtime-install.js +4 -5
- package/dist/runtime.js +1 -4
- package/dist/serve.js +4 -5
- package/dist/service.js +82 -21
- package/dist/update.js +1 -1
- package/package.json +2 -2
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +1 -1
- package/runtime/node_modules/@metro-labs/core/src/events.ts +4 -2
- package/runtime/node_modules/@metro-labs/core/src/lines.ts +12 -25
- package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +45 -22
- package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +0 -1
- package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +8 -80
- package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +3 -5
- package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +4 -9
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +9 -39
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +9 -28
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +0 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +8 -116
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +11 -35
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +7 -9
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +3 -29
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +5 -8
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +5 -8
- package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +3 -6
- package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +25 -3
- package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +2 -3
- package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +6 -56
- package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +7 -6
- package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +7 -7
- package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +4 -4
- package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +2 -4
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +19 -22
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +1 -2
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +6 -8
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +3 -6
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +2 -3
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +28 -1
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +4 -4
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +3 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +6 -6
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +7 -7
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +3 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +10 -31
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +1 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +5 -6
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +1 -4
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +3 -8
- package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +6 -7
- package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +5 -44
- package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +4 -4
- package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +6 -7
- package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +12 -13
- package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +5 -22
- package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +1 -19
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +7 -35
- package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +5 -10
- package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
- package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +1 -2
- package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +1 -1
- package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +11 -12
- package/runtime/node_modules/@metro-labs/http/src/api-http.ts +2 -5
- package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +0 -1
- package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +1 -15
- package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +0 -6
- package/runtime/node_modules/@metro-labs/outlook/src/format.ts +0 -1
- package/runtime/node_modules/@metro-labs/outlook/src/state.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +4 -22
- package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +2 -2
- package/runtime/node_modules/@metro-labs/telegram/src/format.ts +1 -3
- package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +1 -2
- package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +4 -37
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +7 -23
- package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +1 -4
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +4 -9
- package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +3 -3
- package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +0 -11
- package/runtime/node_modules/@metro-labs/threema/src/actions.ts +2 -12
- package/runtime/node_modules/@metro-labs/threema/src/files.ts +4 -15
- package/runtime/node_modules/@metro-labs/threema/src/format.ts +2 -7
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -2
- package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +5 -26
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +5 -6
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +1 -3
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +1 -12
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +14 -5
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +31 -78
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +3 -4
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +1 -6
- package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +2 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +0 -2
- package/runtime/runtime.json +1 -1
- package/runtime/node_modules/@metro-labs/core/src/identity.ts +0 -7
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/needs.ts +0 -2
- package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +0 -12
- package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +0 -13
- package/runtime/node_modules/@metro-labs/daemon/src/channels/reply-id.ts +0 -1
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +0 -29
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/api.ts +0 -43
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/move.ts +0 -165
- package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -1
- package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WAMessage } from 'baileys';
|
|
2
|
-
import { emit } from '
|
|
2
|
+
import { emit } from '@metro-labs/core/stations/station-runtime';
|
|
3
3
|
import { reportAttachment } from '@metro-labs/core/stations/train-events';
|
|
4
4
|
import { lineOf } from './accounts.js';
|
|
5
5
|
import {
|
|
@@ -15,10 +15,6 @@ import {
|
|
|
15
15
|
} from '@metro-labs/core/stations/account-store';
|
|
16
16
|
import { Line } from '@metro-labs/core/lines';
|
|
17
17
|
|
|
18
|
-
const ACCOUNTS_FILE =
|
|
19
|
-
process.env.XMTP_ACCOUNTS_FILE ??
|
|
20
|
-
join(homedir(), '.metro', 'xmtp-accounts.json');
|
|
21
|
-
|
|
22
18
|
export interface AccountConfig {
|
|
23
19
|
id: string;
|
|
24
20
|
privateKey?: string;
|
|
@@ -28,15 +24,8 @@ export interface AccountConfig {
|
|
|
28
24
|
|
|
29
25
|
export const { loadAccounts } = makeAccountStore<AccountConfig>({
|
|
30
26
|
prefix: 'xmtp',
|
|
31
|
-
file: ACCOUNTS_FILE,
|
|
32
27
|
validate(raw, die) {
|
|
33
|
-
const
|
|
34
|
-
for (const a of raw) {
|
|
35
|
-
if (!a.id) die('account missing id');
|
|
36
|
-
if (!a.privateKey) die(`account '${a.id}' needs a privateKey`);
|
|
37
|
-
if (seen.has(a.id)) die(`duplicate account id '${a.id}'`);
|
|
38
|
-
seen.add(a.id);
|
|
39
|
-
}
|
|
28
|
+
for (const a of raw) if (!a.privateKey) die(`account '${a.id}' needs a privateKey`);
|
|
40
29
|
},
|
|
41
30
|
});
|
|
42
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errMsg } from '@metro-labs/core/log';
|
|
2
2
|
import { accountForCall, convOf, lineOf, type Account } from './accounts.js';
|
|
3
|
-
import { respond } from '
|
|
3
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
4
4
|
import type { GroupLike } from './labels.js';
|
|
5
5
|
|
|
6
6
|
type Args = Record<string, unknown>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IdentifierKind } from '@xmtp/node-sdk';
|
|
2
2
|
import { accountForCall, convOf, lineOf, parseLine } from './accounts.js';
|
|
3
|
-
import { respond } from '
|
|
3
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
4
|
+
import { resolveMsgId } from './wire.js';
|
|
4
5
|
import { TrainError } from '@metro-labs/core/train-error';
|
|
5
6
|
import {
|
|
6
7
|
buildGroupInfo,
|
|
@@ -33,15 +34,23 @@ async function newDm(id: string, args: Args): Promise<void> {
|
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
function upTo<T extends { id: string }>(all: T[], before: string | undefined): T[] {
|
|
38
|
+
if (!before) return all;
|
|
39
|
+
const target = resolveMsgId(before);
|
|
40
|
+
const at = all.findIndex((m) => m.id === target);
|
|
41
|
+
if (at < 0) throw new TrainError('NOT_FOUND', `message ${before} is not in this conversation`);
|
|
42
|
+
return all.slice(0, at);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function read(id: string, args: Args): Promise<void> {
|
|
46
|
+
const { line, limit, before } = args as { line: string; limit?: number; before?: string };
|
|
38
47
|
const { conv } = await convOf(line);
|
|
39
48
|
if (!conv)
|
|
40
49
|
throw new TrainError('NOT_FOUND', `conversation not found for ${line}`);
|
|
41
50
|
const lim = Math.min(Math.max(1, limit ?? 20), 200);
|
|
42
51
|
await conv.sync().catch(() => undefined);
|
|
43
52
|
const all = await conv.messages();
|
|
44
|
-
const slice = all.slice(-lim);
|
|
53
|
+
const slice = upTo(all, before).slice(-lim);
|
|
45
54
|
const parsed = parseLine(line);
|
|
46
55
|
if (!parsed)
|
|
47
56
|
throw new TrainError('NOT_FOUND', `could not parse line ${line}`);
|
|
@@ -86,7 +95,7 @@ export const convHandlers: Record<string, Handler> = {
|
|
|
86
95
|
newDm,
|
|
87
96
|
updateChannelMeta,
|
|
88
97
|
closeGroup,
|
|
89
|
-
|
|
98
|
+
read,
|
|
90
99
|
groupInfo,
|
|
91
100
|
listMembers,
|
|
92
101
|
groupCreate: async (id, args) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { accountForCall, convOf, lineOf } from './accounts.js';
|
|
2
|
-
import { respond } from '
|
|
2
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
3
3
|
import { warmGroupName } from './conv-helpers.js';
|
|
4
4
|
import { mergeAppData, readAppData, type GroupLike } from './labels.js';
|
|
5
5
|
import { TrainError } from '@metro-labs/core/train-error';
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { ReactionAction, ReactionSchema } from '@xmtp/node-sdk';
|
|
1
|
+
import { ReactionAction, ReactionSchema, type Conversation } from '@xmtp/node-sdk';
|
|
2
2
|
import type { Reply } from '@xmtp/node-bindings';
|
|
3
3
|
import {
|
|
4
4
|
AttachmentCodec,
|
|
5
5
|
type Attachment,
|
|
6
6
|
} from '@xmtp/content-type-remote-attachment';
|
|
7
7
|
import { convOf } from './accounts.js';
|
|
8
|
-
import { resolveMsgId
|
|
8
|
+
import { resolveMsgId } from './wire.js';
|
|
9
9
|
import { emitOutbound } from './emit.js';
|
|
10
10
|
import { PollCodec, buildPollContent } from './codecs.js';
|
|
11
11
|
import { convHandlers } from './actions-conv.js';
|
|
12
|
-
import {
|
|
12
|
+
import { messagingAliases } from '@metro-labs/core/stations/messaging-normalize';
|
|
13
13
|
import { TrainError } from '@metro-labs/core/train-error';
|
|
14
14
|
import { claimNameAction, nameAction, setProfile } from './profile.js';
|
|
15
15
|
import { profileAction } from './sender.js';
|
|
16
|
-
import { makeStation, type CallMsg } from '@metro-labs/core/stations/station-runtime';
|
|
16
|
+
import { makeStation, respond, type CallMsg } from '@metro-labs/core/stations/station-runtime';
|
|
17
17
|
|
|
18
18
|
type Args = Record<string, unknown>;
|
|
19
19
|
|
|
@@ -32,68 +32,47 @@ async function send(id: string, args: Args): Promise<void> {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function ask(id: string, args: Args): Promise<void> {
|
|
35
|
-
const { line
|
|
35
|
+
const { line } = args as { line: string };
|
|
36
36
|
const { acct, conv } = await convOf(line);
|
|
37
37
|
if (!conv) throw noConv(line);
|
|
38
|
-
const
|
|
39
|
-
const mintedId =
|
|
40
|
-
pollId ??
|
|
41
|
-
(typeof crypto?.randomUUID === 'function'
|
|
42
|
-
? crypto.randomUUID()
|
|
43
|
-
: fallbackId);
|
|
38
|
+
const mintedId = crypto.randomUUID();
|
|
44
39
|
const { poll, title } = buildPollContent(args, mintedId);
|
|
45
40
|
const sentId = await conv.send(new PollCodec().encode(poll));
|
|
46
41
|
emitOutbound(acct.cfg.id, line, sentId, `📊 Poll: ${title}`);
|
|
47
42
|
respond(id, { result: { messageId: sentId, pollId: mintedId } });
|
|
48
43
|
}
|
|
49
44
|
|
|
45
|
+
async function referenceInboxOf(conv: Conversation, xmtpMsgId: string): Promise<string> {
|
|
46
|
+
const recent = await conv.messages({ limit: 200, direction: 1 });
|
|
47
|
+
const inbox = recent.find((m) => m.id === xmtpMsgId)?.senderInboxId;
|
|
48
|
+
if (!inbox)
|
|
49
|
+
throw new TrainError('NOT_FOUND', `could not resolve referenceInboxId for ${xmtpMsgId}`);
|
|
50
|
+
return inbox;
|
|
51
|
+
}
|
|
52
|
+
|
|
50
53
|
async function react(id: string, args: Args): Promise<void> {
|
|
51
|
-
const {
|
|
52
|
-
line,
|
|
53
|
-
messageId,
|
|
54
|
-
emoji,
|
|
55
|
-
action: reactAction,
|
|
56
|
-
schema: reactSchema,
|
|
57
|
-
} = args as {
|
|
54
|
+
const { line, messageId, emoji, action: reactAction } = args as {
|
|
58
55
|
line: string;
|
|
59
56
|
messageId: string;
|
|
60
57
|
emoji: string;
|
|
61
58
|
action?: 'added' | 'removed';
|
|
62
|
-
schema?: string;
|
|
63
|
-
referenceInboxId?: string;
|
|
64
59
|
};
|
|
65
60
|
const { acct, conv } = await convOf(line);
|
|
66
61
|
if (!conv) throw noConv(line);
|
|
67
62
|
const xmtpMsgId = resolveMsgId(messageId);
|
|
68
|
-
|
|
69
|
-
if (!refInbox) {
|
|
70
|
-
const recent = await conv.messages({ limit: 200, direction: 1 });
|
|
71
|
-
refInbox = recent.find((m) => m.id === xmtpMsgId)?.senderInboxId;
|
|
72
|
-
if (!refInbox)
|
|
73
|
-
throw new TrainError(
|
|
74
|
-
'NOT_FOUND',
|
|
75
|
-
`could not resolve referenceInboxId for ${xmtpMsgId}`,
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
const schemaEnum =
|
|
79
|
-
reactSchema === 'custom'
|
|
80
|
-
? ReactionSchema.Custom
|
|
81
|
-
: reactSchema === 'shortcode'
|
|
82
|
-
? ReactionSchema.Shortcode
|
|
83
|
-
: ReactionSchema.Unicode;
|
|
63
|
+
const removed = reactAction === 'removed';
|
|
84
64
|
const sentId = await conv.sendReaction({
|
|
85
65
|
reference: xmtpMsgId,
|
|
86
|
-
referenceInboxId:
|
|
87
|
-
action:
|
|
88
|
-
reactAction === 'removed' ? ReactionAction.Removed : ReactionAction.Added,
|
|
66
|
+
referenceInboxId: await referenceInboxOf(conv, xmtpMsgId),
|
|
67
|
+
action: removed ? ReactionAction.Removed : ReactionAction.Added,
|
|
89
68
|
content: emoji,
|
|
90
|
-
schema:
|
|
69
|
+
schema: ReactionSchema.Unicode,
|
|
91
70
|
});
|
|
92
71
|
emitOutbound(
|
|
93
72
|
acct.cfg.id,
|
|
94
73
|
line,
|
|
95
74
|
sentId,
|
|
96
|
-
`[react ${emoji}${
|
|
75
|
+
`[react ${emoji}${removed ? ' (removed)' : ''}]`,
|
|
97
76
|
{ type: 'react', emoji, targetId: xmtpMsgId },
|
|
98
77
|
);
|
|
99
78
|
respond(id, { result: { messageId: sentId } });
|
|
@@ -151,54 +130,28 @@ const IMG_MIME_BY_EXT: Record<string, string> = {
|
|
|
151
130
|
webp: 'image/webp',
|
|
152
131
|
};
|
|
153
132
|
|
|
154
|
-
|
|
155
|
-
path
|
|
156
|
-
dataB64: string | undefined,
|
|
157
|
-
): Promise<Uint8Array> {
|
|
158
|
-
if (path) {
|
|
159
|
-
const { readFileSync } = await import('node:fs');
|
|
160
|
-
return new Uint8Array(readFileSync(path));
|
|
161
|
-
}
|
|
162
|
-
if (dataB64) return new Uint8Array(Buffer.from(dataB64, 'base64'));
|
|
163
|
-
throw badArgs('sendImage requires path or dataB64');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function imageMime(
|
|
167
|
-
mimeType: string | undefined,
|
|
168
|
-
filename: string | undefined,
|
|
169
|
-
path: string | undefined,
|
|
170
|
-
): string {
|
|
171
|
-
if (mimeType) return mimeType;
|
|
172
|
-
const ext = (filename ?? path ?? '').toLowerCase().split('.').pop() ?? '';
|
|
133
|
+
function imageMime(path: string): string {
|
|
134
|
+
const ext = path.toLowerCase().split('.').pop() ?? '';
|
|
173
135
|
return IMG_MIME_BY_EXT[ext] ?? 'image/png';
|
|
174
136
|
}
|
|
175
137
|
|
|
176
|
-
function imageFilename(
|
|
177
|
-
|
|
178
|
-
path: string | undefined,
|
|
179
|
-
): string {
|
|
180
|
-
if (filename) return filename;
|
|
181
|
-
const baseName = path ? path.split('/').pop() : undefined;
|
|
138
|
+
function imageFilename(path: string): string {
|
|
139
|
+
const baseName = path.split('/').pop();
|
|
182
140
|
return baseName != null && baseName !== '' ? baseName : 'image.png';
|
|
183
141
|
}
|
|
184
142
|
|
|
185
143
|
async function sendImage(id: string, args: Args): Promise<void> {
|
|
186
|
-
const { line, path
|
|
187
|
-
|
|
188
|
-
path?: string;
|
|
189
|
-
dataB64?: string;
|
|
190
|
-
filename?: string;
|
|
191
|
-
mimeType?: string;
|
|
192
|
-
};
|
|
144
|
+
const { line, path } = args as { line: string; path?: string };
|
|
145
|
+
if (!path) throw badArgs('sendImage requires path');
|
|
193
146
|
const { acct, conv } = await convOf(line);
|
|
194
147
|
if (!conv) throw noConv(line);
|
|
195
|
-
const
|
|
196
|
-
const mime = imageMime(
|
|
197
|
-
const fname = imageFilename(
|
|
148
|
+
const { readFileSync } = await import('node:fs');
|
|
149
|
+
const mime = imageMime(path);
|
|
150
|
+
const fname = imageFilename(path);
|
|
198
151
|
const attachment: Attachment = {
|
|
199
152
|
filename: fname,
|
|
200
153
|
mimeType: mime,
|
|
201
|
-
data:
|
|
154
|
+
data: new Uint8Array(readFileSync(path)),
|
|
202
155
|
};
|
|
203
156
|
const sentId = await conv.send(new AttachmentCodec().encode(attachment));
|
|
204
157
|
emitOutbound(acct.cfg.id, line, sentId, `[${mime.split('/')[0]}: ${fname}]`);
|
|
@@ -240,5 +193,5 @@ export type { CallMsg };
|
|
|
240
193
|
|
|
241
194
|
export const handleCall = makeStation({
|
|
242
195
|
handlers,
|
|
243
|
-
normalize:
|
|
196
|
+
normalize: messagingAliases({ action: 'removed' }),
|
|
244
197
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Conversation, DecodedMessage } from '@xmtp/node-sdk';
|
|
2
2
|
import { lineOf } from './accounts.js';
|
|
3
3
|
import { selfUri } from '@metro-labs/core/stations/train-events';
|
|
4
|
-
import { emit, mintId
|
|
4
|
+
import { emit, mintId } from '@metro-labs/core/stations/station-runtime';
|
|
5
|
+
import { rememberSent, rememberUid } from './wire.js';
|
|
5
6
|
import { typedEnvelope, type EnvelopeCtx } from './emit-payloads.js';
|
|
6
7
|
import type { StructuredEvent } from '@metro-labs/core/events';
|
|
7
8
|
|
|
@@ -53,16 +54,14 @@ export function emitOutbound(
|
|
|
53
54
|
rememberUid(uid, messageId);
|
|
54
55
|
rememberSent(messageId);
|
|
55
56
|
emit({
|
|
56
|
-
kind: 'outbound',
|
|
57
57
|
id: uid,
|
|
58
58
|
ts: new Date().toISOString(),
|
|
59
59
|
station: 'xmtp',
|
|
60
60
|
line,
|
|
61
|
-
from: selfUri(
|
|
61
|
+
from: selfUri(),
|
|
62
62
|
to: line,
|
|
63
63
|
message_id: messageId,
|
|
64
64
|
text,
|
|
65
|
-
account: accountId,
|
|
66
65
|
...(event ? { event } : {}),
|
|
67
66
|
payload: { account: accountId },
|
|
68
67
|
});
|
|
@@ -68,12 +68,7 @@ async function handleStreamMessage(
|
|
|
68
68
|
const env = envelope(id, msg, conv);
|
|
69
69
|
Object.assign(env, senderFieldsNow(acct, msg.senderInboxId));
|
|
70
70
|
const name = await groupNameFor(msg.conversationId, conv);
|
|
71
|
-
if (name)
|
|
72
|
-
env.line_name = name;
|
|
73
|
-
env.lineName = name;
|
|
74
|
-
const p = (env.payload ?? {}) as Record<string, unknown>;
|
|
75
|
-
env.payload = { ...p, lineName: name };
|
|
76
|
-
}
|
|
71
|
+
if (name) env.line_name = name;
|
|
77
72
|
emitInbound(id, env);
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { accountForCall } from './accounts.js';
|
|
14
14
|
import { claimName, nameOf, parseLabel } from './names.js';
|
|
15
15
|
import { sendSponsored, type SmartAccount } from './smart.js';
|
|
16
|
-
import { respond } from '
|
|
16
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
17
17
|
|
|
18
18
|
export const BASENAME_REGISTRY = '0xB94704422c2a1E396835A571837Aa5AE53285a95' as const;
|
|
19
19
|
export const BASENAME_L2_RESOLVER = '0xC6d566A56A1aFf6508b41f6c90ff131615583BCD' as const;
|
|
@@ -2,7 +2,7 @@ import { createPublicClient, http, namehash, type Hex } from 'viem';
|
|
|
2
2
|
import { base } from 'viem/chains';
|
|
3
3
|
import { normalize } from 'viem/ens';
|
|
4
4
|
import { makeProfileCache, type SenderProfile as Profile } from '@metro-labs/core/stations/sender-profile';
|
|
5
|
-
import { respond } from '
|
|
5
|
+
import { respond } from '@metro-labs/core/stations/station-runtime';
|
|
6
6
|
import { TrainError } from '@metro-labs/core/train-error';
|
|
7
7
|
import { accountForCall, accounts, type Account } from './accounts.js';
|
|
8
8
|
import { resolveAddresses } from './conv-helpers.js';
|
|
@@ -65,7 +65,7 @@ export async function xmtpSendAttachments(
|
|
|
65
65
|
): Promise<string[]> {
|
|
66
66
|
const sent: string[] = [];
|
|
67
67
|
for (const a of atts) {
|
|
68
|
-
const src = a.path ??
|
|
68
|
+
const src = a.path ?? '';
|
|
69
69
|
if (!src) continue;
|
|
70
70
|
const mime = a.mime ?? guessMime(src);
|
|
71
71
|
if (isImageMime(mime) || isImageExt(src)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errMsg } from '@metro-labs/core/log';
|
|
2
2
|
import { emitInbound, selfUri } from '@metro-labs/core/stations/train-events';
|
|
3
|
-
import { mintId } from '
|
|
3
|
+
import { mintId } from '@metro-labs/core/stations/station-runtime';
|
|
4
4
|
|
|
5
5
|
const WHISPER_BIN = process.env.METRO_WHISPER_BIN ?? 'whisper-cli';
|
|
6
6
|
const WHISPER_MODEL =
|
|
@@ -67,7 +67,7 @@ export async function transcribeAndEmit(
|
|
|
67
67
|
ts: new Date().toISOString(),
|
|
68
68
|
station: 'xmtp',
|
|
69
69
|
line,
|
|
70
|
-
from: selfUri(
|
|
70
|
+
from: selfUri(),
|
|
71
71
|
text: `🎙️ ${text}`,
|
|
72
72
|
payload: {
|
|
73
73
|
contentType: 'transcript',
|
package/runtime/runtime.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export const NEEDS_APPROVAL = (where: string, tool: string): string =>
|
|
2
|
-
`Needs the owner's approval for ${where} (${tool}). Make this exact call from a background worker so Claude Code asks the owner in chat, and wait for the answer. An approval given only in the terminal does not count.`;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const accountStrippedLine = (line: string): string => {
|
|
2
|
-
const parts = line.split('/');
|
|
3
|
-
if (parts.length < 5) return line;
|
|
4
|
-
return [parts[0], parts[1], parts[2], ...parts.slice(4)].join('/');
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const dedupeKey = (
|
|
8
|
-
station: string,
|
|
9
|
-
line: string,
|
|
10
|
-
kind: string,
|
|
11
|
-
messageId: string,
|
|
12
|
-
): string => `${station} ${accountStrippedLine(line)} ${kind} ${messageId}`;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const shortId = (id: string): string => (id.length > 10 ? `${id.slice(0, 6)}…` : id);
|
|
2
|
-
|
|
3
|
-
export function reactionEmoji(raw: unknown): string {
|
|
4
|
-
if (typeof raw === 'string') return raw;
|
|
5
|
-
const obj = raw as { name?: string; reaction?: string } | undefined;
|
|
6
|
-
return obj?.name ?? obj?.reaction ?? '';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function reactContent(emoji: string, target: string, removed: boolean): string {
|
|
10
|
-
const verb = removed ? 'removed from' : 'reacted to';
|
|
11
|
-
const label = removed ? emoji || 'reaction' : emoji || 'reacted';
|
|
12
|
-
return `${label} ${verb} message ${shortId(target)}`.trim();
|
|
13
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const PERMISSION_REPLY_RE = /^\s*(y|yes|n|no)\s+([a-km-z]{5})\s*$/i;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { authHeaders, type ConnectorAuth, type OAuthAuth } from './verify.js';
|
|
2
|
-
|
|
3
|
-
export type RelayTarget =
|
|
4
|
-
| { kind: 'ok'; url: string; headers: Record<string, string> }
|
|
5
|
-
| { kind: 'missing' }
|
|
6
|
-
| { kind: 'signin' };
|
|
7
|
-
|
|
8
|
-
function staleUsable(auth: OAuthAuth, now = Date.now()): boolean {
|
|
9
|
-
return auth.expiresAt === undefined || auth.expiresAt > now;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function unrefreshedTarget(
|
|
13
|
-
url: string,
|
|
14
|
-
auth: OAuthAuth,
|
|
15
|
-
force: boolean,
|
|
16
|
-
now = Date.now(),
|
|
17
|
-
): RelayTarget {
|
|
18
|
-
if (force) return { kind: 'signin' };
|
|
19
|
-
return { kind: 'ok', url, headers: staleUsable(auth, now) ? authHeaders(auth) : {} };
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function fixedTarget(
|
|
23
|
-
url: string,
|
|
24
|
-
auth: Exclude<ConnectorAuth, OAuthAuth>,
|
|
25
|
-
force: boolean,
|
|
26
|
-
): RelayTarget {
|
|
27
|
-
if (force) return { kind: 'signin' };
|
|
28
|
-
return { kind: 'ok', url, headers: authHeaders(auth) };
|
|
29
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { sessionRoute } from '@metro-labs/http/api-http';
|
|
4
|
-
import { MOVE_LOG, moveState, startMove } from './move.js';
|
|
5
|
-
import { rootHelper, runningAsMetro, runningAsRoot } from './privilege.js';
|
|
6
|
-
import { HELPER_VERSION } from './helper-script.js';
|
|
7
|
-
|
|
8
|
-
const PATH = '/api/server/metro-user';
|
|
9
|
-
const LOG_TAIL = 40;
|
|
10
|
-
|
|
11
|
-
function logTail(): string {
|
|
12
|
-
try {
|
|
13
|
-
return readFileSync(MOVE_LOG, 'utf8').split('\n').slice(-LOG_TAIL).join('\n');
|
|
14
|
-
} catch {
|
|
15
|
-
return '';
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function helperVersion(): number | null {
|
|
20
|
-
if (!runningAsMetro()) return null;
|
|
21
|
-
const v = Number(rootHelper(['version']).stdout.trim());
|
|
22
|
-
return Number.isInteger(v) ? v : null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function view(): unknown {
|
|
26
|
-
const runningAs = runningAsRoot() ? 'root' : runningAsMetro() ? 'metro' : 'other';
|
|
27
|
-
const helper = helperVersion();
|
|
28
|
-
return {
|
|
29
|
-
runningAs,
|
|
30
|
-
canMove: runningAs === 'root',
|
|
31
|
-
move: moveState(),
|
|
32
|
-
log: logTail(),
|
|
33
|
-
helper,
|
|
34
|
-
helperCurrent: runningAs !== 'metro' || helper === HELPER_VERSION,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function handleMetroUserRequest(req: IncomingMessage, res: ServerResponse): boolean {
|
|
39
|
-
return sessionRoute(req, res, { methods: { [PATH]: ['GET', 'POST'] }, admin: true, label: 'metro-user-api' }, () => {
|
|
40
|
-
if (req.method === 'POST') startMove();
|
|
41
|
-
return Promise.resolve(view());
|
|
42
|
-
});
|
|
43
|
-
}
|