@somewhere-tech/cli 0.1.6 → 0.2.0
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/README.md +1 -0
- package/dist/commands/mcp.js +96 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/auth.js +3 -1
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/device.js +48 -0
- package/dist/lib/device.js.map +1 -0
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ After `somewhere init`, Claude Code and Codex auto-connect via the `.mcp.json` i
|
|
|
52
52
|
| `somewhere open --dashboard` | Open the dashboard |
|
|
53
53
|
| `somewhere dev` | Run local dev with platform env vars |
|
|
54
54
|
| `somewhere api GET /v1/projects` | Raw API call with auto-auth |
|
|
55
|
+
| `somewhere mcp` | Run MCP server over stdio (proxies to mcp.somewhere.tech) |
|
|
55
56
|
|
|
56
57
|
Short alias: `sw` works everywhere `somewhere` does.
|
|
57
58
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
|
+
import { loadConfig } from '../lib/config.js';
|
|
5
|
+
const UPSTREAM_URL = 'https://mcp.somewhere.tech/mcp';
|
|
6
|
+
// Emit a JSON-RPC error notification on stdout so MCP hosts surface a clear
|
|
7
|
+
// message instead of a generic crash. id=null because it's not a response to
|
|
8
|
+
// any specific request.
|
|
9
|
+
function emitFatalError(message) {
|
|
10
|
+
const payload = {
|
|
11
|
+
jsonrpc: '2.0',
|
|
12
|
+
id: null,
|
|
13
|
+
error: { code: -32001, message },
|
|
14
|
+
};
|
|
15
|
+
process.stdout.write(JSON.stringify(payload) + '\n');
|
|
16
|
+
}
|
|
17
|
+
export function registerMcp(program) {
|
|
18
|
+
program
|
|
19
|
+
.command('mcp')
|
|
20
|
+
.description('Run somewhere.tech MCP server over stdio (proxies to mcp.somewhere.tech)')
|
|
21
|
+
.action(async () => {
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
if (!config?.token) {
|
|
24
|
+
emitFatalError('Not logged in. Run: somewhere login');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const httpTransport = new StreamableHTTPClientTransport(new URL(UPSTREAM_URL), {
|
|
28
|
+
requestInit: {
|
|
29
|
+
headers: { Authorization: `Bearer ${config.token}` },
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const stdioTransport = new StdioServerTransport();
|
|
33
|
+
let shuttingDown = false;
|
|
34
|
+
const shutdown = async (reason) => {
|
|
35
|
+
if (shuttingDown)
|
|
36
|
+
return;
|
|
37
|
+
shuttingDown = true;
|
|
38
|
+
if (reason instanceof UnauthorizedError) {
|
|
39
|
+
emitFatalError('somewhere.tech rejected the API key. Run: somewhere login');
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
await stdioTransport.close();
|
|
43
|
+
}
|
|
44
|
+
catch { }
|
|
45
|
+
try {
|
|
46
|
+
await httpTransport.close();
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
};
|
|
50
|
+
stdioTransport.onmessage = (msg) => {
|
|
51
|
+
httpTransport.send(msg).catch((err) => {
|
|
52
|
+
if (err instanceof UnauthorizedError) {
|
|
53
|
+
void shutdown(err);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
process.stderr.write(`[somewhere mcp] upstream send failed: ${String(err)}\n`);
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
httpTransport.onmessage = (msg) => {
|
|
60
|
+
stdioTransport.send(msg).catch((err) => {
|
|
61
|
+
process.stderr.write(`[somewhere mcp] stdio send failed: ${String(err)}\n`);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
stdioTransport.onclose = () => { void shutdown(); };
|
|
65
|
+
httpTransport.onclose = () => { void shutdown(); };
|
|
66
|
+
stdioTransport.onerror = (err) => {
|
|
67
|
+
process.stderr.write(`[somewhere mcp] stdio error: ${String(err)}\n`);
|
|
68
|
+
};
|
|
69
|
+
httpTransport.onerror = (err) => {
|
|
70
|
+
if (err instanceof UnauthorizedError) {
|
|
71
|
+
void shutdown(err);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
process.stderr.write(`[somewhere mcp] upstream error: ${String(err)}\n`);
|
|
75
|
+
};
|
|
76
|
+
try {
|
|
77
|
+
await httpTransport.start();
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof UnauthorizedError) {
|
|
81
|
+
emitFatalError('somewhere.tech rejected the API key. Run: somewhere login');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
emitFatalError(`Failed to connect to mcp.somewhere.tech: ${String(err)}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await stdioTransport.start();
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
emitFatalError(`Failed to start stdio transport: ${String(err)}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -9,10 +9,11 @@ import { registerStatus } from './commands/status.js';
|
|
|
9
9
|
import { registerOpen } from './commands/open.js';
|
|
10
10
|
import { registerDev } from './commands/dev.js';
|
|
11
11
|
import { registerApi } from './commands/api.js';
|
|
12
|
+
import { registerMcp } from './commands/mcp.js';
|
|
12
13
|
const program = new Command()
|
|
13
14
|
.name('somewhere')
|
|
14
15
|
.description('CLI for somewhere.tech')
|
|
15
|
-
.version('0.
|
|
16
|
+
.version('0.2.0');
|
|
16
17
|
registerAuth(program);
|
|
17
18
|
registerInit(program);
|
|
18
19
|
registerProject(program);
|
|
@@ -23,5 +24,6 @@ registerStatus(program);
|
|
|
23
24
|
registerOpen(program);
|
|
24
25
|
registerDev(program);
|
|
25
26
|
registerApi(program);
|
|
27
|
+
registerMcp(program);
|
|
26
28
|
program.parse();
|
|
27
29
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wBAAwB,CAAC;KACrC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,WAAW,CAAC,OAAO,CAAC,CAAC;AAErB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wBAAwB,CAAC;KACrC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,WAAW,CAAC,OAAO,CAAC,CAAC;AAErB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import open from 'open';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
+
import { getDeviceKeyName } from './device.js';
|
|
4
5
|
const AUTH_URL = 'https://api.somewhere.tech/v1/auth/cli';
|
|
5
6
|
/**
|
|
6
7
|
* Browser-based OAuth login flow:
|
|
@@ -136,7 +137,8 @@ export async function browserLogin() {
|
|
|
136
137
|
}
|
|
137
138
|
const port = addr.port;
|
|
138
139
|
const redirect = `http://localhost:${port}/callback`;
|
|
139
|
-
const
|
|
140
|
+
const deviceName = getDeviceKeyName();
|
|
141
|
+
const loginUrl = `${AUTH_URL}?redirect=${encodeURIComponent(redirect)}&device_name=${encodeURIComponent(deviceName)}`;
|
|
140
142
|
console.log('');
|
|
141
143
|
console.log(` If the browser doesn't open, visit this URL:`);
|
|
142
144
|
console.log(` ${chalk.cyan(loginUrl)}`);
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir, hostname } from 'node:os';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.somewhere');
|
|
6
|
+
const DEVICE_PATH = join(CONFIG_DIR, 'device.json');
|
|
7
|
+
function ensureDir() {
|
|
8
|
+
if (!existsSync(CONFIG_DIR))
|
|
9
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
function loadDevice() {
|
|
12
|
+
if (!existsSync(DEVICE_PATH))
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(readFileSync(DEVICE_PATH, 'utf-8'));
|
|
16
|
+
if (typeof parsed.id !== 'string' || parsed.id.length < 8)
|
|
17
|
+
return null;
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function saveDevice(device) {
|
|
25
|
+
ensureDir();
|
|
26
|
+
writeFileSync(DEVICE_PATH, JSON.stringify(device, null, 2) + '\n', { mode: 0o600 });
|
|
27
|
+
}
|
|
28
|
+
export function getDeviceId() {
|
|
29
|
+
const existing = loadDevice();
|
|
30
|
+
if (existing)
|
|
31
|
+
return existing.id;
|
|
32
|
+
const fresh = { id: randomUUID(), created_at: new Date().toISOString() };
|
|
33
|
+
saveDevice(fresh);
|
|
34
|
+
return fresh.id;
|
|
35
|
+
}
|
|
36
|
+
function safeHostname() {
|
|
37
|
+
const raw = hostname() || 'unknown';
|
|
38
|
+
return raw
|
|
39
|
+
.replace(/\.local$/i, '')
|
|
40
|
+
.replace(/[^A-Za-z0-9_\-]/g, '-')
|
|
41
|
+
.slice(0, 32) || 'unknown';
|
|
42
|
+
}
|
|
43
|
+
export function getDeviceKeyName() {
|
|
44
|
+
const id = getDeviceId();
|
|
45
|
+
const short = id.replace(/-/g, '').slice(0, 8);
|
|
46
|
+
return `CLI \u00b7 ${safeHostname()} \u00b7 ${short}`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/lib/device.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAOpD,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAe,CAAC;QAC5E,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACvE,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAkB;IACpC,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,EAAE,CAAC;IACjC,MAAM,KAAK,GAAe,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IACrF,UAAU,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,EAAE,CAAC;AAClB,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,GAAG,GAAG,QAAQ,EAAE,IAAI,SAAS,CAAC;IACpC,OAAO,GAAG;SACP,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC;SAChC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,OAAO,cAAc,YAAY,EAAE,WAAW,KAAK,EAAE,CAAC;AACxD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@somewhere-tech/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI for somewhere.tech — auth, projects, deploy, logs, env.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "CLI for somewhere.tech — auth, projects, deploy, logs, env, MCP bridge.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"somewhere",
|
|
7
7
|
"somewhere.tech",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"homepage": "https://somewhere.tech",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/
|
|
15
|
+
"url": "git+https://github.com/Somewhere-Tech/somewhere-cli.git"
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"author": "somewhere.tech",
|
|
@@ -36,15 +36,16 @@
|
|
|
36
36
|
"node": ">=18"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
|
-
"
|
|
41
|
+
"commander": "^12.0.0",
|
|
42
42
|
"open": "^10.0.0",
|
|
43
|
+
"ora": "^8.0.0",
|
|
43
44
|
"prompts": "^2.4.2"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"typescript": "^5.4.0",
|
|
47
47
|
"@types/node": "^20.0.0",
|
|
48
|
-
"@types/prompts": "^2.4.0"
|
|
48
|
+
"@types/prompts": "^2.4.0",
|
|
49
|
+
"typescript": "^5.4.0"
|
|
49
50
|
}
|
|
50
51
|
}
|