@stage-labs/metro 0.1.0-beta.3 → 0.1.0-beta.30
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/api.js +131 -0
- package/dist/bedrock-eventstream.js +120 -0
- package/dist/bedrock-proxy.js +260 -0
- package/dist/bedrock-upstream.js +72 -0
- package/dist/bedrock.js +104 -0
- package/dist/claude.js +15 -0
- package/dist/cli.js +157 -253
- package/dist/control.js +158 -0
- package/dist/plugin.js +82 -0
- package/dist/prompt.js +61 -0
- package/dist/runtime.js +94 -0
- package/dist/store.js +70 -0
- package/dist/tail.js +120 -0
- package/dist/update.js +33 -0
- package/dist/version.js +97 -0
- package/package.json +34 -21
- package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +119 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +210 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
- package/runtime/node_modules/@metro-labs/mcp/package.json +66 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +24 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/inbound.ts +367 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/media-note.ts +85 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/pending.ts +75 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/relay.ts +129 -0
- package/runtime/node_modules/@metro-labs/mcp/src/channels/webhook-note.ts +51 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +311 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +337 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-error.ts +8 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +129 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-grant.ts +99 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-owner.ts +32 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-serve.ts +129 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-session.ts +278 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +321 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +123 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +20 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +202 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-api.ts +339 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +21 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth-routes.ts +157 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth.ts +127 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +100 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +57 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +333 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cors.ts +29 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/crash-guard.ts +49 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/events.ts +117 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +164 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +208 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/http.ts +359 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +79 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/log.ts +42 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-client.ts +162 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-discovery.ts +120 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +65 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +58 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/paths.ts +134 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +214 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/protocol.ts +224 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/relay.ts +302 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +130 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +18 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +105 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/secure-fs.ts +57 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-api.ts +27 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +43 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +218 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/supervisor-io.ts +97 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/supervisor.ts +323 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/train-call.ts +22 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/train-error.ts +53 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +169 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/upload-api.ts +295 -0
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/upload-store.ts +181 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +91 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +215 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +71 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-scope.ts +64 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +37 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +218 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/connector-config.ts +147 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/connector-relay.ts +126 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +308 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/ids.ts +19 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/key-map.ts +45 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +382 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +300 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +31 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +105 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +131 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +45 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +57 -0
- package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +18 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/accounts.ts +145 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/call-tools.ts +203 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +29 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/ctx.ts +62 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/event-store.ts +91 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +21 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/group-tools.ts +129 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/index.ts +192 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/member-tools.ts +72 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +66 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/raw-get-stream.ts +207 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +73 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +172 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +43 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session.ts +211 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/str.ts +5 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/tool-dispatch.ts +212 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/tool-schemas.ts +397 -0
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/upload-tool.ts +66 -0
- package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +240 -0
- package/runtime/node_modules/@metro-labs/mcp/src/server.ts +2 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +80 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-inline.ts +100 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-interactive.ts +161 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-resolve.ts +200 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-xmtp.ts +111 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attach.ts +182 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/attachments.ts +196 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/lines.ts +82 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +88 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/registry.ts +35 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/station-runtime.ts +64 -0
- package/runtime/node_modules/@metro-labs/mcp/src/stations/types.ts +107 -0
- package/runtime/node_modules/@metro-labs/telegram/package.json +28 -0
- package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +81 -0
- package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
- package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
- package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
- package/runtime/node_modules/@metro-labs/telegram/src/format.ts +141 -0
- package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
- package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
- package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
- package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
- package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
- package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
- package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
- package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
- package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
- package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
- package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
- package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +172 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +48 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
- package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
- package/runtime/node_modules/@metro-labs/webhook/src/station.ts +40 -0
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +29 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +67 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +178 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +318 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +132 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +141 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +17 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
- package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +113 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +333 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +78 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +39 -0
- package/runtime/runtime.json +3 -0
- package/runtime/trains/.keep +0 -0
- package/LICENSE +0 -21
- package/README.md +0 -114
- package/dist/agents/claude.js +0 -229
- package/dist/agents/codex.js +0 -282
- package/dist/agents/types.js +0 -3
- package/dist/channels/discord.js +0 -142
- package/dist/channels/telegram.js +0 -209
- package/dist/lib/dotenv.js +0 -31
- package/dist/lib/scope-cache.js +0 -85
- package/dist/lib/streaming.js +0 -207
- package/dist/log.js +0 -12
- package/dist/orchestrator.js +0 -399
- package/dist/paths.js +0 -33
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { readToken } from './store.js';
|
|
6
|
+
const MARKETPLACE_REPO = 'bonustrack/metro';
|
|
7
|
+
const PLUGIN_SPEC = 'metro@metro';
|
|
8
|
+
export function installPathFrom(raw) {
|
|
9
|
+
let parsed;
|
|
10
|
+
try {
|
|
11
|
+
parsed = JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
17
|
+
return null;
|
|
18
|
+
const plugins = parsed.plugins;
|
|
19
|
+
if (typeof plugins !== 'object' || plugins === null)
|
|
20
|
+
return null;
|
|
21
|
+
const entries = plugins[PLUGIN_SPEC];
|
|
22
|
+
if (!Array.isArray(entries))
|
|
23
|
+
return null;
|
|
24
|
+
const first = entries[0];
|
|
25
|
+
return typeof first?.installPath === 'string' ? first.installPath : null;
|
|
26
|
+
}
|
|
27
|
+
export function pluginInstallPath() {
|
|
28
|
+
const registry = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = readFileSync(registry, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const path = installPathFrom(raw);
|
|
37
|
+
if (path === null)
|
|
38
|
+
return null;
|
|
39
|
+
return existsSync(join(path, 'bin', 'metro-plugin.mjs')) ? path : null;
|
|
40
|
+
}
|
|
41
|
+
function runClaude(args) {
|
|
42
|
+
const res = spawnSync('claude', args, { encoding: 'utf8' });
|
|
43
|
+
if (res.error !== undefined)
|
|
44
|
+
throw new Error('the `claude` command is not on PATH — install Claude Code first');
|
|
45
|
+
const output = `${res.stdout ?? ''}${res.stderr ?? ''}`;
|
|
46
|
+
return { ok: res.status === 0, output };
|
|
47
|
+
}
|
|
48
|
+
const tolerable = (output) => /already|exists|latest version/i.test(output);
|
|
49
|
+
export function syncPluginServers() {
|
|
50
|
+
const path = pluginInstallPath();
|
|
51
|
+
if (path === null || readToken() === null)
|
|
52
|
+
return false;
|
|
53
|
+
const script = join(path, 'bin', 'metro-plugin.mjs');
|
|
54
|
+
const refreshed = spawnSync(process.execPath, [script, 'refresh'], {
|
|
55
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
56
|
+
});
|
|
57
|
+
if (refreshed.status !== 0)
|
|
58
|
+
return false;
|
|
59
|
+
runClaude(['plugin', 'update', PLUGIN_SPEC]);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
export async function installPlugin() {
|
|
63
|
+
const added = runClaude(['plugin', 'marketplace', 'add', MARKETPLACE_REPO]);
|
|
64
|
+
if (!added.ok && !tolerable(added.output)) {
|
|
65
|
+
process.stderr.write(added.output);
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
const installed = runClaude(['plugin', 'install', PLUGIN_SPEC]);
|
|
69
|
+
if (!installed.ok && !tolerable(installed.output)) {
|
|
70
|
+
process.stderr.write(installed.output);
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
process.stderr.write('Claude Code plugin installed.\n');
|
|
74
|
+
if (syncPluginServers()) {
|
|
75
|
+
process.stderr.write('Connector servers loaded — new Claude sessions have them; ' +
|
|
76
|
+
'run /reload-plugins in any session already open.\n');
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
process.stderr.write('Now sign in: metro login (get a code at https://metro.box/#/authorize), ' +
|
|
80
|
+
'or run /metro:login <code> inside Claude Code.\n');
|
|
81
|
+
return Promise.resolve(0);
|
|
82
|
+
}
|
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
const CTRL_C = '\u0003';
|
|
3
|
+
const BACKSPACE = '\u007f';
|
|
4
|
+
export function askLine(question) {
|
|
5
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
rl.question(question, (answer) => {
|
|
8
|
+
rl.close();
|
|
9
|
+
resolve(answer.trim());
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function feedSecret(value, chunk) {
|
|
14
|
+
let out = value;
|
|
15
|
+
for (const ch of chunk) {
|
|
16
|
+
if (ch === CTRL_C)
|
|
17
|
+
return { kind: 'cancelled' };
|
|
18
|
+
if (ch === '\r' || ch === '\n')
|
|
19
|
+
return { kind: 'done', value: out };
|
|
20
|
+
if (ch === BACKSPACE || ch === '\b') {
|
|
21
|
+
out = out.slice(0, -1);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (ch >= ' ')
|
|
25
|
+
out += ch;
|
|
26
|
+
}
|
|
27
|
+
return { kind: 'more', value: out };
|
|
28
|
+
}
|
|
29
|
+
export function askSecret(question) {
|
|
30
|
+
const stdin = process.stdin;
|
|
31
|
+
if (!stdin.isTTY)
|
|
32
|
+
return askLine(question);
|
|
33
|
+
process.stderr.write(question);
|
|
34
|
+
stdin.setRawMode(true);
|
|
35
|
+
stdin.resume();
|
|
36
|
+
stdin.setEncoding('utf8');
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
let value = '';
|
|
39
|
+
const finish = () => {
|
|
40
|
+
stdin.setRawMode(false);
|
|
41
|
+
stdin.pause();
|
|
42
|
+
stdin.off('data', onData);
|
|
43
|
+
process.stderr.write('\n');
|
|
44
|
+
};
|
|
45
|
+
const onData = (chunk) => {
|
|
46
|
+
const step = feedSecret(value, chunk);
|
|
47
|
+
if (step.kind === 'cancelled') {
|
|
48
|
+
finish();
|
|
49
|
+
reject(new Error('cancelled'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (step.kind === 'done') {
|
|
53
|
+
finish();
|
|
54
|
+
resolve(step.value.trim());
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
value = step.value;
|
|
58
|
+
};
|
|
59
|
+
stdin.on('data', onData);
|
|
60
|
+
});
|
|
61
|
+
}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync, chmodSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { metroUrl } from './store.js';
|
|
8
|
+
const AGENT_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{10}$/;
|
|
9
|
+
const SERVER_ENTRY = join('node_modules', '@metro-labs', 'mcp', 'src', 'server.ts');
|
|
10
|
+
export class MissingRuntime extends Error {
|
|
11
|
+
}
|
|
12
|
+
export function runtimeDir() {
|
|
13
|
+
const explicit = process.env.METRO_RUNTIME_DIR?.trim();
|
|
14
|
+
const dir = explicit !== undefined && explicit !== ''
|
|
15
|
+
? explicit
|
|
16
|
+
: join(dirname(dirname(fileURLToPath(import.meta.url))), 'runtime');
|
|
17
|
+
if (!existsSync(join(dir, SERVER_ENTRY)))
|
|
18
|
+
throw new MissingRuntime(`no metro daemon at ${dir}. Reinstall with: npm i -g @stage-labs/metro@beta`);
|
|
19
|
+
return dir;
|
|
20
|
+
}
|
|
21
|
+
export class MissingBun extends Error {
|
|
22
|
+
}
|
|
23
|
+
export function assertAgentId(id) {
|
|
24
|
+
if (id === undefined || !AGENT_RE.test(id))
|
|
25
|
+
throw new Error(`'${id ?? ''}' is not an agent id — copy it from the agent's page in the web UI`);
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
export function findBun() {
|
|
29
|
+
const found = spawnSync('bun', ['--version'], { stdio: 'ignore' });
|
|
30
|
+
if (found.error !== undefined || found.status !== 0)
|
|
31
|
+
throw new MissingBun('metro start needs Bun, which is not on PATH.\n' +
|
|
32
|
+
'Install it with: curl -fsSL https://bun.sh/install | bash');
|
|
33
|
+
return 'bun';
|
|
34
|
+
}
|
|
35
|
+
function tokenPath(agentId) {
|
|
36
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
37
|
+
const base = xdg === undefined || xdg === '' ? join(homedir(), '.config') : xdg;
|
|
38
|
+
return join(base, 'metro', `runtime-${agentId}.json`);
|
|
39
|
+
}
|
|
40
|
+
export function readRunToken(agentId) {
|
|
41
|
+
const fromEnv = process.env.METRO_RUN_TOKEN?.trim();
|
|
42
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
43
|
+
return fromEnv;
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(readFileSync(tokenPath(agentId), 'utf8'));
|
|
46
|
+
if (typeof parsed.token !== 'string' || parsed.token === '')
|
|
47
|
+
return null;
|
|
48
|
+
return parsed.url === metroUrl() ? parsed.token : null;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function writeRunToken(agentId, token) {
|
|
55
|
+
const path = tokenPath(agentId);
|
|
56
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
57
|
+
writeFileSync(path, JSON.stringify({ token, url: metroUrl() }, null, 2));
|
|
58
|
+
chmodSync(path, 0o600);
|
|
59
|
+
}
|
|
60
|
+
export const localPort = () => Number(process.env.METRO_WEBHOOK_PORT) || 8420;
|
|
61
|
+
export const localUrl = () => `http://127.0.0.1:${String(localPort())}`;
|
|
62
|
+
export function daemonPlan(opts) {
|
|
63
|
+
return {
|
|
64
|
+
command: findBun(),
|
|
65
|
+
args: [SERVER_ENTRY],
|
|
66
|
+
cwd: opts.dir,
|
|
67
|
+
env: {
|
|
68
|
+
...process.env,
|
|
69
|
+
METRO_RUN_TOKEN: opts.token,
|
|
70
|
+
METRO_AGENT: opts.agentId,
|
|
71
|
+
METRO_URL: metroUrl(),
|
|
72
|
+
METRO_HTTP_HOST: process.env.METRO_HTTP_HOST ?? '127.0.0.1',
|
|
73
|
+
METRO_TRAINS_DIR: join(opts.dir, 'trains'),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function runDaemon(agentId, plan) {
|
|
78
|
+
process.stderr.write(`Starting metro for ${agentId}\n`);
|
|
79
|
+
const child = spawn(plan.command, plan.args, {
|
|
80
|
+
cwd: plan.cwd,
|
|
81
|
+
env: plan.env,
|
|
82
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
83
|
+
});
|
|
84
|
+
const relay = (sig) => () => {
|
|
85
|
+
child.kill(sig);
|
|
86
|
+
};
|
|
87
|
+
process.on('SIGINT', relay('SIGINT'));
|
|
88
|
+
process.on('SIGTERM', relay('SIGTERM'));
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
child.on('exit', (code) => {
|
|
91
|
+
resolve(code ?? 0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
const DEFAULT_BASE = 'https://mcp.metro.box';
|
|
5
|
+
const DEFAULT_WEB = 'https://metro.box';
|
|
6
|
+
function fromEnv(name, fallback) {
|
|
7
|
+
const raw = process.env[name]?.trim();
|
|
8
|
+
return raw === undefined || raw === '' ? fallback : raw.replace(/\/+$/, '');
|
|
9
|
+
}
|
|
10
|
+
export function metroUrl() {
|
|
11
|
+
return fromEnv('METRO_URL', DEFAULT_BASE);
|
|
12
|
+
}
|
|
13
|
+
export function metroWebUrl() {
|
|
14
|
+
return fromEnv('METRO_UI_URL', DEFAULT_WEB);
|
|
15
|
+
}
|
|
16
|
+
function configDir() {
|
|
17
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
18
|
+
const base = xdg === undefined || xdg === '' ? join(homedir(), '.config') : xdg;
|
|
19
|
+
return join(base, 'metro');
|
|
20
|
+
}
|
|
21
|
+
export function credentialsPath() {
|
|
22
|
+
return join(configDir(), 'credentials.json');
|
|
23
|
+
}
|
|
24
|
+
function readStored() {
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = readFileSync(credentialsPath(), 'utf8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = JSON.parse(raw);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
40
|
+
return null;
|
|
41
|
+
const { token, url } = parsed;
|
|
42
|
+
if (typeof token !== 'string' || token === '')
|
|
43
|
+
return null;
|
|
44
|
+
return { token, url: typeof url === 'string' ? url : DEFAULT_BASE };
|
|
45
|
+
}
|
|
46
|
+
export function readToken() {
|
|
47
|
+
const fromEnv = process.env.METRO_TOKEN?.trim();
|
|
48
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
49
|
+
return fromEnv;
|
|
50
|
+
const stored = readStored();
|
|
51
|
+
if (stored === null)
|
|
52
|
+
return null;
|
|
53
|
+
return stored.url === metroUrl() ? stored.token : null;
|
|
54
|
+
}
|
|
55
|
+
export function writeToken(token) {
|
|
56
|
+
const path = credentialsPath();
|
|
57
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
58
|
+
writeFileSync(path, `${JSON.stringify({ token, url: metroUrl() })}\n`, {
|
|
59
|
+
mode: 0o600,
|
|
60
|
+
});
|
|
61
|
+
chmodSync(path, 0o600);
|
|
62
|
+
}
|
|
63
|
+
export function clearToken() {
|
|
64
|
+
try {
|
|
65
|
+
rmSync(credentialsPath());
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
package/dist/tail.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { runConfigKey } from './api.js';
|
|
2
|
+
import { assertAgentId, localUrl, readRunToken } from './runtime.js';
|
|
3
|
+
const BACKOFF_MS = [1_000, 2_000, 5_000];
|
|
4
|
+
const STALL_MS = 90_000;
|
|
5
|
+
export const backoffAt = (attempt) => BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)] ?? 5_000;
|
|
6
|
+
export function sseDataLines(buffer, chunk) {
|
|
7
|
+
const lines = (buffer + chunk).split('\n');
|
|
8
|
+
const rest = lines.pop() ?? '';
|
|
9
|
+
const events = [];
|
|
10
|
+
for (const raw of lines) {
|
|
11
|
+
const line = raw.endsWith('\r') ? raw.slice(0, -1) : raw;
|
|
12
|
+
if (!line.startsWith('data:'))
|
|
13
|
+
continue;
|
|
14
|
+
const value = line.slice(5);
|
|
15
|
+
events.push(value.startsWith(' ') ? value.slice(1) : value);
|
|
16
|
+
}
|
|
17
|
+
return { rest, events };
|
|
18
|
+
}
|
|
19
|
+
function keySource(agentId) {
|
|
20
|
+
const fromEnv = process.env.METRO_AGENT_KEY?.trim();
|
|
21
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
22
|
+
return { resolve: () => Promise.resolve(fromEnv), fixed: true };
|
|
23
|
+
return {
|
|
24
|
+
resolve: () => {
|
|
25
|
+
const token = readRunToken(agentId);
|
|
26
|
+
if (token === null)
|
|
27
|
+
throw new Error(`this machine is not authorized for ${agentId} — ` +
|
|
28
|
+
`run 'metro start ${agentId}' once, or set METRO_AGENT_KEY`);
|
|
29
|
+
return runConfigKey(token);
|
|
30
|
+
},
|
|
31
|
+
fixed: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const armStall = (control) => setTimeout(() => {
|
|
35
|
+
control.abort();
|
|
36
|
+
}, STALL_MS);
|
|
37
|
+
async function connect(key, signal) {
|
|
38
|
+
try {
|
|
39
|
+
return await fetch(`${localUrl()}/api/tail`, {
|
|
40
|
+
headers: { authorization: `Bearer ${key}` },
|
|
41
|
+
signal,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function pump(body, control, stall) {
|
|
49
|
+
const reader = body.getReader();
|
|
50
|
+
const decoder = new TextDecoder();
|
|
51
|
+
let buffer = '';
|
|
52
|
+
try {
|
|
53
|
+
for (;;) {
|
|
54
|
+
const { done, value } = await reader.read();
|
|
55
|
+
if (done)
|
|
56
|
+
return 'ended';
|
|
57
|
+
clearTimeout(stall.timer);
|
|
58
|
+
stall.timer = armStall(control);
|
|
59
|
+
const out = sseDataLines(buffer, decoder.decode(value, { stream: true }));
|
|
60
|
+
buffer = out.rest;
|
|
61
|
+
for (const event of out.events)
|
|
62
|
+
process.stdout.write(`${event}\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return 'ended';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function streamOnce(key) {
|
|
70
|
+
const control = new AbortController();
|
|
71
|
+
const stall = { timer: armStall(control) };
|
|
72
|
+
try {
|
|
73
|
+
const res = await connect(key, control.signal);
|
|
74
|
+
if (res === null)
|
|
75
|
+
return 'unreachable';
|
|
76
|
+
if (res.status === 401)
|
|
77
|
+
return 'unauthorized';
|
|
78
|
+
if (!res.ok || res.body === null)
|
|
79
|
+
return 'unreachable';
|
|
80
|
+
return await pump(res.body, control, stall);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
clearTimeout(stall.timer);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function note(state, message) {
|
|
87
|
+
if (state.last === message)
|
|
88
|
+
return;
|
|
89
|
+
state.last = message;
|
|
90
|
+
process.stderr.write(`metro: ${message}\n`);
|
|
91
|
+
}
|
|
92
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
93
|
+
async function settle(end, source, key, agentId, state) {
|
|
94
|
+
if (end === 'unauthorized') {
|
|
95
|
+
if (source.fixed)
|
|
96
|
+
throw new Error('the key in METRO_AGENT_KEY was refused by the local daemon');
|
|
97
|
+
note(state, 'key refused — fetching the current one');
|
|
98
|
+
return source.resolve();
|
|
99
|
+
}
|
|
100
|
+
if (end === 'unreachable')
|
|
101
|
+
note(state, `no metro daemon on ${localUrl()} — run 'metro start ${agentId}'`);
|
|
102
|
+
else
|
|
103
|
+
note(state, 'stream ended — reconnecting');
|
|
104
|
+
return key;
|
|
105
|
+
}
|
|
106
|
+
export async function tailEvents(argv) {
|
|
107
|
+
const agentId = assertAgentId(argv[0]);
|
|
108
|
+
const source = keySource(agentId);
|
|
109
|
+
let key = await source.resolve();
|
|
110
|
+
const state = { last: '' };
|
|
111
|
+
let attempt = 0;
|
|
112
|
+
for (;;) {
|
|
113
|
+
const end = await streamOnce(key);
|
|
114
|
+
if (end === 'ended')
|
|
115
|
+
attempt = 0;
|
|
116
|
+
key = await settle(end, source, key, agentId, state);
|
|
117
|
+
await delay(backoffAt(attempt));
|
|
118
|
+
attempt += 1;
|
|
119
|
+
}
|
|
120
|
+
}
|
package/dist/update.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { currentVersion, isNewer, PACKAGE_NAME, publishedVersion, } from './version.js';
|
|
3
|
+
export function managerFor(location) {
|
|
4
|
+
return location.includes('/.bun/') ? 'bun' : 'npm';
|
|
5
|
+
}
|
|
6
|
+
export function installArgs(manager, version) {
|
|
7
|
+
const spec = `${PACKAGE_NAME}@${version}`;
|
|
8
|
+
return manager === 'bun'
|
|
9
|
+
? ['add', '--global', spec]
|
|
10
|
+
: ['install', '--global', spec];
|
|
11
|
+
}
|
|
12
|
+
export async function update() {
|
|
13
|
+
const current = currentVersion();
|
|
14
|
+
const newest = await publishedVersion();
|
|
15
|
+
if (newest === '') {
|
|
16
|
+
process.stderr.write('npm published no version this CLI understands\n');
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
if (!isNewer(newest, current)) {
|
|
20
|
+
process.stderr.write(`metro ${current} is the newest published version\n`);
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
const manager = managerFor(import.meta.url);
|
|
24
|
+
const args = installArgs(manager, newest);
|
|
25
|
+
process.stderr.write(`Updating metro ${current} to ${newest} with ${manager}\n`);
|
|
26
|
+
const run = spawnSync(manager, args, { stdio: 'inherit' });
|
|
27
|
+
if (run.error !== undefined || run.status !== 0) {
|
|
28
|
+
process.stderr.write(`That did not work. Run it yourself:\n ${manager} ${args.join(' ')}\n`);
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
process.stderr.write(`metro is now ${newest}\n`);
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
export const PACKAGE_NAME = '@stage-labs/metro';
|
|
3
|
+
const REGISTRY = 'https://registry.npmjs.org';
|
|
4
|
+
const TIMEOUT_MS = 15_000;
|
|
5
|
+
export function parseVersion(raw) {
|
|
6
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(raw.trim());
|
|
7
|
+
if (match === null)
|
|
8
|
+
return null;
|
|
9
|
+
const core = [match[1], match[2], match[3]].map((n) => Number(n));
|
|
10
|
+
const pre = match[4] === undefined
|
|
11
|
+
? []
|
|
12
|
+
: match[4]
|
|
13
|
+
.split('.')
|
|
14
|
+
.map((part) => (/^\d+$/.test(part) ? Number(part) : part));
|
|
15
|
+
return { core, pre };
|
|
16
|
+
}
|
|
17
|
+
function comparePart(left, right) {
|
|
18
|
+
if (left === undefined)
|
|
19
|
+
return -1;
|
|
20
|
+
if (right === undefined)
|
|
21
|
+
return 1;
|
|
22
|
+
if (left === right)
|
|
23
|
+
return 0;
|
|
24
|
+
if (typeof left === 'number' && typeof right === 'number')
|
|
25
|
+
return left < right ? -1 : 1;
|
|
26
|
+
if (typeof left === 'number')
|
|
27
|
+
return -1;
|
|
28
|
+
if (typeof right === 'number')
|
|
29
|
+
return 1;
|
|
30
|
+
return left < right ? -1 : 1;
|
|
31
|
+
}
|
|
32
|
+
function comparePre(a, b) {
|
|
33
|
+
if (a.length === 0 && b.length === 0)
|
|
34
|
+
return 0;
|
|
35
|
+
if (a.length === 0)
|
|
36
|
+
return 1;
|
|
37
|
+
if (b.length === 0)
|
|
38
|
+
return -1;
|
|
39
|
+
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
40
|
+
const cmp = comparePart(a[i], b[i]);
|
|
41
|
+
if (cmp !== 0)
|
|
42
|
+
return cmp;
|
|
43
|
+
}
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
export function compareVersions(a, b) {
|
|
47
|
+
const left = parseVersion(a);
|
|
48
|
+
const right = parseVersion(b);
|
|
49
|
+
if (left === null || right === null)
|
|
50
|
+
return 0;
|
|
51
|
+
for (let i = 0; i < 3; i += 1) {
|
|
52
|
+
const l = left.core[i] ?? 0;
|
|
53
|
+
const r = right.core[i] ?? 0;
|
|
54
|
+
if (l !== r)
|
|
55
|
+
return l < r ? -1 : 1;
|
|
56
|
+
}
|
|
57
|
+
return comparePre(left.pre, right.pre);
|
|
58
|
+
}
|
|
59
|
+
export function isNewer(candidate, current) {
|
|
60
|
+
return compareVersions(candidate, current) > 0;
|
|
61
|
+
}
|
|
62
|
+
export function currentVersion() {
|
|
63
|
+
const path = new URL('../package.json', import.meta.url);
|
|
64
|
+
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
65
|
+
return typeof raw.version === 'string' ? raw.version : '0.0.0';
|
|
66
|
+
}
|
|
67
|
+
export function newestOf(tags) {
|
|
68
|
+
let best = '';
|
|
69
|
+
for (const value of Object.values(tags)) {
|
|
70
|
+
if (typeof value !== 'string' || parseVersion(value) === null)
|
|
71
|
+
continue;
|
|
72
|
+
if (best === '' || isNewer(value, best))
|
|
73
|
+
best = value;
|
|
74
|
+
}
|
|
75
|
+
return best;
|
|
76
|
+
}
|
|
77
|
+
export async function publishedVersion() {
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await fetch(`${REGISTRY}/${PACKAGE_NAME.replace('/', '%2F')}`, {
|
|
81
|
+
headers: { accept: 'application/json' },
|
|
82
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error('could not reach the npm registry');
|
|
87
|
+
}
|
|
88
|
+
if (!res.ok)
|
|
89
|
+
throw new Error(`npm answered ${String(res.status)}`);
|
|
90
|
+
const body = await res.json();
|
|
91
|
+
if (typeof body !== 'object' || body === null)
|
|
92
|
+
throw new Error('npm returned an unexpected response');
|
|
93
|
+
const tags = body['dist-tags'];
|
|
94
|
+
if (typeof tags !== 'object' || tags === null)
|
|
95
|
+
throw new Error('npm returned no dist-tags');
|
|
96
|
+
return newestOf(tags);
|
|
97
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stage-labs/metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0-beta.30",
|
|
4
|
+
"description": "The metro command line. Sign in once per machine, then hand your MCP connector list to Claude Code without the credentials touching disk, argv or shell history.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -14,34 +14,47 @@
|
|
|
14
14
|
"node": ">=22"
|
|
15
15
|
},
|
|
16
16
|
"bin": {
|
|
17
|
-
"metro": "
|
|
17
|
+
"metro": "dist/cli.js"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
-
"
|
|
22
|
-
"LICENSE"
|
|
21
|
+
"runtime"
|
|
23
22
|
],
|
|
24
23
|
"publishConfig": {
|
|
25
|
-
"access": "public"
|
|
24
|
+
"access": "public",
|
|
25
|
+
"tag": "beta"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"build": "tsc",
|
|
29
|
-
"prepublishOnly": "tsc",
|
|
30
|
-
"
|
|
31
|
-
"lint:fix": "eslint src/ --fix",
|
|
32
|
-
"typecheck": "tsc --noEmit"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"discord.js": "^14.14.0",
|
|
36
|
-
"pino": "^9.5.0",
|
|
37
|
-
"ws": "^8.20.0"
|
|
28
|
+
"build": "tsc && node scripts/stage-runtime.mjs",
|
|
29
|
+
"prepublishOnly": "tsc && node scripts/stage-runtime.mjs",
|
|
30
|
+
"test": "tsc --noEmit && node scripts/stage-runtime.mjs && bun test test/"
|
|
38
31
|
},
|
|
39
32
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"@types/ws": "^8.18.1",
|
|
33
|
+
"@stage-labs/config": "0.1.0-beta.2",
|
|
42
34
|
"eslint": "^10.3.0",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
35
|
+
"knip": "^6.15.0",
|
|
36
|
+
"madge": "^8.0.0",
|
|
37
|
+
"typescript": "^5"
|
|
45
38
|
},
|
|
46
|
-
"
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@discordjs/voice": "^0.19.2",
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
42
|
+
"@mtcute/bun": "0.30.1",
|
|
43
|
+
"@xmtp/content-type-primitives": "^3.0.1",
|
|
44
|
+
"@xmtp/content-type-reaction": "^2.0.2",
|
|
45
|
+
"@xmtp/content-type-remote-attachment": "^2.0.4",
|
|
46
|
+
"@xmtp/content-type-reply": "^2.0.3",
|
|
47
|
+
"@xmtp/content-type-wallet-send-calls": "^2.0.0",
|
|
48
|
+
"@xmtp/node-bindings": "1.9.1",
|
|
49
|
+
"@xmtp/node-sdk": "^6.0.0",
|
|
50
|
+
"baileys": "7.0.0-rc14",
|
|
51
|
+
"discord.js": "^14.26.4",
|
|
52
|
+
"drizzle-orm": "^0.44.0",
|
|
53
|
+
"pino": "^9.5.0",
|
|
54
|
+
"pino-pretty": "^13.1.3",
|
|
55
|
+
"postgres": "^3.4.5",
|
|
56
|
+
"prism-media": "^1.3.5",
|
|
57
|
+
"viem": "^2.52.2",
|
|
58
|
+
"zod": "^3.23.8"
|
|
59
|
+
}
|
|
47
60
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metro-labs/discord-bot",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/station.ts",
|
|
8
|
+
"./train": "./src/index.ts",
|
|
9
|
+
"./verify": "./src/verify.ts"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"test": "tsc --noEmit && bun test test/"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@metro-labs/mcp": "workspace:*",
|
|
17
|
+
"@discordjs/voice": "^0.19.2",
|
|
18
|
+
"discord.js": "^14.26.4",
|
|
19
|
+
"prism-media": "^1.3.5"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@stage-labs/config": "0.1.0-beta.2",
|
|
23
|
+
"eslint": "^10.3.0",
|
|
24
|
+
"knip": "^6.15.0",
|
|
25
|
+
"madge": "^8.0.0",
|
|
26
|
+
"typescript": "^5"
|
|
27
|
+
}
|
|
28
|
+
}
|