@somewhere-tech/cli 0.27.7 → 0.28.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 +20 -0
- package/dist/commands/advisor.js +2 -67
- package/dist/commands/advisor.js.map +1 -1
- package/dist/commands/call.js +62 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/feedback.js +75 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/git.js +265 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/grep.js +55 -0
- package/dist/commands/grep.js.map +1 -0
- package/dist/commands/mcp.js +10 -41
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/status.js +36 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/tasks.js +195 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/commands/usage.js +46 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/platform-command.js +32 -0
- package/dist/lib/platform-command.js.map +1 -0
- package/dist/lib/platform-tools.js +163 -0
- package/dist/lib/platform-tools.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { ApiClient } from './client.js';
|
|
2
|
+
import { getToken, loadConfig } from './config.js';
|
|
3
|
+
const MCP_BASE_URL = process.env.SOMEWHERE_MCP_URL?.replace(/\/$/, '') || 'https://mcp.somewhere.tech/mcp';
|
|
4
|
+
let isSdkAuthError = () => false;
|
|
5
|
+
export class PlatformToolError extends Error {
|
|
6
|
+
tool;
|
|
7
|
+
constructor(tool, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.tool = tool;
|
|
10
|
+
this.name = 'PlatformToolError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function mcpUrl(allTools) {
|
|
14
|
+
const url = new URL(MCP_BASE_URL);
|
|
15
|
+
if (allTools)
|
|
16
|
+
url.searchParams.set('groups', 'all');
|
|
17
|
+
return url;
|
|
18
|
+
}
|
|
19
|
+
export function mcpAccessExpiresSoon() {
|
|
20
|
+
const config = loadConfig();
|
|
21
|
+
if (!config?.refresh_token || !config.access_expires_at)
|
|
22
|
+
return false;
|
|
23
|
+
const expiresAt = Date.parse(config.access_expires_at);
|
|
24
|
+
return Number.isFinite(expiresAt) && expiresAt <= Date.now() + 60_000;
|
|
25
|
+
}
|
|
26
|
+
/** Reuse ApiClient's canonical cli-pair rotation and persistence path. */
|
|
27
|
+
export async function refreshMcpAccessToken(preemptive) {
|
|
28
|
+
const token = getToken();
|
|
29
|
+
const client = new ApiClient(token);
|
|
30
|
+
if (preemptive) {
|
|
31
|
+
const refreshed = await client.refreshAccessKey(10_000);
|
|
32
|
+
if (!refreshed) {
|
|
33
|
+
throw new Error('Session renewal returned an incomplete credential pair.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
await client.call('GET', '/auth/whoami', undefined, undefined, { timeoutMs: 10_000 });
|
|
38
|
+
}
|
|
39
|
+
return getToken();
|
|
40
|
+
}
|
|
41
|
+
export function isMcpAuthRejection(err) {
|
|
42
|
+
if (isSdkAuthError(err))
|
|
43
|
+
return true;
|
|
44
|
+
if (!(err instanceof Error))
|
|
45
|
+
return false;
|
|
46
|
+
const candidate = err;
|
|
47
|
+
return candidate.code === 401;
|
|
48
|
+
}
|
|
49
|
+
export async function createPlatformMcpTransport(token, options = {}) {
|
|
50
|
+
const [{ StreamableHTTPClientTransport, StreamableHTTPError }, { UnauthorizedError }] = await Promise.all([
|
|
51
|
+
import('@modelcontextprotocol/sdk/client/streamableHttp.js'),
|
|
52
|
+
import('@modelcontextprotocol/sdk/client/auth.js'),
|
|
53
|
+
]);
|
|
54
|
+
isSdkAuthError = (err) => err instanceof UnauthorizedError
|
|
55
|
+
|| (err instanceof StreamableHTTPError && err.code === 401);
|
|
56
|
+
return new StreamableHTTPClientTransport(mcpUrl(options.allTools === true), {
|
|
57
|
+
requestInit: {
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${token}`,
|
|
60
|
+
...(options.userAgent ? { 'User-Agent': options.userAgent } : {}),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function connectClient(token, options) {
|
|
66
|
+
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
67
|
+
const client = new Client({ name: 'somewhere-cli', version: 'unknown' });
|
|
68
|
+
const transport = await createPlatformMcpTransport(token, {
|
|
69
|
+
...options,
|
|
70
|
+
userAgent: 'somewhere-cli',
|
|
71
|
+
});
|
|
72
|
+
await client.connect(transport);
|
|
73
|
+
return {
|
|
74
|
+
client,
|
|
75
|
+
close: async () => {
|
|
76
|
+
await client.close().catch(() => { });
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function withPlatformClient(options, operation) {
|
|
81
|
+
let token = getToken();
|
|
82
|
+
if (mcpAccessExpiresSoon())
|
|
83
|
+
token = await refreshMcpAccessToken(true);
|
|
84
|
+
const attempt = async (accessToken) => {
|
|
85
|
+
const connection = await connectClient(accessToken, options);
|
|
86
|
+
try {
|
|
87
|
+
return await operation(connection.client);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
await connection.close();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
return await attempt(token);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (!isMcpAuthRejection(err))
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
token = await refreshMcpAccessToken(false);
|
|
101
|
+
return attempt(token);
|
|
102
|
+
}
|
|
103
|
+
export async function listPlatformTools(options = {}) {
|
|
104
|
+
return withPlatformClient(options, async (client) => {
|
|
105
|
+
const result = await client.listTools();
|
|
106
|
+
return result.tools;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function textFromResult(result) {
|
|
110
|
+
return result.content
|
|
111
|
+
.filter((block) => block.type === 'text')
|
|
112
|
+
.map((block) => block.text)
|
|
113
|
+
.join('\n');
|
|
114
|
+
}
|
|
115
|
+
function toolErrorMessage(text) {
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(text);
|
|
118
|
+
const message = typeof parsed.message === 'string' ? parsed.message : text;
|
|
119
|
+
const code = typeof parsed.error === 'string' ? `${parsed.error}: ` : '';
|
|
120
|
+
const next = typeof parsed.next_step === 'string'
|
|
121
|
+
? parsed.next_step
|
|
122
|
+
: typeof parsed.hint === 'string'
|
|
123
|
+
? parsed.hint
|
|
124
|
+
: null;
|
|
125
|
+
return `${code}${message}${next ? ` Next: ${next}` : ''}`;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return text;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export async function callPlatformToolRaw(name, args, options = {}) {
|
|
132
|
+
const result = await withPlatformClient(options, (client) => client.callTool({ name, arguments: args }));
|
|
133
|
+
const typed = result;
|
|
134
|
+
if (typed.isError) {
|
|
135
|
+
throw new PlatformToolError(name, toolErrorMessage(textFromResult(typed)));
|
|
136
|
+
}
|
|
137
|
+
return typed;
|
|
138
|
+
}
|
|
139
|
+
export function platformToolResultValue(result) {
|
|
140
|
+
if (result.structuredContent !== undefined)
|
|
141
|
+
return result.structuredContent;
|
|
142
|
+
const text = textFromResult(result);
|
|
143
|
+
if (text) {
|
|
144
|
+
try {
|
|
145
|
+
return JSON.parse(text);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return text;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return result.content;
|
|
152
|
+
}
|
|
153
|
+
export async function callPlatformTool(name, args, options = {}) {
|
|
154
|
+
return platformToolResultValue(await callPlatformToolRaw(name, args, options));
|
|
155
|
+
}
|
|
156
|
+
export async function callPlatformHelpTool(name, args) {
|
|
157
|
+
const result = await callPlatformToolRaw(name, args);
|
|
158
|
+
const text = textFromResult(result);
|
|
159
|
+
if (!text)
|
|
160
|
+
throw new PlatformToolError(name, `${name} returned an empty response.`);
|
|
161
|
+
return text;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=platform-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-tools.js","sourceRoot":"","sources":["../../src/lib/platform-tools.ts"],"names":[],"mappings":"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"}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@somewhere-tech/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@somewhere-tech/cli",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.28.0",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"@modelcontextprotocol/sdk",
|
|
12
12
|
"chokidar",
|