@stage-labs/metro 0.1.0-beta.26 → 0.1.0-beta.28

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 ADDED
@@ -0,0 +1,15 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ const CHANNEL_FLAGS = ['--dangerously-load-development-channels', 'server:metro'];
3
+ export const claudeArgs = (extra) => [
4
+ ...CHANNEL_FLAGS,
5
+ ...extra,
6
+ ];
7
+ export function launchClaude(extra) {
8
+ const leaveToChild = () => undefined;
9
+ process.on('SIGINT', leaveToChild);
10
+ process.on('SIGTERM', leaveToChild);
11
+ const res = spawnSync('claude', claudeArgs(extra), { stdio: 'inherit' });
12
+ if (res.error !== undefined)
13
+ throw new Error('the `claude` command is not on PATH — install Claude Code first');
14
+ return Promise.resolve(res.status ?? 1);
15
+ }
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import { clearToken, credentialsPath, metroUrl, metroWebUrl, writeToken, } from
6
6
  import { detach, lockedBy, probe, runningPid, stopAll, tail } from './control.js';
7
7
  import { tailEvents } from './tail.js';
8
8
  import { assertAgentId, daemonPlan, localUrl, readRunToken, runDaemon, runtimeDir, writeRunToken, } from './runtime.js';
9
+ import { launchClaude } from './claude.js';
9
10
  import { installPlugin, syncPluginServers } from './plugin.js';
10
11
  import { update } from './update.js';
11
12
  import { currentVersion } from './version.js';
@@ -26,6 +27,8 @@ const USAGE = `metro — the command line for your MCP connectors
26
27
  metro whoami print the account and collection this machine may read
27
28
  metro mcp print the mcpServers block for the authorized collection
28
29
  metro plugin set up the Claude Code plugin (connector servers + /metro:login)
30
+ metro claude [args...]
31
+ open Claude Code with the metro channel; every argument is passed through
29
32
  metro update update to the newest published version
30
33
  metro version print this CLI's version
31
34
 
@@ -137,6 +140,7 @@ const COMMANDS = {
137
140
  return 0;
138
141
  },
139
142
  plugin: installPlugin,
143
+ claude: () => launchClaude(process.argv.slice(3)),
140
144
  update,
141
145
  version: async () => {
142
146
  process.stdout.write(`${currentVersion()}\n`);
package/dist/prompt.js CHANGED
@@ -35,7 +35,7 @@ export function askSecret(question) {
35
35
  stdin.resume();
36
36
  stdin.setEncoding('utf8');
37
37
  return new Promise((resolve, reject) => {
38
- let value = '\u0003';
38
+ let value = '';
39
39
  const finish = () => {
40
40
  stdin.setRawMode(false);
41
41
  stdin.pause();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stage-labs/metro",
3
- "version": "0.1.0-beta.26",
3
+ "version": "0.1.0-beta.28",
4
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": {
@@ -40,11 +40,16 @@ async function handleClaim(
40
40
  sendJson(req, res, 503, { error: 'sign-in is not configured' });
41
41
  return;
42
42
  }
43
- const code = bodyField(await readJsonBody(req), 'code');
44
- const taken =
45
- typeof code === 'string' && CLI_CODE_RE.test(code)
46
- ? takeCliCode(code)
47
- : undefined;
43
+ const raw = bodyField(await readJsonBody(req), 'code');
44
+ const code = typeof raw === 'string' ? raw.trim() : '';
45
+ if (!CLI_CODE_RE.test(code)) {
46
+ sendJson(req, res, 400, {
47
+ error:
48
+ 'that does not look like a collection code — metro login wants the mc_… code from metro.box/#/authorize',
49
+ });
50
+ return;
51
+ }
52
+ const taken = takeCliCode(code);
48
53
  if (taken === undefined) {
49
54
  sendJson(req, res, 400, {
50
55
  error: 'that code has expired or was already used',
@@ -51,11 +51,16 @@ async function handleClaim(
51
51
  return;
52
52
  }
53
53
  const body = await readJsonBody(req);
54
- const code = bodyField(body, 'code');
55
- const taken =
56
- typeof code === 'string' && RUN_CODE_RE.test(code)
57
- ? takeRunCode(code)
58
- : undefined;
54
+ const raw = bodyField(body, 'code');
55
+ const code = typeof raw === 'string' ? raw.trim() : '';
56
+ if (!RUN_CODE_RE.test(code)) {
57
+ sendJson(req, res, 400, {
58
+ error:
59
+ 'that does not look like a runtime code — metro start wants the mr_… code from the agent page',
60
+ });
61
+ return;
62
+ }
63
+ const taken = takeRunCode(code);
59
64
  if (taken === undefined) {
60
65
  sendJson(req, res, 400, {
61
66
  error: 'that code has expired or was already used',
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.1.0-beta.26"
2
+ "version": "0.1.0-beta.28"
3
3
  }