@kodycodes/cli 0.0.0 → 1.0.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/LICENSE +21 -0
- package/README.md +62 -1
- package/dist/auth.d.ts +39 -0
- package/dist/auth.js +223 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +5 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +31 -0
- package/dist/cli.js +205 -0
- package/dist/cli.js.map +1 -0
- package/dist/defaults.d.ts +6 -0
- package/dist/defaults.js +7 -0
- package/dist/defaults.js.map +1 -0
- package/dist/help.d.ts +1 -0
- package/dist/help.js +19 -0
- package/dist/help.js.map +1 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +105 -0
- package/dist/mcp.js.map +1 -0
- package/dist/open-url.d.ts +1 -0
- package/dist/open-url.js +21 -0
- package/dist/open-url.js.map +1 -0
- package/dist/package-info.d.ts +1 -0
- package/dist/package-info.js +7 -0
- package/dist/package-info.js.map +1 -0
- package/dist/redact.d.ts +2 -0
- package/dist/redact.js +12 -0
- package/dist/redact.js.map +1 -0
- package/dist/skill.d.ts +18 -0
- package/dist/skill.js +35 -0
- package/dist/skill.js.map +1 -0
- package/dist/store.d.ts +34 -0
- package/dist/store.js +140 -0
- package/dist/store.js.map +1 -0
- package/package.json +56 -7
- package/skills/kody/SKILL.md +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kent C. Dodds
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
1
|
# @kodycodes/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Turn one-off agent work into something you can rerun: a local MCP client for
|
|
4
|
+
[Kody](https://kody.codes) with login, OS keychain token storage, `search`, and
|
|
5
|
+
`execute`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @kodycodes/cli login
|
|
9
|
+
npx @kodycodes/cli search "what can you do"
|
|
10
|
+
npx @kodycodes/cli skill install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Copyright © 2026 [Kent C. Dodds](https://kentcdodds.com). MIT licensed.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @kodycodes/cli
|
|
19
|
+
kody login
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or run via `npx @kodycodes/cli` without a global install.
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
| Command | Purpose |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `kody login` | Browser OAuth (DCR + PKCE). Stores access and refresh tokens. |
|
|
29
|
+
| `kody logout` | Deletes stored credentials. |
|
|
30
|
+
| `kody status` | Shows login state without printing secrets. |
|
|
31
|
+
| `kody whoami` | Confirms the MCP connection and lists tools. |
|
|
32
|
+
| `kody search [query]` | Calls Kody `search`. |
|
|
33
|
+
| `kody execute` | Calls Kody `execute` (`--code`, `--file`, or stdin via `--file -`). |
|
|
34
|
+
| `kody skill install` | Copies the getting-started skill into Claude Code / Cursor / Agents. |
|
|
35
|
+
|
|
36
|
+
`--mcp-url` or `KODY_MCP_URL` overrides the default `https://kody.codes/mcp`.
|
|
37
|
+
`--json` prints structured MCP results.
|
|
38
|
+
|
|
39
|
+
## Token storage
|
|
40
|
+
|
|
41
|
+
Credentials are stored in the OS secret store:
|
|
42
|
+
|
|
43
|
+
- macOS: Keychain
|
|
44
|
+
- Windows: Credential Manager
|
|
45
|
+
- Linux: Secret Service / libsecret
|
|
46
|
+
|
|
47
|
+
If the keychain is unavailable (common on headless Linux), the CLI writes a
|
|
48
|
+
`0600` file under `$XDG_CONFIG_HOME/kody` (or `%APPDATA%\\kody` on Windows,
|
|
49
|
+
`~/Library/Application Support/kody` on macOS). Tokens are never printed.
|
|
50
|
+
|
|
51
|
+
Access tokens refresh automatically on expiry or HTTP 401.
|
|
52
|
+
|
|
53
|
+
## Releases
|
|
54
|
+
|
|
55
|
+
This repo uses [semantic-release](https://github.com/semantic-release/semantic-release)
|
|
56
|
+
the same way [match-sorter](https://github.com/kentcdodds/match-sorter) does:
|
|
57
|
+
conventional commits on `main` publish `@kodycodes/cli` with npm provenance
|
|
58
|
+
(`id-token: write`). Version in `package.json` stays `0.0.0-semantically-released`.
|
|
59
|
+
|
|
60
|
+
Trusted publishing for `@kodycodes/cli` is attached to this GitHub repository.
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT © Kent C. Dodds
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
2
|
+
import { type SecretBackend, type StoredCredentials } from './store.js';
|
|
3
|
+
export type LoginOptions = {
|
|
4
|
+
mcpUrl?: string;
|
|
5
|
+
openBrowser?: boolean;
|
|
6
|
+
backend?: SecretBackend;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
now?: () => number;
|
|
9
|
+
fetchFn?: typeof fetch;
|
|
10
|
+
onAuthorizationUrl?: (url: URL) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare function isAccessTokenExpired(credentials: StoredCredentials, now?: number): boolean;
|
|
13
|
+
export declare function credentialsFromTokens(input: {
|
|
14
|
+
mcpUrl: string;
|
|
15
|
+
resource: string;
|
|
16
|
+
authorizationServerUrl: string;
|
|
17
|
+
client: OAuthClientInformationMixed;
|
|
18
|
+
tokens: OAuthTokens;
|
|
19
|
+
previous?: StoredCredentials;
|
|
20
|
+
now?: number;
|
|
21
|
+
}): StoredCredentials;
|
|
22
|
+
export declare function refreshStoredCredentials(input: {
|
|
23
|
+
credentials: StoredCredentials;
|
|
24
|
+
backend?: SecretBackend;
|
|
25
|
+
now?: number;
|
|
26
|
+
fetchFn?: typeof fetch;
|
|
27
|
+
}): Promise<StoredCredentials>;
|
|
28
|
+
export declare function ensureFreshCredentials(input: {
|
|
29
|
+
mcpUrl?: string;
|
|
30
|
+
backend?: SecretBackend;
|
|
31
|
+
now?: number;
|
|
32
|
+
fetchFn?: typeof fetch;
|
|
33
|
+
}): Promise<StoredCredentials>;
|
|
34
|
+
export declare function login(options?: LoginOptions): Promise<{
|
|
35
|
+
credentials: StoredCredentials;
|
|
36
|
+
authorizationUrl: URL;
|
|
37
|
+
backendKind: 'keyring' | 'file';
|
|
38
|
+
backendPath?: string;
|
|
39
|
+
}>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createServer, } from 'node:http';
|
|
2
|
+
import { discoverOAuthServerInfo, exchangeAuthorization, refreshAuthorization, registerClient, startAuthorization, } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
3
|
+
import { accessTokenSkewMs, defaultMcpUrl, defaultScopes, loginTimeoutMs, } from './defaults.js';
|
|
4
|
+
import { openUrl } from './open-url.js';
|
|
5
|
+
import { redactError } from './redact.js';
|
|
6
|
+
import { loadCredentials, saveCredentials, } from './store.js';
|
|
7
|
+
function clientInformationFrom(credentials) {
|
|
8
|
+
return {
|
|
9
|
+
client_id: credentials.clientId,
|
|
10
|
+
...(credentials.clientSecret
|
|
11
|
+
? { client_secret: credentials.clientSecret }
|
|
12
|
+
: {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function isAccessTokenExpired(credentials, now = Date.now()) {
|
|
16
|
+
if (!credentials.expiresAt)
|
|
17
|
+
return false;
|
|
18
|
+
return now + accessTokenSkewMs >= credentials.expiresAt;
|
|
19
|
+
}
|
|
20
|
+
export function credentialsFromTokens(input) {
|
|
21
|
+
const now = input.now ?? Date.now();
|
|
22
|
+
const expiresAt = typeof input.tokens.expires_in === 'number'
|
|
23
|
+
? now + input.tokens.expires_in * 1000
|
|
24
|
+
: input.previous?.expiresAt;
|
|
25
|
+
return {
|
|
26
|
+
version: 1,
|
|
27
|
+
mcpUrl: input.mcpUrl,
|
|
28
|
+
resource: input.resource,
|
|
29
|
+
authorizationServerUrl: input.authorizationServerUrl,
|
|
30
|
+
clientId: input.client.client_id,
|
|
31
|
+
clientSecret: 'client_secret' in input.client
|
|
32
|
+
? input.client.client_secret
|
|
33
|
+
: input.previous?.clientSecret,
|
|
34
|
+
accessToken: input.tokens.access_token,
|
|
35
|
+
refreshToken: input.tokens.refresh_token ?? input.previous?.refreshToken,
|
|
36
|
+
tokenType: input.tokens.token_type ?? 'bearer',
|
|
37
|
+
expiresAt,
|
|
38
|
+
scope: input.tokens.scope ?? input.previous?.scope,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export async function refreshStoredCredentials(input) {
|
|
42
|
+
const { credentials } = input;
|
|
43
|
+
if (!credentials.refreshToken) {
|
|
44
|
+
throw new Error('No refresh token is stored. Run `kody login`.');
|
|
45
|
+
}
|
|
46
|
+
const info = await discoverOAuthServerInfo(credentials.mcpUrl, {
|
|
47
|
+
fetchFn: input.fetchFn,
|
|
48
|
+
});
|
|
49
|
+
const tokens = await refreshAuthorization(info.authorizationServerUrl, {
|
|
50
|
+
metadata: info.authorizationServerMetadata,
|
|
51
|
+
clientInformation: clientInformationFrom(credentials),
|
|
52
|
+
refreshToken: credentials.refreshToken,
|
|
53
|
+
resource: new URL(credentials.resource),
|
|
54
|
+
fetchFn: input.fetchFn,
|
|
55
|
+
});
|
|
56
|
+
const next = credentialsFromTokens({
|
|
57
|
+
mcpUrl: credentials.mcpUrl,
|
|
58
|
+
resource: credentials.resource,
|
|
59
|
+
authorizationServerUrl: credentials.authorizationServerUrl,
|
|
60
|
+
client: clientInformationFrom(credentials),
|
|
61
|
+
tokens,
|
|
62
|
+
previous: credentials,
|
|
63
|
+
now: input.now,
|
|
64
|
+
});
|
|
65
|
+
saveCredentials(next, input.backend);
|
|
66
|
+
return next;
|
|
67
|
+
}
|
|
68
|
+
export async function ensureFreshCredentials(input) {
|
|
69
|
+
const mcpUrl = input.mcpUrl ?? defaultMcpUrl;
|
|
70
|
+
const credentials = loadCredentials(mcpUrl, input.backend);
|
|
71
|
+
if (!credentials) {
|
|
72
|
+
throw new Error('Not logged in. Run `kody login`.');
|
|
73
|
+
}
|
|
74
|
+
if (!isAccessTokenExpired(credentials, input.now)) {
|
|
75
|
+
return credentials;
|
|
76
|
+
}
|
|
77
|
+
return await refreshStoredCredentials({
|
|
78
|
+
credentials,
|
|
79
|
+
backend: input.backend,
|
|
80
|
+
now: input.now,
|
|
81
|
+
fetchFn: input.fetchFn,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function startCallbackServer() {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const server = createServer();
|
|
87
|
+
server.listen(0, '127.0.0.1', () => {
|
|
88
|
+
const address = server.address();
|
|
89
|
+
if (!address || typeof address === 'string') {
|
|
90
|
+
server.close();
|
|
91
|
+
reject(new Error('Could not bind a localhost callback port.'));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
resolve({
|
|
95
|
+
server,
|
|
96
|
+
redirectUri: new URL(`http://127.0.0.1:${address.port}/callback`),
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
server.on('error', reject);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function waitForCallback(input) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const finish = (error, code) => {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
input.server.close();
|
|
107
|
+
if (error)
|
|
108
|
+
reject(error);
|
|
109
|
+
else
|
|
110
|
+
resolve(code ?? '');
|
|
111
|
+
};
|
|
112
|
+
const timer = setTimeout(() => {
|
|
113
|
+
finish(new Error('Timed out waiting for the browser login.'));
|
|
114
|
+
}, input.timeoutMs);
|
|
115
|
+
input.server.on('request', (request, response) => {
|
|
116
|
+
try {
|
|
117
|
+
const url = new URL(request.url ?? '/', input.redirectUri);
|
|
118
|
+
if (url.pathname !== input.redirectUri.pathname) {
|
|
119
|
+
response.writeHead(404).end('Not found');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const error = url.searchParams.get('error');
|
|
123
|
+
if (error) {
|
|
124
|
+
const description = url.searchParams.get('error_description') ?? '';
|
|
125
|
+
response
|
|
126
|
+
.writeHead(400, { 'Content-Type': 'text/html' })
|
|
127
|
+
.end('<p>Authorization failed. You can close this window.</p>');
|
|
128
|
+
finish(new Error(description || error));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const state = url.searchParams.get('state');
|
|
132
|
+
const code = url.searchParams.get('code');
|
|
133
|
+
if (state !== input.expectedState || !code) {
|
|
134
|
+
response
|
|
135
|
+
.writeHead(400, { 'Content-Type': 'text/html' })
|
|
136
|
+
.end('<p>Invalid OAuth callback. You can close this window.</p>');
|
|
137
|
+
finish(new Error('OAuth callback missing code or state.'));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
response
|
|
141
|
+
.writeHead(200, { 'Content-Type': 'text/html' })
|
|
142
|
+
.end('<p>Kody CLI is signed in. You can close this window.</p>');
|
|
143
|
+
finish(null, code);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
finish(redactError(error));
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
export async function login(options = {}) {
|
|
152
|
+
const mcpUrl = options.mcpUrl ?? defaultMcpUrl;
|
|
153
|
+
const fetchFn = options.fetchFn;
|
|
154
|
+
const info = await discoverOAuthServerInfo(mcpUrl, { fetchFn });
|
|
155
|
+
const resource = info.resourceMetadata?.resource ??
|
|
156
|
+
`${new URL(mcpUrl).origin}${new URL(mcpUrl).pathname}`;
|
|
157
|
+
const { server, redirectUri } = await startCallbackServer();
|
|
158
|
+
try {
|
|
159
|
+
const metadata = info.authorizationServerMetadata;
|
|
160
|
+
const client = await registerClient(info.authorizationServerUrl, {
|
|
161
|
+
metadata,
|
|
162
|
+
clientMetadata: {
|
|
163
|
+
redirect_uris: [redirectUri.href],
|
|
164
|
+
client_name: 'Kody CLI',
|
|
165
|
+
client_uri: 'https://github.com/kody-bot/cli',
|
|
166
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
167
|
+
response_types: ['code'],
|
|
168
|
+
token_endpoint_auth_method: 'none',
|
|
169
|
+
scope: defaultScopes.join(' '),
|
|
170
|
+
},
|
|
171
|
+
scope: defaultScopes.join(' '),
|
|
172
|
+
fetchFn,
|
|
173
|
+
});
|
|
174
|
+
const state = crypto.randomUUID();
|
|
175
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(info.authorizationServerUrl, {
|
|
176
|
+
metadata,
|
|
177
|
+
clientInformation: client,
|
|
178
|
+
redirectUrl: redirectUri,
|
|
179
|
+
scope: defaultScopes.join(' '),
|
|
180
|
+
state,
|
|
181
|
+
resource: new URL(resource),
|
|
182
|
+
});
|
|
183
|
+
options.onAuthorizationUrl?.(authorizationUrl);
|
|
184
|
+
if (options.openBrowser !== false) {
|
|
185
|
+
await openUrl(authorizationUrl.href);
|
|
186
|
+
}
|
|
187
|
+
const code = await waitForCallback({
|
|
188
|
+
server,
|
|
189
|
+
redirectUri,
|
|
190
|
+
expectedState: state,
|
|
191
|
+
timeoutMs: options.timeoutMs ?? loginTimeoutMs,
|
|
192
|
+
});
|
|
193
|
+
const tokens = await exchangeAuthorization(info.authorizationServerUrl, {
|
|
194
|
+
metadata,
|
|
195
|
+
clientInformation: client,
|
|
196
|
+
authorizationCode: code,
|
|
197
|
+
codeVerifier,
|
|
198
|
+
redirectUri,
|
|
199
|
+
resource: new URL(resource),
|
|
200
|
+
fetchFn,
|
|
201
|
+
});
|
|
202
|
+
const credentials = credentialsFromTokens({
|
|
203
|
+
mcpUrl,
|
|
204
|
+
resource,
|
|
205
|
+
authorizationServerUrl: info.authorizationServerUrl,
|
|
206
|
+
client,
|
|
207
|
+
tokens,
|
|
208
|
+
now: options.now?.(),
|
|
209
|
+
});
|
|
210
|
+
const saved = saveCredentials(credentials, options.backend);
|
|
211
|
+
return {
|
|
212
|
+
credentials,
|
|
213
|
+
authorizationUrl,
|
|
214
|
+
backendKind: saved.backend.kind,
|
|
215
|
+
backendPath: saved.backend.path,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
server.close();
|
|
220
|
+
throw redactError(error);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,MAAM,IAAI,GAAG,MAAM,MAAM,EAAE,CAAA;AAC3B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAA"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type CommandName = 'login' | 'logout' | 'status' | 'whoami' | 'search' | 'execute' | 'skill' | 'help' | 'version';
|
|
2
|
+
declare function parseKnown(args: Array<string>): {
|
|
3
|
+
values: {
|
|
4
|
+
[longOption: string]: string | boolean | undefined;
|
|
5
|
+
} & {
|
|
6
|
+
help?: string | boolean | undefined;
|
|
7
|
+
version?: string | boolean | undefined;
|
|
8
|
+
json?: string | boolean | undefined;
|
|
9
|
+
'mcp-url'?: string | boolean | undefined;
|
|
10
|
+
entity?: string | boolean | undefined;
|
|
11
|
+
domain?: string | boolean | undefined;
|
|
12
|
+
limit?: string | boolean | undefined;
|
|
13
|
+
code?: string | boolean | undefined;
|
|
14
|
+
file?: string | boolean | undefined;
|
|
15
|
+
params?: string | boolean | undefined;
|
|
16
|
+
'conversation-id'?: string | boolean | undefined;
|
|
17
|
+
project?: string | boolean | undefined;
|
|
18
|
+
'no-browser'?: string | boolean | undefined;
|
|
19
|
+
};
|
|
20
|
+
positionals: string[];
|
|
21
|
+
};
|
|
22
|
+
export declare function resolveCommand(argv: Array<string>): {
|
|
23
|
+
command: CommandName;
|
|
24
|
+
positionals: Array<string>;
|
|
25
|
+
values: ReturnType<typeof parseKnown>['values'];
|
|
26
|
+
};
|
|
27
|
+
export declare function runCli(argv?: Array<string>, io?: {
|
|
28
|
+
stdout?: (text: string) => void;
|
|
29
|
+
stderr?: (text: string) => void;
|
|
30
|
+
}): Promise<number>;
|
|
31
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { defaultMcpUrl } from './defaults.js';
|
|
4
|
+
import { usage } from './help.js';
|
|
5
|
+
import { ensureFreshCredentials, login } from './auth.js';
|
|
6
|
+
import { deleteCredentials, loadCredentials } from './store.js';
|
|
7
|
+
import { callKodyTool, formatToolResult, listKodyTools } from './mcp.js';
|
|
8
|
+
import { installSkill } from './skill.js';
|
|
9
|
+
import { readPackageVersion } from './package-info.js';
|
|
10
|
+
import { redactError } from './redact.js';
|
|
11
|
+
function mcpUrlFrom(values) {
|
|
12
|
+
return values.mcpUrl || process.env.KODY_MCP_URL || defaultMcpUrl;
|
|
13
|
+
}
|
|
14
|
+
function parseKnown(args) {
|
|
15
|
+
return parseArgs({
|
|
16
|
+
args,
|
|
17
|
+
allowPositionals: true,
|
|
18
|
+
strict: false,
|
|
19
|
+
options: {
|
|
20
|
+
help: { type: 'boolean', short: 'h' },
|
|
21
|
+
version: { type: 'boolean', short: 'v' },
|
|
22
|
+
json: { type: 'boolean' },
|
|
23
|
+
'mcp-url': { type: 'string' },
|
|
24
|
+
entity: { type: 'string' },
|
|
25
|
+
domain: { type: 'string' },
|
|
26
|
+
limit: { type: 'string' },
|
|
27
|
+
code: { type: 'string' },
|
|
28
|
+
file: { type: 'string' },
|
|
29
|
+
params: { type: 'string' },
|
|
30
|
+
'conversation-id': { type: 'string' },
|
|
31
|
+
project: { type: 'boolean' },
|
|
32
|
+
'no-browser': { type: 'boolean' },
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function resolveCommand(argv) {
|
|
37
|
+
const { positionals, values } = parseKnown(argv);
|
|
38
|
+
if (values.help && positionals.length === 0) {
|
|
39
|
+
return { command: 'help', positionals, values };
|
|
40
|
+
}
|
|
41
|
+
if (values.version && positionals.length === 0) {
|
|
42
|
+
return { command: 'version', positionals, values };
|
|
43
|
+
}
|
|
44
|
+
const raw = positionals[0];
|
|
45
|
+
if (!raw)
|
|
46
|
+
return { command: 'help', positionals, values };
|
|
47
|
+
switch (raw) {
|
|
48
|
+
case 'login':
|
|
49
|
+
case 'logout':
|
|
50
|
+
case 'status':
|
|
51
|
+
case 'whoami':
|
|
52
|
+
case 'search':
|
|
53
|
+
case 'execute':
|
|
54
|
+
case 'skill':
|
|
55
|
+
case 'help':
|
|
56
|
+
case 'version':
|
|
57
|
+
return { command: raw, positionals: positionals.slice(1), values };
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unknown command "${raw}".\n\n${usage}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function runCli(argv = process.argv.slice(2), io = {}) {
|
|
63
|
+
const write = io.stdout ?? ((text) => process.stdout.write(text));
|
|
64
|
+
const writeErr = io.stderr ?? ((text) => process.stderr.write(text));
|
|
65
|
+
try {
|
|
66
|
+
const parsed = resolveCommand(argv);
|
|
67
|
+
if (parsed.values.help && parsed.command !== 'help') {
|
|
68
|
+
write(usage);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
return await dispatch(parsed, write);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
writeErr(`${redactError(error).message}\n`);
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function dispatch(parsed, write) {
|
|
79
|
+
const mcpUrl = mcpUrlFrom({
|
|
80
|
+
mcpUrl: typeof parsed.values['mcp-url'] === 'string' ? parsed.values['mcp-url'] : undefined,
|
|
81
|
+
});
|
|
82
|
+
const json = parsed.values.json === true;
|
|
83
|
+
switch (parsed.command) {
|
|
84
|
+
case 'help':
|
|
85
|
+
write(usage);
|
|
86
|
+
return 0;
|
|
87
|
+
case 'version':
|
|
88
|
+
write(`${readPackageVersion()}\n`);
|
|
89
|
+
return 0;
|
|
90
|
+
case 'login': {
|
|
91
|
+
write('Opening the Kody login page in your browser…\n');
|
|
92
|
+
const result = await login({
|
|
93
|
+
mcpUrl,
|
|
94
|
+
openBrowser: parsed.values['no-browser'] !== true,
|
|
95
|
+
onAuthorizationUrl: (url) => {
|
|
96
|
+
write(`If the browser does not open, visit:\n${url.href}\n`);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
write(`Logged in to ${result.credentials.mcpUrl}.\n`);
|
|
100
|
+
if (result.backendKind === 'file' && result.backendPath) {
|
|
101
|
+
write(`OS keychain was unavailable; credentials saved at ${result.backendPath} (mode 0600).\n`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
write('Credentials stored in the OS keychain.\n');
|
|
105
|
+
}
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
case 'logout': {
|
|
109
|
+
const result = deleteCredentials(mcpUrl);
|
|
110
|
+
write(result.deleted ? 'Logged out.\n' : 'No stored credentials.\n');
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
case 'status': {
|
|
114
|
+
const credentials = loadCredentials(mcpUrl);
|
|
115
|
+
if (!credentials) {
|
|
116
|
+
write('Not logged in.\n');
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
const expires = credentials.expiresAt
|
|
120
|
+
? new Date(credentials.expiresAt).toISOString()
|
|
121
|
+
: 'unknown';
|
|
122
|
+
write([
|
|
123
|
+
`mcp: ${credentials.mcpUrl}`,
|
|
124
|
+
`logged in: yes`,
|
|
125
|
+
`access token expires: ${expires}`,
|
|
126
|
+
`refresh token: ${credentials.refreshToken ? 'yes' : 'no'}`,
|
|
127
|
+
`scope: ${credentials.scope ?? 'unknown'}`,
|
|
128
|
+
'',
|
|
129
|
+
].join('\n'));
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
case 'whoami': {
|
|
133
|
+
const credentials = await ensureFreshCredentials({ mcpUrl });
|
|
134
|
+
const tools = await listKodyTools({ mcpUrl });
|
|
135
|
+
if (json) {
|
|
136
|
+
write(`${JSON.stringify({
|
|
137
|
+
mcpUrl: credentials.mcpUrl,
|
|
138
|
+
scope: credentials.scope ?? null,
|
|
139
|
+
tools: tools.map((tool) => tool.name),
|
|
140
|
+
}, null, 2)}\n`);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
write(`Connected to ${credentials.mcpUrl}\nTools: ${tools.map((tool) => tool.name).join(', ') || '(none)'}\n`);
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
case 'search': {
|
|
147
|
+
const query = parsed.positionals.join(' ').trim();
|
|
148
|
+
const args = {};
|
|
149
|
+
if (query)
|
|
150
|
+
args.query = query;
|
|
151
|
+
if (typeof parsed.values.entity === 'string')
|
|
152
|
+
args.entity = parsed.values.entity;
|
|
153
|
+
if (typeof parsed.values.domain === 'string')
|
|
154
|
+
args.domain = parsed.values.domain;
|
|
155
|
+
if (typeof parsed.values.limit === 'string')
|
|
156
|
+
args.limit = Number(parsed.values.limit);
|
|
157
|
+
const result = await callKodyTool({ name: 'search', args, mcpUrl });
|
|
158
|
+
write(formatToolResult(result, json));
|
|
159
|
+
return result.isError ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
case 'execute': {
|
|
162
|
+
const code = typeof parsed.values.code === 'string'
|
|
163
|
+
? parsed.values.code
|
|
164
|
+
: typeof parsed.values.file === 'string'
|
|
165
|
+
? parsed.values.file === '-'
|
|
166
|
+
? await readStdin()
|
|
167
|
+
: await readFile(parsed.values.file, 'utf8')
|
|
168
|
+
: parsed.positionals.join('\n').trim();
|
|
169
|
+
if (!code) {
|
|
170
|
+
throw new Error('Provide --code, --file, or a module string.');
|
|
171
|
+
}
|
|
172
|
+
const args = { code };
|
|
173
|
+
if (typeof parsed.values.params === 'string') {
|
|
174
|
+
args.params = JSON.parse(parsed.values.params);
|
|
175
|
+
}
|
|
176
|
+
if (typeof parsed.values['conversation-id'] === 'string') {
|
|
177
|
+
args.conversationId = parsed.values['conversation-id'];
|
|
178
|
+
}
|
|
179
|
+
const result = await callKodyTool({ name: 'execute', args, mcpUrl });
|
|
180
|
+
write(formatToolResult(result, json));
|
|
181
|
+
return result.isError ? 1 : 0;
|
|
182
|
+
}
|
|
183
|
+
case 'skill': {
|
|
184
|
+
const action = parsed.positionals[0] ?? 'install';
|
|
185
|
+
if (action !== 'install') {
|
|
186
|
+
throw new Error('Usage: kody skill install [--project]');
|
|
187
|
+
}
|
|
188
|
+
const targets = await installSkill({ project: parsed.values.project === true });
|
|
189
|
+
write(`Installed the Kody skill to:\n${targets.map((target) => `- ${target.host}: ${target.path}`).join('\n')}\n`);
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
default: {
|
|
193
|
+
const exhaustive = parsed.command;
|
|
194
|
+
throw new Error(`Unhandled command: ${String(exhaustive)}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function readStdin() {
|
|
199
|
+
const chunks = [];
|
|
200
|
+
for await (const chunk of process.stdin) {
|
|
201
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
202
|
+
}
|
|
203
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const defaultMcpUrl = "https://kody.codes/mcp";
|
|
2
|
+
export declare const defaultScopes: readonly ["profile", "email"];
|
|
3
|
+
export declare const keyringService = "kody.codes";
|
|
4
|
+
export declare const loginTimeoutMs: number;
|
|
5
|
+
export declare const accessTokenSkewMs = 60000;
|
|
6
|
+
export declare const cliName = "@kodycodes/cli";
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const defaultMcpUrl = 'https://kody.codes/mcp';
|
|
2
|
+
export const defaultScopes = ['profile', 'email'];
|
|
3
|
+
export const keyringService = 'kody.codes';
|
|
4
|
+
export const loginTimeoutMs = 5 * 60 * 1000;
|
|
5
|
+
export const accessTokenSkewMs = 60_000;
|
|
6
|
+
export const cliName = '@kodycodes/cli';
|
|
7
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,wBAAwB,CAAA;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,OAAO,CAAU,CAAA;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAA;AAC1C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAA;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAA;AACvC,MAAM,CAAC,MAAM,OAAO,GAAG,gBAAgB,CAAA"}
|
package/dist/help.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const usage: string;
|
package/dist/help.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defaultMcpUrl } from './defaults.js';
|
|
2
|
+
import { readPackageVersion } from './package-info.js';
|
|
3
|
+
export const usage = `Kody CLI ${readPackageVersion()}
|
|
4
|
+
|
|
5
|
+
A local MCP client for https://kody.codes — login once, then search and execute.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
kody login [--mcp-url <url>] [--no-browser]
|
|
9
|
+
kody logout [--mcp-url <url>]
|
|
10
|
+
kody status [--mcp-url <url>]
|
|
11
|
+
kody whoami [--mcp-url <url>] [--json]
|
|
12
|
+
kody search [query] [--entity <ref>] [--domain <id>] [--limit <n>] [--json]
|
|
13
|
+
kody execute [--code <esm>] [--file <path>] [--params <json>] [--conversation-id <id>] [--json]
|
|
14
|
+
kody skill install [--project]
|
|
15
|
+
|
|
16
|
+
Environment:
|
|
17
|
+
KODY_MCP_URL Override the default MCP URL (${defaultMcpUrl})
|
|
18
|
+
`;
|
|
19
|
+
//# sourceMappingURL=help.js.map
|
package/dist/help.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,MAAM,CAAC,MAAM,KAAK,GAAG,YAAY,kBAAkB,EAAE;;;;;;;;;;;;;;iDAcJ,aAAa;CAC7D,CAAA"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SecretBackend } from './store.js';
|
|
2
|
+
export type CallToolInput = {
|
|
3
|
+
name: 'search' | 'execute';
|
|
4
|
+
args: Record<string, unknown>;
|
|
5
|
+
mcpUrl?: string;
|
|
6
|
+
backend?: SecretBackend;
|
|
7
|
+
fetchFn?: typeof fetch;
|
|
8
|
+
};
|
|
9
|
+
export type ToolCallResult = {
|
|
10
|
+
content: Array<{
|
|
11
|
+
type: string;
|
|
12
|
+
text?: string;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
structuredContent?: unknown;
|
|
16
|
+
isError?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare function callKodyTool(input: CallToolInput): Promise<ToolCallResult>;
|
|
19
|
+
export declare function listKodyTools(input: {
|
|
20
|
+
mcpUrl?: string;
|
|
21
|
+
backend?: SecretBackend;
|
|
22
|
+
fetchFn?: typeof fetch;
|
|
23
|
+
}): Promise<Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
}>>;
|
|
27
|
+
export declare function formatToolResult(result: ToolCallResult, json: boolean): string;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
|
+
import { cliName } from './defaults.js';
|
|
5
|
+
import { ensureFreshCredentials, refreshStoredCredentials } from './auth.js';
|
|
6
|
+
import { readPackageVersion } from './package-info.js';
|
|
7
|
+
import { redactError } from './redact.js';
|
|
8
|
+
async function connect(mcpUrl, accessToken, fetchFn) {
|
|
9
|
+
const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {
|
|
10
|
+
requestInit: {
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${accessToken}`,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
fetch: fetchFn,
|
|
16
|
+
});
|
|
17
|
+
const client = new Client({
|
|
18
|
+
name: cliName,
|
|
19
|
+
version: readPackageVersion(),
|
|
20
|
+
});
|
|
21
|
+
await client.connect(transport);
|
|
22
|
+
return { client, transport };
|
|
23
|
+
}
|
|
24
|
+
export async function callKodyTool(input) {
|
|
25
|
+
const credentials = await ensureFreshCredentials({
|
|
26
|
+
mcpUrl: input.mcpUrl,
|
|
27
|
+
backend: input.backend,
|
|
28
|
+
fetchFn: input.fetchFn,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
return await invoke(credentials.mcpUrl, credentials.accessToken, input);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (!(error instanceof UnauthorizedError) && !isUnauthorized(error)) {
|
|
35
|
+
throw redactError(error);
|
|
36
|
+
}
|
|
37
|
+
const refreshed = await refreshStoredCredentials({
|
|
38
|
+
credentials,
|
|
39
|
+
backend: input.backend,
|
|
40
|
+
fetchFn: input.fetchFn,
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
return await invoke(refreshed.mcpUrl, refreshed.accessToken, input);
|
|
44
|
+
}
|
|
45
|
+
catch (retryError) {
|
|
46
|
+
throw redactError(retryError);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function invoke(mcpUrl, accessToken, input) {
|
|
51
|
+
const { client, transport } = await connect(mcpUrl, accessToken, input.fetchFn);
|
|
52
|
+
try {
|
|
53
|
+
const result = await client.callTool({
|
|
54
|
+
name: input.name,
|
|
55
|
+
arguments: input.args,
|
|
56
|
+
});
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
await transport.close().catch(() => undefined);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function listKodyTools(input) {
|
|
64
|
+
const credentials = await ensureFreshCredentials({
|
|
65
|
+
mcpUrl: input.mcpUrl,
|
|
66
|
+
backend: input.backend,
|
|
67
|
+
fetchFn: input.fetchFn,
|
|
68
|
+
});
|
|
69
|
+
const { client, transport } = await connect(credentials.mcpUrl, credentials.accessToken, input.fetchFn);
|
|
70
|
+
try {
|
|
71
|
+
const listed = await client.listTools();
|
|
72
|
+
return listed.tools.map((tool) => ({
|
|
73
|
+
name: tool.name,
|
|
74
|
+
description: tool.description,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await transport.close().catch(() => undefined);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function formatToolResult(result, json) {
|
|
82
|
+
if (json) {
|
|
83
|
+
return `${JSON.stringify({
|
|
84
|
+
isError: result.isError ?? false,
|
|
85
|
+
structuredContent: result.structuredContent ?? null,
|
|
86
|
+
content: result.content,
|
|
87
|
+
}, null, 2)}\n`;
|
|
88
|
+
}
|
|
89
|
+
const texts = result.content
|
|
90
|
+
.filter((part) => part.type === 'text' && typeof part.text === 'string')
|
|
91
|
+
.map((part) => part.text ?? '');
|
|
92
|
+
if (texts.length > 0)
|
|
93
|
+
return texts.join('\n\n').replace(/\n*$/, '\n');
|
|
94
|
+
if (result.structuredContent != null) {
|
|
95
|
+
return `${JSON.stringify(result.structuredContent, null, 2)}\n`;
|
|
96
|
+
}
|
|
97
|
+
return `${JSON.stringify(result.content, null, 2)}\n`;
|
|
98
|
+
}
|
|
99
|
+
function isUnauthorized(error) {
|
|
100
|
+
if (!error || typeof error !== 'object')
|
|
101
|
+
return false;
|
|
102
|
+
const status = 'code' in error ? error.code : undefined;
|
|
103
|
+
return status === 401 || (error instanceof Error && /401|unauthorized/i.test(error.message));
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function openUrl(url: string): Promise<boolean>;
|
package/dist/open-url.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
export async function openUrl(url) {
|
|
3
|
+
const platform = process.platform;
|
|
4
|
+
const command = platform === 'darwin'
|
|
5
|
+
? 'open'
|
|
6
|
+
: platform === 'win32'
|
|
7
|
+
? 'cmd'
|
|
8
|
+
: 'xdg-open';
|
|
9
|
+
const args = platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
10
|
+
return await new Promise((resolve) => {
|
|
11
|
+
const child = spawn(command, args, {
|
|
12
|
+
detached: true,
|
|
13
|
+
stdio: 'ignore',
|
|
14
|
+
windowsHide: true,
|
|
15
|
+
});
|
|
16
|
+
child.on('error', () => resolve(false));
|
|
17
|
+
child.unref();
|
|
18
|
+
resolve(true);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=open-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-url.js","sourceRoot":"","sources":["../src/open-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE1C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;IACjC,MAAM,OAAO,GACZ,QAAQ,KAAK,QAAQ;QACpB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,QAAQ,KAAK,OAAO;YACrB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,UAAU,CAAA;IACf,MAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACpE,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YAClC,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,IAAI;SACjB,CAAC,CAAA;QACF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QACvC,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,OAAO,CAAC,IAAI,CAAC,CAAA;IACd,CAAC,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readPackageVersion(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-info.js","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C,MAAM,UAAU,kBAAkB;IACjC,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAyB,CAAA;IAC9D,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAA;AAC9B,CAAC"}
|
package/dist/redact.d.ts
ADDED
package/dist/redact.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const secretPattern = /(access_token|refresh_token|client_secret|authorization)["']?\s*[:=]\s*["']?[^\s"',}]+/gi;
|
|
2
|
+
export function redact(value) {
|
|
3
|
+
return value.replace(secretPattern, '$1=[redacted]');
|
|
4
|
+
}
|
|
5
|
+
export function redactError(error) {
|
|
6
|
+
if (error instanceof Error) {
|
|
7
|
+
error.message = redact(error.message);
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
return new Error(redact(String(error)));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAClB,0FAA0F,CAAA;AAE3F,MAAM,UAAU,MAAM,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC5B,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACrC,OAAO,KAAK,CAAA;IACb,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACxC,CAAC"}
|
package/dist/skill.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function bundledSkillPath(): string;
|
|
2
|
+
export declare function userSkillTargets(home?: string): Array<{
|
|
3
|
+
host: string;
|
|
4
|
+
path: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function projectSkillTargets(cwd?: string): Array<{
|
|
7
|
+
host: string;
|
|
8
|
+
path: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function installSkill(input: {
|
|
11
|
+
project?: boolean;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
home?: string;
|
|
14
|
+
sourcePath?: string;
|
|
15
|
+
}): Promise<Array<{
|
|
16
|
+
host: string;
|
|
17
|
+
path: string;
|
|
18
|
+
}>>;
|
package/dist/skill.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
const skillRelativePath = 'skills/kody/SKILL.md';
|
|
6
|
+
export function bundledSkillPath() {
|
|
7
|
+
return join(fileURLToPath(new URL('../', import.meta.url)), skillRelativePath);
|
|
8
|
+
}
|
|
9
|
+
export function userSkillTargets(home = homedir()) {
|
|
10
|
+
return [
|
|
11
|
+
{ host: 'Claude Code', path: join(home, '.claude', 'skills', 'kody', 'SKILL.md') },
|
|
12
|
+
{ host: 'Cursor', path: join(home, '.cursor', 'skills', 'kody', 'SKILL.md') },
|
|
13
|
+
{ host: 'Agents', path: join(home, '.agents', 'skills', 'kody', 'SKILL.md') },
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
export function projectSkillTargets(cwd = process.cwd()) {
|
|
17
|
+
return [
|
|
18
|
+
{ host: 'Agents', path: join(cwd, '.agents', 'skills', 'kody', 'SKILL.md') },
|
|
19
|
+
{ host: 'Cursor', path: join(cwd, '.cursor', 'skills', 'kody', 'SKILL.md') },
|
|
20
|
+
{ host: 'Claude Code', path: join(cwd, '.claude', 'skills', 'kody', 'SKILL.md') },
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
export async function installSkill(input) {
|
|
24
|
+
const source = input.sourcePath ?? bundledSkillPath();
|
|
25
|
+
const body = await readFile(source, 'utf8');
|
|
26
|
+
const targets = input.project
|
|
27
|
+
? projectSkillTargets(input.cwd)
|
|
28
|
+
: userSkillTargets(input.home);
|
|
29
|
+
for (const target of targets) {
|
|
30
|
+
await mkdir(dirname(target.path), { recursive: true });
|
|
31
|
+
await writeFile(target.path, body, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
return targets;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEjC,MAAM,iBAAiB,GAAG,sBAAsB,CAAA;AAEhD,MAAM,UAAU,gBAAgB;IAC/B,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe,OAAO,EAAE;IAIxD,OAAO;QACN,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAClF,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAC7E,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;KAC7E,CAAA;AACF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAI9D,OAAO;QACN,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAC5E,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;QAC5E,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE;KACjF,CAAA;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAKlC;IACA,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAA;IACrD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO;QAC5B,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC;QAChC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACtD,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3C,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type StoredCredentials = {
|
|
2
|
+
version: 1;
|
|
3
|
+
mcpUrl: string;
|
|
4
|
+
resource: string;
|
|
5
|
+
authorizationServerUrl: string;
|
|
6
|
+
clientId: string;
|
|
7
|
+
clientSecret?: string;
|
|
8
|
+
accessToken: string;
|
|
9
|
+
refreshToken?: string;
|
|
10
|
+
tokenType: string;
|
|
11
|
+
expiresAt?: number;
|
|
12
|
+
scope?: string;
|
|
13
|
+
};
|
|
14
|
+
export type SecretBackend = {
|
|
15
|
+
kind: 'keyring' | 'file';
|
|
16
|
+
path?: string;
|
|
17
|
+
get(): string | null;
|
|
18
|
+
set(value: string): void;
|
|
19
|
+
delete(): boolean;
|
|
20
|
+
};
|
|
21
|
+
export declare function accountForMcpUrl(mcpUrl: string): string;
|
|
22
|
+
export declare function fileStorePath(mcpUrl: string, home?: string): string;
|
|
23
|
+
export declare function createFileBackend(path: string): SecretBackend;
|
|
24
|
+
export declare function createKeyringBackend(mcpUrl: string): SecretBackend;
|
|
25
|
+
export declare function resolveBackend(mcpUrl: string, preferred?: SecretBackend): SecretBackend;
|
|
26
|
+
export declare function parseCredentials(raw: string): StoredCredentials;
|
|
27
|
+
export declare function loadCredentials(mcpUrl?: string, backend?: SecretBackend): StoredCredentials | null;
|
|
28
|
+
export declare function saveCredentials(credentials: StoredCredentials, backend?: SecretBackend): {
|
|
29
|
+
backend: SecretBackend;
|
|
30
|
+
};
|
|
31
|
+
export declare function deleteCredentials(mcpUrl?: string, backend?: SecretBackend): {
|
|
32
|
+
deleted: boolean;
|
|
33
|
+
backend: SecretBackend;
|
|
34
|
+
};
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { Entry } from '@napi-rs/keyring';
|
|
5
|
+
import { defaultMcpUrl, keyringService } from './defaults.js';
|
|
6
|
+
export function accountForMcpUrl(mcpUrl) {
|
|
7
|
+
return `cli:${new URL(mcpUrl).origin}`;
|
|
8
|
+
}
|
|
9
|
+
export function fileStorePath(mcpUrl, home = homedir()) {
|
|
10
|
+
const origin = new URL(mcpUrl).host.replace(/[^a-zA-Z0-9.-]/g, '_');
|
|
11
|
+
const base = process.platform === 'win32'
|
|
12
|
+
? join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'kody')
|
|
13
|
+
: process.platform === 'darwin'
|
|
14
|
+
? join(home, 'Library', 'Application Support', 'kody')
|
|
15
|
+
: join(process.env.XDG_CONFIG_HOME || join(home, '.config'), 'kody');
|
|
16
|
+
return join(base, `credentials-${origin}.json`);
|
|
17
|
+
}
|
|
18
|
+
export function createFileBackend(path) {
|
|
19
|
+
return {
|
|
20
|
+
kind: 'file',
|
|
21
|
+
path,
|
|
22
|
+
get() {
|
|
23
|
+
try {
|
|
24
|
+
return readFileSync(path, 'utf8');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
set(value) {
|
|
31
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
32
|
+
writeFileSync(path, value, { mode: 0o600 });
|
|
33
|
+
try {
|
|
34
|
+
chmodSync(path, 0o600);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Windows cannot apply POSIX modes.
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
delete() {
|
|
41
|
+
try {
|
|
42
|
+
unlinkSync(path);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function createKeyringBackend(mcpUrl) {
|
|
52
|
+
const entry = new Entry(keyringService, accountForMcpUrl(mcpUrl));
|
|
53
|
+
return {
|
|
54
|
+
kind: 'keyring',
|
|
55
|
+
get() {
|
|
56
|
+
try {
|
|
57
|
+
return entry.getPassword();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
set(value) {
|
|
64
|
+
entry.setPassword(value);
|
|
65
|
+
},
|
|
66
|
+
delete() {
|
|
67
|
+
try {
|
|
68
|
+
return entry.deleteCredential();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function resolveBackend(mcpUrl, preferred) {
|
|
77
|
+
if (preferred)
|
|
78
|
+
return preferred;
|
|
79
|
+
try {
|
|
80
|
+
return createKeyringBackend(mcpUrl);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return createFileBackend(fileStorePath(mcpUrl));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function parseCredentials(raw) {
|
|
87
|
+
const parsed = JSON.parse(raw);
|
|
88
|
+
if (parsed.version !== 1 || !parsed.accessToken || !parsed.clientId) {
|
|
89
|
+
throw new Error('Stored Kody credentials are invalid. Run `kody login`.');
|
|
90
|
+
}
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
export function loadCredentials(mcpUrl = defaultMcpUrl, backend) {
|
|
94
|
+
const store = resolveBackend(mcpUrl, backend);
|
|
95
|
+
try {
|
|
96
|
+
const raw = store.get();
|
|
97
|
+
if (!raw)
|
|
98
|
+
return null;
|
|
99
|
+
return parseCredentials(raw);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (store.kind === 'keyring' && !backend) {
|
|
103
|
+
const fallback = createFileBackend(fileStorePath(mcpUrl));
|
|
104
|
+
const raw = fallback.get();
|
|
105
|
+
return raw ? parseCredentials(raw) : null;
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function saveCredentials(credentials, backend) {
|
|
111
|
+
const store = resolveBackend(credentials.mcpUrl, backend);
|
|
112
|
+
try {
|
|
113
|
+
store.set(JSON.stringify(credentials));
|
|
114
|
+
return { backend: store };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (store.kind === 'keyring' && !backend) {
|
|
118
|
+
const fallback = createFileBackend(fileStorePath(credentials.mcpUrl));
|
|
119
|
+
fallback.set(JSON.stringify(credentials));
|
|
120
|
+
return { backend: fallback };
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function deleteCredentials(mcpUrl = defaultMcpUrl, backend) {
|
|
126
|
+
const store = resolveBackend(mcpUrl, backend);
|
|
127
|
+
let deleted = false;
|
|
128
|
+
try {
|
|
129
|
+
deleted = store.delete();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
deleted = false;
|
|
133
|
+
}
|
|
134
|
+
if (store.kind === 'keyring' && !backend) {
|
|
135
|
+
const file = createFileBackend(fileStorePath(mcpUrl));
|
|
136
|
+
deleted = file.delete() || deleted;
|
|
137
|
+
}
|
|
138
|
+
return { deleted, backend: store };
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"name": "@kodycodes/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Kody MCP client CLI: login, secure token storage, search, and execute.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kody": "dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/cli.js",
|
|
10
|
+
"types": "./dist/cli.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/cli.d.ts",
|
|
14
|
+
"default": "./dist/cli.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"skills"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.build.json",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"test": "tsx --test test/*.test.ts",
|
|
25
|
+
"validate": "npm run typecheck && npm run test && npm run build"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"kody",
|
|
32
|
+
"mcp",
|
|
33
|
+
"cli",
|
|
34
|
+
"oauth"
|
|
35
|
+
],
|
|
36
|
+
"author": "Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/kody-bot/cli.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/kody-bot/cli/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://kody.codes",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
51
|
+
"@napi-rs/keyring": "^1.3.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^24.5.2",
|
|
55
|
+
"tsx": "^4.20.5",
|
|
56
|
+
"typescript": "^5.9.2"
|
|
57
|
+
}
|
|
9
58
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kody
|
|
3
|
+
description: >
|
|
4
|
+
Use the Kody CLI to log in, search Kody capabilities, and execute
|
|
5
|
+
sandboxed modules against kody.codes. Use when the user mentions Kody,
|
|
6
|
+
kody.codes, durable agent tasks, or wants to search/execute via `kody`.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Kody CLI
|
|
10
|
+
|
|
11
|
+
Kody is a remote MCP personal assistant. This skill uses the `@kodycodes/cli`
|
|
12
|
+
package — a local MCP client — instead of configuring an MCP server by hand.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g @kodycodes/cli
|
|
18
|
+
# or
|
|
19
|
+
npx @kodycodes/cli --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Then install this skill into the current host if it is not already present:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @kodycodes/cli skill install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Login
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
kody login
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The CLI opens a browser for Kody OAuth (PKCE + dynamic client registration).
|
|
35
|
+
If a browser cannot open, it prints the URL. Tokens (access + refresh) are
|
|
36
|
+
stored in the OS keychain on macOS, Windows, and Linux. Linux without Secret
|
|
37
|
+
Service falls back to a `0600` file under `$XDG_CONFIG_HOME/kody`.
|
|
38
|
+
|
|
39
|
+
Never ask the user to paste tokens into chat.
|
|
40
|
+
|
|
41
|
+
## Use Kody
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
kody search "what can you do"
|
|
45
|
+
kody search --domain email
|
|
46
|
+
kody execute --code "import { kody } from 'kody:runtime'\nexport default async function main() { return await kody.search({ query: 'what can you do' }) }"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`search` and `execute` are Kody's only MCP tools. Prefer `kody search` before
|
|
50
|
+
`kody execute`. Add `--json` when you need structured output.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
kody status
|
|
54
|
+
kody whoami
|
|
55
|
+
kody logout
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Override the MCP URL with `--mcp-url` or `KODY_MCP_URL` for preview or local
|
|
59
|
+
servers. Default: `https://kody.codes/mcp`.
|