@inquir/compute-cli 0.3.0 → 0.4.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 +223 -114
- package/dist/commands/admin-tenants.d.ts +11 -0
- package/dist/commands/admin-tenants.d.ts.map +1 -0
- package/dist/commands/admin-tenants.js +318 -0
- package/dist/commands/admin-tenants.js.map +1 -0
- package/dist/commands/admin.d.ts +2 -0
- package/dist/commands/admin.d.ts.map +1 -0
- package/dist/commands/admin.js +445 -0
- package/dist/commands/admin.js.map +1 -0
- package/dist/commands/apps-describe.d.ts +9 -0
- package/dist/commands/apps-describe.d.ts.map +1 -0
- package/dist/commands/apps-describe.js +118 -0
- package/dist/commands/apps-describe.js.map +1 -0
- package/dist/commands/apps-observability.d.ts +9 -0
- package/dist/commands/apps-observability.d.ts.map +1 -0
- package/dist/commands/apps-observability.js +281 -0
- package/dist/commands/apps-observability.js.map +1 -0
- package/dist/commands/apps-promote.d.ts +31 -0
- package/dist/commands/apps-promote.d.ts.map +1 -0
- package/dist/commands/apps-promote.js +115 -0
- package/dist/commands/apps-promote.js.map +1 -0
- package/dist/commands/apps-resources.d.ts +6 -0
- package/dist/commands/apps-resources.d.ts.map +1 -0
- package/dist/commands/apps-resources.js +107 -0
- package/dist/commands/apps-resources.js.map +1 -0
- package/dist/commands/apps.d.ts +25 -2
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +434 -66
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +7 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +10 -2
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +78 -33
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +37 -5
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/mcp.d.ts +13 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +184 -77
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/projects.d.ts.map +1 -1
- package/dist/commands/projects.js +107 -11
- package/dist/commands/projects.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/finite-source-command-client.d.ts +3 -0
- package/dist/lib/finite-source-command-client.d.ts.map +1 -0
- package/dist/lib/finite-source-command-client.js +3 -0
- package/dist/lib/finite-source-command-client.js.map +1 -0
- package/dist/lib/mcp-io.d.ts +23 -0
- package/dist/lib/mcp-io.d.ts.map +1 -0
- package/dist/lib/mcp-io.js +185 -0
- package/dist/lib/mcp-io.js.map +1 -0
- package/dist/lib/mcp-source-commands.d.ts +17 -0
- package/dist/lib/mcp-source-commands.d.ts.map +1 -0
- package/dist/lib/mcp-source-commands.js +345 -0
- package/dist/lib/mcp-source-commands.js.map +1 -0
- package/dist/utils/api.d.ts +19 -10
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +22 -4
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/apps-presentation.d.ts +1 -1
- package/dist/utils/apps-presentation.d.ts.map +1 -1
- package/dist/utils/apps-presentation.js +10 -0
- package/dist/utils/apps-presentation.js.map +1 -1
- package/dist/utils/auth.d.ts +21 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +119 -22
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/browser.d.ts +12 -0
- package/dist/utils/browser.d.ts.map +1 -1
- package/dist/utils/browser.js +37 -16
- package/dist/utils/browser.js.map +1 -1
- package/dist/utils/package-metadata.js +1 -1
- package/dist/utils/project-context.d.ts.map +1 -1
- package/dist/utils/project-context.js +7 -5
- package/dist/utils/project-context.js.map +1 -1
- package/dist/utils/project-lookup.d.ts +10 -0
- package/dist/utils/project-lookup.d.ts.map +1 -0
- package/dist/utils/project-lookup.js +52 -0
- package/dist/utils/project-lookup.js.map +1 -0
- package/package.json +10 -10
- package/skill/SKILL.md +9 -3
package/dist/commands/login.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
|
-
import { startCliAuth, pollCliAuth } from '../sdk.js';
|
|
3
|
-
import { resolveAuthConfig, DEFAULT_API_URL, sameApiEndpoint, updateEnvironmentConfig, } from '../utils/auth.js';
|
|
2
|
+
import { startCliAuth, pollCliAuth, logoutCliAuth } from '../sdk.js';
|
|
3
|
+
import { resolveAuthConfig, DEFAULT_API_URL, sameApiEndpoint, updateEnvironmentConfig, cliSession, ownedCliSession, configReferencesToken, } from '../utils/auth.js';
|
|
4
4
|
import { getMe } from '../utils/api.js';
|
|
5
5
|
import { openBrowser } from '../utils/browser.js';
|
|
6
6
|
import { hasFlag, readEnvironmentFlag, readFlagValue, } from '../utils/args.js';
|
|
@@ -43,38 +43,73 @@ function startLoopback() {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
-
async function persistLogin(environment, apiUrl, token, user) {
|
|
46
|
+
async function persistLogin(environment, apiUrl, token, user, session) {
|
|
47
47
|
let previousWorkspace;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
let persisted = false;
|
|
49
|
+
try {
|
|
50
|
+
await updateEnvironmentConfig(environment, (slice, config) => {
|
|
51
|
+
const previousSession = ownedCliSession(slice);
|
|
52
|
+
const previousToken = slice.token;
|
|
53
|
+
const previousApiUrl = slice.apiUrl ?? config.apiUrl ?? DEFAULT_API_URL;
|
|
54
|
+
const sameApi = sameApiEndpoint(previousApiUrl, apiUrl);
|
|
55
|
+
if (!sameApi && slice === config) {
|
|
56
|
+
// Changing the default must not silently retarget another profile's
|
|
57
|
+
// existing credentials or workspace that used to inherit this API.
|
|
58
|
+
for (const profile of Object.values(config.environments ?? {})) {
|
|
59
|
+
if (profile && typeof profile === 'object' && !Array.isArray(profile) && profile.apiUrl == null &&
|
|
60
|
+
[profile.token, profile.apiKey, profile.workspaceId, profile.user].some((value) => value !== undefined)) {
|
|
61
|
+
profile.apiUrl = previousApiUrl;
|
|
62
|
+
}
|
|
58
63
|
}
|
|
59
64
|
}
|
|
65
|
+
if (sameApi)
|
|
66
|
+
previousWorkspace = slice.workspaceId;
|
|
67
|
+
if (!sameApi)
|
|
68
|
+
delete slice.apiKey;
|
|
69
|
+
if (!sameApi || slice.token !== token) {
|
|
70
|
+
// An empty selector also prevents a new named profile from inheriting a
|
|
71
|
+
// different account's default workspace while discovery is unavailable.
|
|
72
|
+
slice.workspaceId = '';
|
|
73
|
+
delete slice.user;
|
|
74
|
+
}
|
|
75
|
+
// A credential must keep the API that issued it when later commands no
|
|
76
|
+
// longer carry the login-only --api-url override.
|
|
77
|
+
slice.apiUrl = apiUrl;
|
|
78
|
+
slice.token = token;
|
|
79
|
+
delete slice.loggedOut;
|
|
80
|
+
if (session)
|
|
81
|
+
slice.tokenSession = session;
|
|
82
|
+
else
|
|
83
|
+
delete slice.tokenSession;
|
|
84
|
+
if (user)
|
|
85
|
+
slice.user = user;
|
|
86
|
+
return previousSession && previousToken && previousToken !== token
|
|
87
|
+
? { session: previousSession, token: previousToken } : undefined;
|
|
88
|
+
}, async (previous, config) => {
|
|
89
|
+
persisted = true;
|
|
90
|
+
// The replacement is durable before the old session can be revoked. The
|
|
91
|
+
// same config lock prevents another CLI process from adopting it meanwhile.
|
|
92
|
+
if (!previous || configReferencesToken(config, previous.token))
|
|
93
|
+
return;
|
|
94
|
+
try {
|
|
95
|
+
await logoutCliAuth(previous.session.apiUrl, previous.token);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
printWarning('The new login was saved, but the previous CLI session could not be revoked. Revoke it in Settings → Access tokens.');
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (session && !persisted) {
|
|
104
|
+
try {
|
|
105
|
+
await logoutCliAuth(apiUrl, token);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
printWarning('Login could not be saved and its CLI session could not be revoked. Revoke it in Settings → Access tokens.');
|
|
109
|
+
}
|
|
60
110
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (!sameApi)
|
|
64
|
-
delete slice.apiKey;
|
|
65
|
-
if (!sameApi || slice.token !== token) {
|
|
66
|
-
// An empty selector also prevents a new named profile from inheriting a
|
|
67
|
-
// different account's default workspace while discovery is unavailable.
|
|
68
|
-
slice.workspaceId = '';
|
|
69
|
-
delete slice.user;
|
|
70
|
-
}
|
|
71
|
-
// A credential must keep the API that issued it when later commands no
|
|
72
|
-
// longer carry the login-only --api-url override.
|
|
73
|
-
slice.apiUrl = apiUrl;
|
|
74
|
-
slice.token = token;
|
|
75
|
-
if (user)
|
|
76
|
-
slice.user = user;
|
|
77
|
-
});
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
78
113
|
return previousWorkspace;
|
|
79
114
|
}
|
|
80
115
|
/** Fetch identity with the freshly-minted token and store the default workspace. */
|
|
@@ -88,7 +123,10 @@ async function finalizeWorkspace(environment, apiUrl, token, previousWorkspace)
|
|
|
88
123
|
// again without them could let ambient API/token variables redirect the
|
|
89
124
|
// identity request away from the endpoint the user just authenticated.
|
|
90
125
|
const me = await getMe({ environment, apiUrl, token, ignoreStoredWorkspace: true });
|
|
91
|
-
await updateEnvironmentConfig(environment, (slice) => {
|
|
126
|
+
const applied = await updateEnvironmentConfig(environment, (slice) => {
|
|
127
|
+
// A slow discovery response must not overwrite a newer login or logout.
|
|
128
|
+
if (slice.loggedOut || slice.token !== token || !sameApiEndpoint(slice.apiUrl ?? DEFAULT_API_URL, apiUrl))
|
|
129
|
+
return false;
|
|
92
130
|
// Heal a missing OR stale active workspace: only keep the stored selector
|
|
93
131
|
// when it still maps to a workspace the user belongs to.
|
|
94
132
|
const validSelectors = new Set(me.workspaces.flatMap((ws) => [ws.id, ws.slug]).filter((value) => Boolean(value)));
|
|
@@ -98,7 +136,10 @@ async function finalizeWorkspace(environment, apiUrl, token, previousWorkspace)
|
|
|
98
136
|
: me.activeWorkspace?.id ?? '';
|
|
99
137
|
if (me.user)
|
|
100
138
|
slice.user = { id: me.user.id, email: me.user.email, name: me.user.name };
|
|
139
|
+
return true;
|
|
101
140
|
});
|
|
141
|
+
if (!applied)
|
|
142
|
+
return;
|
|
102
143
|
if (me.activeWorkspace) {
|
|
103
144
|
printLine(`Active workspace: ${bold(me.activeWorkspace.name)} (${me.activeWorkspace.slug || me.activeWorkspace.id})`);
|
|
104
145
|
}
|
|
@@ -141,7 +182,10 @@ export async function loginCommand(args) {
|
|
|
141
182
|
const deviceName = readFlagValue(args, '--name') ?? defaultDeviceName();
|
|
142
183
|
const browserless = hasFlag(args, '--browserless') || hasFlag(args, '--no-browser');
|
|
143
184
|
const loopback = browserless ? null : await startLoopback();
|
|
144
|
-
const pairing = await startCliAuth(apiUrl, { name: deviceName, port: loopback?.port || undefined })
|
|
185
|
+
const pairing = await startCliAuth(apiUrl, { name: deviceName, port: loopback?.port || undefined }).catch((error) => {
|
|
186
|
+
loopback?.close();
|
|
187
|
+
throw error;
|
|
188
|
+
});
|
|
145
189
|
const verificationUrl = absoluteVerificationUrl(pairing.verificationUrl, apiUrl);
|
|
146
190
|
printLine('');
|
|
147
191
|
printLine(`To authorize this device, open:`);
|
|
@@ -181,7 +225,8 @@ export async function loginCommand(args) {
|
|
|
181
225
|
});
|
|
182
226
|
if (result.status === 'approved') {
|
|
183
227
|
const user = { id: result.user.id, email: result.user.email, name: result.user.name };
|
|
184
|
-
const
|
|
228
|
+
const session = cliSession(apiUrl, result.token, { tokenId: result.tokenId, expiresAt: result.expiresAt });
|
|
229
|
+
const previousWorkspace = await persistLogin(environment, apiUrl, result.token, user, session);
|
|
185
230
|
const who = user.name || user.email || user.id;
|
|
186
231
|
printSuccess(`Logged in as ${who}.`);
|
|
187
232
|
await finalizeWorkspace(environment, apiUrl, result.token, previousWorkspace);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAKA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CjE"}
|
package/dist/commands/logout.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { readEnvironmentFlag, hasFlag } from '../utils/args.js';
|
|
2
|
-
import { updateEnvironmentConfig } from '../utils/auth.js';
|
|
3
|
-
import {
|
|
2
|
+
import { configReferencesToken, ownedCliSession, updateEnvironmentConfig } from '../utils/auth.js';
|
|
3
|
+
import { logoutCliAuth } from '../sdk.js';
|
|
4
|
+
import { printCommandHelp, printSuccess, printWarning } from '../utils/output.js';
|
|
4
5
|
export async function logoutCommand(args) {
|
|
5
6
|
if (hasFlag(args, '--help') || hasFlag(args, '-h')) {
|
|
6
7
|
printCommandHelp('logout', 'logout [options]', [
|
|
7
|
-
'--env <name>
|
|
8
|
+
'--env <name> Log out a named environment and revoke its CLI session',
|
|
8
9
|
], [
|
|
9
10
|
'inquir logout',
|
|
10
11
|
'inquir logout --env staging',
|
|
@@ -12,11 +13,42 @@ export async function logoutCommand(args) {
|
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
const environment = readEnvironmentFlag(args);
|
|
15
|
-
await updateEnvironmentConfig(environment, (slice) => {
|
|
16
|
+
const outcome = await updateEnvironmentConfig(environment, async (slice, config) => {
|
|
17
|
+
const session = ownedCliSession(slice);
|
|
18
|
+
let result = slice.token ? 'unmanaged' : 'none';
|
|
19
|
+
if (slice.token && session) {
|
|
20
|
+
if (configReferencesToken(config, slice.token, slice))
|
|
21
|
+
result = 'shared';
|
|
22
|
+
else {
|
|
23
|
+
try {
|
|
24
|
+
// Never resolve ambient API/token/workspace settings for revocation.
|
|
25
|
+
await logoutCliAuth(session.apiUrl, slice.token);
|
|
26
|
+
result = 'revoked';
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
result = 'failed';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
16
33
|
delete slice.token;
|
|
34
|
+
delete slice.tokenSession;
|
|
35
|
+
delete slice.apiKey;
|
|
17
36
|
delete slice.user;
|
|
18
37
|
delete slice.workspaceId;
|
|
38
|
+
slice.loggedOut = true;
|
|
39
|
+
return result;
|
|
19
40
|
});
|
|
20
|
-
printSuccess(
|
|
41
|
+
printSuccess(outcome === 'revoked'
|
|
42
|
+
? 'Logged out. The CLI session was revoked and local credentials were cleared.'
|
|
43
|
+
: 'Logged out locally. Stored credentials and active workspace were cleared.');
|
|
44
|
+
if (outcome === 'failed')
|
|
45
|
+
printWarning('Server revocation could not be confirmed. The CLI session may still be active; revoke it in Settings → Access tokens.');
|
|
46
|
+
if (outcome === 'shared')
|
|
47
|
+
printWarning('The token is also used by another profile or environment variable, so it was not revoked.');
|
|
48
|
+
if (outcome === 'unmanaged')
|
|
49
|
+
printWarning('Imported or older tokens are not automatically revoked. Revoke this token in Settings → Access tokens if it is no longer needed.');
|
|
50
|
+
if ([process.env.INQUIR_TOKEN, process.env.INQUIR_API_KEY, process.env.LAMBDA_API_KEY].some((value) => value?.trim())) {
|
|
51
|
+
printWarning('Credentials from environment variables remain active. Unset them to finish logging out of this shell.');
|
|
52
|
+
}
|
|
21
53
|
}
|
|
22
54
|
//# sourceMappingURL=logout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc;IAChD,IAAI,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACnD,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,EAAE;YAC7C,uEAAuE;SACxE,EAAE;YACD,eAAe;YACf,6BAA6B;SAC9B,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QACjF,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,MAAM,GAA2D,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC;QACxG,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC;gBAAE,MAAM,GAAG,QAAQ,CAAC;iBACpE,CAAC;gBACJ,IAAI,CAAC;oBACH,qEAAqE;oBACrE,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBACjD,MAAM,GAAG,SAAS,CAAC;gBACrB,CAAC;gBAAC,MAAM,CAAC;oBAAC,MAAM,GAAG,QAAQ,CAAC;gBAAC,CAAC;YAChC,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;QACnB,OAAO,KAAK,CAAC,YAAY,CAAC;QAC1B,OAAO,KAAK,CAAC,MAAM,CAAC;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC;QAClB,OAAO,KAAK,CAAC,WAAW,CAAC;QACzB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,YAAY,CAAC,OAAO,KAAK,SAAS;QAChC,CAAC,CAAC,6EAA6E;QAC/E,CAAC,CAAC,2EAA2E,CAAC,CAAC;IACjF,IAAI,OAAO,KAAK,QAAQ;QAAE,YAAY,CAAC,uHAAuH,CAAC,CAAC;IAChK,IAAI,OAAO,KAAK,QAAQ;QAAE,YAAY,CAAC,2FAA2F,CAAC,CAAC;IACpI,IAAI,OAAO,KAAK,WAAW;QAAE,YAAY,CAAC,kIAAkI,CAAC,CAAC;IAC9K,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACtH,YAAY,CAAC,uGAAuG,CAAC,CAAC;IACxH,CAAC;AACH,CAAC"}
|
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -11,5 +11,18 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Register (Claude Code): claude mcp add inquir -- inquir mcp
|
|
13
13
|
*/
|
|
14
|
+
import { type ApiRequestOptions } from '../utils/api.js';
|
|
15
|
+
import { type McpSourceCommands } from '../lib/mcp-source-commands.js';
|
|
16
|
+
/** Requests run independently so cancellation notifications and control tools
|
|
17
|
+
* can be consumed while a GET observation or deployment is waiting.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createMcpDispatcher(apiOptions: ApiRequestOptions, options: {
|
|
20
|
+
write(message: Record<string, unknown>): void | Promise<void>;
|
|
21
|
+
sources?: McpSourceCommands;
|
|
22
|
+
sourceSession?: string;
|
|
23
|
+
}): ((line: string) => Promise<void>) & {
|
|
24
|
+
close: (error: Error) => void;
|
|
25
|
+
drain(): Promise<void>;
|
|
26
|
+
};
|
|
14
27
|
export declare function mcpCommand(args: string[]): Promise<void>;
|
|
15
28
|
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAWL,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAOzB,OAAO,EAA2B,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AA0NhG;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE;IAC1E,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACpH,WAM+B,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;mBAD9B,KAAK;;EA4D5B;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B9D"}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -12,14 +12,16 @@
|
|
|
12
12
|
* Register (Claude Code): claude mcp add inquir -- inquir mcp
|
|
13
13
|
*/
|
|
14
14
|
import path from 'node:path';
|
|
15
|
-
import
|
|
16
|
-
import { createZipBase64, rawRequest } from '@inquir/compute';
|
|
15
|
+
import { createZipBase64, rawRequest, createClient, getMe, listRemoteFunctions as listFunctionsWithClient, resolveRemoteFunction as resolveFunctionWithClient } from '@inquir/compute';
|
|
17
16
|
import { createApiClient, createRemoteFunction, getDeployStatus, invokeRemote, listRemoteFunctions, listRemoteInvocations, queueDeploy, resolveRemoteFunction, rollbackDeploy, updateRemoteFunction, } from '../utils/api.js';
|
|
18
17
|
import { buildApiOptions } from '../utils/context.js';
|
|
19
18
|
import { isTerminalDeployStatus } from '../sdk.js';
|
|
20
19
|
import { detectApp } from '../utils/detect.js';
|
|
21
|
-
import { hasFlag } from '../utils/args.js';
|
|
20
|
+
import { hasFlag, readFlagValue } from '../utils/args.js';
|
|
22
21
|
import { printCommandHelp } from '../utils/output.js';
|
|
22
|
+
import { redact } from '../utils/redact.js';
|
|
23
|
+
import { createMcpSourceCommands } from '../lib/mcp-source-commands.js';
|
|
24
|
+
import { boundedMcpFetch, createMcpWriter, readMcpLines, MCP_FRAME_BYTES } from '../lib/mcp-io.js';
|
|
23
25
|
const PROTOCOL_VERSION = '2024-11-05';
|
|
24
26
|
const SERVER_INFO = { name: 'inquir', version: '0.1.0' };
|
|
25
27
|
/** Wait for a queued deploy to reach a terminal status (poll, no SSE). */
|
|
@@ -104,9 +106,9 @@ const TOOLS = [
|
|
|
104
106
|
},
|
|
105
107
|
{
|
|
106
108
|
name: 'exec',
|
|
107
|
-
description: '
|
|
108
|
-
'
|
|
109
|
-
'
|
|
109
|
+
description: 'Submit a command against a private snapshot of function source (default target). Source requires a caller-retained UUID requestId; ' +
|
|
110
|
+
'returns asynchronous execution identity. Observe with source_command_status and explicitly publish with source_command_reconcile. ' +
|
|
111
|
+
'Unavailable finite execution never falls back to writable source mounts. target "release" executes against the deployed release read-only.',
|
|
110
112
|
inputSchema: {
|
|
111
113
|
type: 'object',
|
|
112
114
|
properties: {
|
|
@@ -114,20 +116,52 @@ const TOOLS = [
|
|
|
114
116
|
command: { type: 'string', description: 'Shell command (sh -c)' },
|
|
115
117
|
timeoutMs: { type: 'number', description: 'Timeout in ms (default 60000, max 900000)' },
|
|
116
118
|
target: { type: 'string', enum: ['source', 'release'] },
|
|
119
|
+
requestId: { type: 'string', format: 'uuid', description: 'Required for source: retain one lowercase UUID v4 per intent before calling; reuse for uncertain replies' },
|
|
120
|
+
env: { type: 'object', additionalProperties: { type: 'string' }, description: 'Source command environment overrides' },
|
|
117
121
|
},
|
|
118
122
|
required: ['function', 'command'],
|
|
123
|
+
anyOf: [{ properties: { target: { const: 'release' } }, required: ['target'] }, { required: ['requestId'] }],
|
|
119
124
|
additionalProperties: false,
|
|
120
125
|
},
|
|
121
|
-
handler: async (args, apiOptions) => {
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
handler: async (args, apiOptions, context) => {
|
|
127
|
+
if (args.target === undefined || args.target === 'source')
|
|
128
|
+
return context.sources.execute(args, context.id, context.signal);
|
|
129
|
+
if (args.target !== 'release')
|
|
130
|
+
throw new Error('Invalid exec target');
|
|
131
|
+
if (args.env !== undefined || args.requestId !== undefined)
|
|
132
|
+
throw new Error('env and requestId apply only to source commands');
|
|
133
|
+
const resolved = await createApiClient(apiOptions), identity = await getMe(resolved);
|
|
134
|
+
const client = createClient({ baseUrl: resolved.baseUrl, apiKey: resolved.apiKey,
|
|
135
|
+
workspaceId: identity.activeWorkspace.id, fetchImpl: resolved.fetchImpl });
|
|
136
|
+
const identifier = String(args.function), functions = await listFunctionsWithClient(client);
|
|
137
|
+
const fn = functions.find(item => item.id === identifier) ?? await resolveFunctionWithClient(client, identifier);
|
|
124
138
|
return rawRequest(client, 'POST', `/functions/${fn.id}/exec`, {
|
|
125
139
|
command: String(args.command),
|
|
126
140
|
...(typeof args.timeoutMs === 'number' ? { timeoutMs: args.timeoutMs } : {}),
|
|
127
|
-
|
|
141
|
+
target: 'release',
|
|
128
142
|
});
|
|
129
143
|
},
|
|
130
144
|
},
|
|
145
|
+
...['status', 'reconcile', 'cancel'].map(action => ({
|
|
146
|
+
name: `source_command_${action}`,
|
|
147
|
+
description: action === 'status' ? 'Read retained source command state/output. Optional waitMs polls GET only; stopping observation does not cancel execution.'
|
|
148
|
+
: action === 'reconcile' ? 'Explicitly reconcile retained output with its original source snapshot. Returns APPLIED, CONFLICT or output refusal; never re-executes the command.'
|
|
149
|
+
: 'Request durable cancellation of a retained source command. CANCEL_REQUESTED is intent, not stopped execution or released capacity; publication may already be committed.',
|
|
150
|
+
inputSchema: { type: 'object', properties: { requestId: { type: 'string', format: 'uuid' },
|
|
151
|
+
...(action === 'status' ? { waitMs: { type: 'integer', minimum: 0, maximum: 900000 } } : {}) }, required: ['requestId'], additionalProperties: false },
|
|
152
|
+
handler: async (args, _apiOptions, context) => context.sources.action(action, args, context.signal),
|
|
153
|
+
})),
|
|
154
|
+
{
|
|
155
|
+
name: 'source_command_resume',
|
|
156
|
+
description: 'Resume a locally retained UUID after reconnect/restart. status only observes; submit explicitly retries the SAME saved command, input and UUID after an uncertain submission. Never generates another execution identity.',
|
|
157
|
+
inputSchema: { type: 'object', properties: { requestId: { type: 'string', format: 'uuid' }, action: { type: 'string', enum: ['status', 'submit'] } },
|
|
158
|
+
required: ['requestId', 'action'], additionalProperties: false },
|
|
159
|
+
handler: async (args, _apiOptions, context) => {
|
|
160
|
+
if (Object.keys(args).some(key => !['requestId', 'action'].includes(key)) || !['status', 'submit'].includes(String(args.action)))
|
|
161
|
+
throw new Error('Invalid source resume action');
|
|
162
|
+
return context.sources.action(args.action, { requestId: args.requestId }, context.signal);
|
|
163
|
+
},
|
|
164
|
+
},
|
|
131
165
|
{
|
|
132
166
|
name: 'list_invocations',
|
|
133
167
|
description: 'Recent invocations for a function (status, duration, errors, logs) — the debugging entry point.',
|
|
@@ -181,7 +215,126 @@ function toolResult(value) {
|
|
|
181
215
|
};
|
|
182
216
|
}
|
|
183
217
|
function toolError(message) {
|
|
184
|
-
return { content: [{ type: 'text', text: message }], isError: true };
|
|
218
|
+
return { content: [{ type: 'text', text: redact(message) }], isError: true };
|
|
219
|
+
}
|
|
220
|
+
/** Requests run independently so cancellation notifications and control tools
|
|
221
|
+
* can be consumed while a GET observation or deployment is waiting.
|
|
222
|
+
*/
|
|
223
|
+
export function createMcpDispatcher(apiOptions, options) {
|
|
224
|
+
const sources = options.sources ?? createMcpSourceCommands({ getClient: () => createApiClient(apiOptions), namespace: options.sourceSession });
|
|
225
|
+
const active = new Map();
|
|
226
|
+
let heavy = 0, control = 0, deployment = 0, closed;
|
|
227
|
+
const keyOf = (id) => `${typeof id}:${id}`;
|
|
228
|
+
const close = (error) => { closed ??= error; for (const entry of active.values())
|
|
229
|
+
entry.controller.abort(error); };
|
|
230
|
+
const dispatch = async (line) => {
|
|
231
|
+
if (closed)
|
|
232
|
+
return;
|
|
233
|
+
if (Buffer.byteLength(line) > MCP_FRAME_BYTES) {
|
|
234
|
+
close(new Error('MCP input frame exceeds 64KiB'));
|
|
235
|
+
throw closed;
|
|
236
|
+
}
|
|
237
|
+
let request;
|
|
238
|
+
try {
|
|
239
|
+
request = JSON.parse(line);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
await options.write({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (!request || request.jsonrpc !== '2.0' || typeof request.method !== 'string'
|
|
246
|
+
|| request.id !== undefined && request.id !== null && (typeof request.id !== 'string' && typeof request.id !== 'number' || typeof request.id === 'number' && !Number.isSafeInteger(request.id))) {
|
|
247
|
+
await options.write({ jsonrpc: '2.0', id: null, error: { code: -32600, message: 'Invalid request' } });
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const { id, method, params } = request;
|
|
251
|
+
if (method === 'notifications/cancelled') {
|
|
252
|
+
const cancelledId = params?.requestId;
|
|
253
|
+
if (typeof cancelledId === 'string' || typeof cancelledId === 'number')
|
|
254
|
+
active.get(keyOf(cancelledId))?.controller.abort(new Error('MCP observation cancelled'));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (id === undefined || id === null)
|
|
258
|
+
return; // Notifications cannot execute tools.
|
|
259
|
+
const key = keyOf(id), body = JSON.stringify(request), existing = active.get(key);
|
|
260
|
+
if (existing) {
|
|
261
|
+
if (existing.body !== body)
|
|
262
|
+
await options.write({ jsonrpc: '2.0', id, error: { code: -32600, message: 'An active request ID cannot identify different input' } });
|
|
263
|
+
// The original accepted request owns its response; duplicates add no waiters.
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const respond = (result) => options.write({ jsonrpc: '2.0', id, result });
|
|
267
|
+
// Protocol controls bypass work admission; output still has bounded backpressure.
|
|
268
|
+
if (method === 'initialize') {
|
|
269
|
+
await respond({ protocolVersion: PROTOCOL_VERSION, capabilities: { tools: {} }, serverInfo: SERVER_INFO });
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (method === 'ping') {
|
|
273
|
+
await respond({});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (method === 'tools/list') {
|
|
277
|
+
await respond({ tools: TOOLS.map(({ name, description, inputSchema }) => ({ name, description, inputSchema })) });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (method !== 'tools/call') {
|
|
281
|
+
await options.write({ jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } });
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const tool = TOOLS.find(item => item.name === String(params?.name ?? ''));
|
|
285
|
+
if (!tool) {
|
|
286
|
+
await respond(toolError(`Unknown tool: ${String(params?.name ?? '')}`));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const args = params?.arguments ?? {};
|
|
290
|
+
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
291
|
+
await respond(toolError('Tool arguments must be an object'));
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const isControl = tool.name.startsWith('source_command_') || tool.name === 'deploy_status';
|
|
295
|
+
const isDeployment = tool.name === 'deploy' || tool.name === 'rollback';
|
|
296
|
+
if (isControl ? control >= 2 : heavy >= 4 || isDeployment && deployment >= 1) {
|
|
297
|
+
await respond(toolError('MCP work limit reached; retain the same source UUID and retry after active work finishes'));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (isControl)
|
|
301
|
+
control++;
|
|
302
|
+
else
|
|
303
|
+
heavy++;
|
|
304
|
+
if (isDeployment)
|
|
305
|
+
deployment++;
|
|
306
|
+
const controller = new AbortController();
|
|
307
|
+
const work = Promise.resolve().then(async () => {
|
|
308
|
+
try {
|
|
309
|
+
controller.signal.throwIfAborted();
|
|
310
|
+
const scopedOptions = { ...apiOptions, fetchImpl: boundedMcpFetch(apiOptions.fetchImpl ?? fetch, controller.signal) };
|
|
311
|
+
try {
|
|
312
|
+
await respond(toolResult(await tool.handler(args, scopedOptions, { id, signal: controller.signal, sources })));
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
await respond(toolError(error instanceof Error ? error.message : 'Tool failed'));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
await options.write({ jsonrpc: '2.0', id, error: { code: -32603, message: redact(error instanceof Error ? error.message : 'Internal error') } });
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
active.set(key, { body, controller, work });
|
|
323
|
+
try {
|
|
324
|
+
await work;
|
|
325
|
+
}
|
|
326
|
+
finally {
|
|
327
|
+
if (active.get(key)?.work === work)
|
|
328
|
+
active.delete(key);
|
|
329
|
+
if (isControl)
|
|
330
|
+
control--;
|
|
331
|
+
else
|
|
332
|
+
heavy--;
|
|
333
|
+
if (isDeployment)
|
|
334
|
+
deployment--;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
return Object.assign(dispatch, { close, async drain() { await Promise.allSettled(Array.from(active.values(), entry => entry.work)); } });
|
|
185
338
|
}
|
|
186
339
|
export async function mcpCommand(args) {
|
|
187
340
|
if (hasFlag(args, '--help') || hasFlag(args, '-h')) {
|
|
@@ -194,75 +347,29 @@ export async function mcpCommand(args) {
|
|
|
194
347
|
]);
|
|
195
348
|
return;
|
|
196
349
|
}
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
request = JSON.parse(trimmed);
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
write({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
|
|
212
|
-
continue;
|
|
350
|
+
let dispatch;
|
|
351
|
+
const writer = createMcpWriter(process.stdout, error => { dispatch?.close(error); process.stdin.destroy(); });
|
|
352
|
+
dispatch = createMcpDispatcher(buildApiOptions(args), { write: writer.write, sourceSession: readFlagValue(args, '--source-session') });
|
|
353
|
+
try {
|
|
354
|
+
for await (const line of readMcpLines(process.stdin)) {
|
|
355
|
+
const trimmed = line.trim();
|
|
356
|
+
if (!trimmed)
|
|
357
|
+
continue;
|
|
358
|
+
// Admission and writer bounds own outstanding work; no unbounded pending set.
|
|
359
|
+
void dispatch(trimmed).catch(error => { dispatch?.close(error instanceof Error ? error : new Error('MCP transport failed')); process.stdin.destroy(); });
|
|
213
360
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (id !== undefined && id !== null)
|
|
222
|
-
write({ jsonrpc: '2.0', id, error: { code, message } });
|
|
223
|
-
};
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
dispatch.close(error instanceof Error ? error : new Error('MCP input failed'));
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
dispatch.close(new Error('MCP input ended; observation stopped, execution is not cancelled'));
|
|
367
|
+
await dispatch.drain();
|
|
224
368
|
try {
|
|
225
|
-
|
|
226
|
-
case 'initialize':
|
|
227
|
-
respond({
|
|
228
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
229
|
-
capabilities: { tools: {} },
|
|
230
|
-
serverInfo: SERVER_INFO,
|
|
231
|
-
});
|
|
232
|
-
break;
|
|
233
|
-
case 'notifications/initialized':
|
|
234
|
-
case 'notifications/cancelled':
|
|
235
|
-
break;
|
|
236
|
-
case 'ping':
|
|
237
|
-
respond({});
|
|
238
|
-
break;
|
|
239
|
-
case 'tools/list':
|
|
240
|
-
respond({
|
|
241
|
-
tools: TOOLS.map(({ name, description, inputSchema }) => ({ name, description, inputSchema })),
|
|
242
|
-
});
|
|
243
|
-
break;
|
|
244
|
-
case 'tools/call': {
|
|
245
|
-
const toolName = String(params?.name ?? '');
|
|
246
|
-
const tool = TOOLS.find((t) => t.name === toolName);
|
|
247
|
-
if (!tool) {
|
|
248
|
-
respond(toolError(`Unknown tool: ${toolName}`));
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
const toolArgs = (params?.arguments ?? {});
|
|
252
|
-
try {
|
|
253
|
-
respond(toolResult(await tool.handler(toolArgs, apiOptions)));
|
|
254
|
-
}
|
|
255
|
-
catch (err) {
|
|
256
|
-
respond(toolError(err instanceof Error ? err.message : String(err)));
|
|
257
|
-
}
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
default:
|
|
261
|
-
respondError(-32601, `Method not found: ${method}`);
|
|
262
|
-
}
|
|
369
|
+
await writer.flush();
|
|
263
370
|
}
|
|
264
|
-
|
|
265
|
-
|
|
371
|
+
finally {
|
|
372
|
+
writer.dispose();
|
|
266
373
|
}
|
|
267
374
|
}
|
|
268
375
|
}
|