@systemdox/mcp-server 0.1.48 → 0.1.49
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 +24 -11
- package/dist/cli.js +462 -260
- package/dist/http.js +203 -61
- package/dist/index.d.ts +2 -1
- package/dist/index.js +348 -168
- package/dist/install-skill.js +1 -2
- package/dist/lib/config.d.ts +4 -1
- package/dist/lib/config.js +1 -2
- package/dist/lib/team-setup-files.d.ts +14 -1
- package/dist/lib/team-setup-files.js +43 -0
- package/dist/setup-mcp.d.ts +66 -0
- package/dist/setup-mcp.js +636 -0
- package/dist/setup-team.d.ts +5 -1
- package/dist/setup-team.js +1 -0
- package/dist/sync-memory.js +22 -12
- package/dist/tools/get-change.d.ts +134 -0
- package/dist/tools/get-change.js +147 -0
- package/dist/tools/skills.js +1 -1
- package/package.json +1 -1
package/dist/install-skill.js
CHANGED
|
@@ -250,8 +250,7 @@ function requireHttpsApiUrl(apiUrl) {
|
|
|
250
250
|
}
|
|
251
251
|
return apiUrl;
|
|
252
252
|
}
|
|
253
|
-
function loadConfig() {
|
|
254
|
-
const apiKey = process.env.SYSTEMDOX_API_KEY;
|
|
253
|
+
function loadConfig(apiKey = process.env.SYSTEMDOX_API_KEY) {
|
|
255
254
|
if (!apiKey) {
|
|
256
255
|
throw new Error(
|
|
257
256
|
"SYSTEMDOX_API_KEY is required. Generate one at your SystemDox settings page."
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -18,4 +18,7 @@ export declare const API_URL_DEFAULT = "https://api.puglieseweb.com/systemdox";
|
|
|
18
18
|
* spare a dev a certificate is not a trade worth making.
|
|
19
19
|
*/
|
|
20
20
|
export declare function requireHttpsApiUrl(apiUrl: string): string;
|
|
21
|
-
|
|
21
|
+
/** The server's settings from the environment. `apiKey` defaults to
|
|
22
|
+
* SYSTEMDOX_API_KEY; the local server passes the key it resolved (that, then
|
|
23
|
+
* ~/.claude/systemdox/credentials.json: `loadLocalConfig`). */
|
|
24
|
+
export declare function loadConfig(apiKey?: string | undefined): ServerConfig;
|
package/dist/lib/config.js
CHANGED
|
@@ -18,8 +18,7 @@ function requireHttpsApiUrl(apiUrl) {
|
|
|
18
18
|
}
|
|
19
19
|
return apiUrl;
|
|
20
20
|
}
|
|
21
|
-
function loadConfig() {
|
|
22
|
-
const apiKey = process.env.SYSTEMDOX_API_KEY;
|
|
21
|
+
function loadConfig(apiKey = process.env.SYSTEMDOX_API_KEY) {
|
|
23
22
|
if (!apiKey) {
|
|
24
23
|
throw new Error(
|
|
25
24
|
"SYSTEMDOX_API_KEY is required. Generate one at your SystemDox settings page."
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
* a test points HOME (USERPROFILE on Windows) at a temporary folder.
|
|
15
15
|
*
|
|
16
16
|
* Also here: the API key's order (SYSTEMDOX_API_KEY, then credentials.json for
|
|
17
|
-
* the workspace
|
|
17
|
+
* the workspace; `setup` writes the key there and nowhere else, not into an AI
|
|
18
|
+
* tool's MCP config) and `marketplace-auth`, the marketplace's `headersHelper`,
|
|
18
19
|
* which reads only these files and the environment.
|
|
19
20
|
*/
|
|
21
|
+
import { type ServerConfig } from "./config.js";
|
|
20
22
|
/** A workspace is a tenant slug (openapi Slug): it names a folder, so nothing
|
|
21
23
|
* else is accepted. */
|
|
22
24
|
export declare function isWorkspace(value: unknown): value is string;
|
|
@@ -41,6 +43,17 @@ export declare function writeCredentials(workspace: string, apiKey: string): Pro
|
|
|
41
43
|
/** The key for `workspace`, in the contract's order: SYSTEMDOX_API_KEY, then
|
|
42
44
|
* credentials.json for the workspace. Undefined when neither has one. */
|
|
43
45
|
export declare function apiKeyFor(workspace: string, env?: NodeJS.ProcessEnv): Promise<string | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* The key for a command that is not told the workspace: the local MCP server
|
|
48
|
+
* and `sync-memory`. SYSTEMDOX_API_KEY; then credentials.json: the key of
|
|
49
|
+
* SYSTEMDOX_WORKSPACE when it is set, otherwise of the one workspace the file
|
|
50
|
+
* holds. Throws, naming SYSTEMDOX_API_KEY and SYSTEMDOX_WORKSPACE, when that
|
|
51
|
+
* names no key or several.
|
|
52
|
+
*/
|
|
53
|
+
export declare function localApiKey(env?: NodeJS.ProcessEnv): Promise<string>;
|
|
54
|
+
/** The local (stdio) server's settings: `loadConfig` with the key from
|
|
55
|
+
* `localApiKey`. The hosted server takes each request's key and never reads this. */
|
|
56
|
+
export declare function loadLocalConfig(env?: NodeJS.ProcessEnv): Promise<ServerConfig>;
|
|
44
57
|
/** SYSTEMDOX_API_URL or the default, https only (throws otherwise). */
|
|
45
58
|
export declare function apiUrlFrom(env?: NodeJS.ProcessEnv): string;
|
|
46
59
|
export interface TeamSetupState {
|
|
@@ -25,6 +25,22 @@ function requireHttpsApiUrl(apiUrl) {
|
|
|
25
25
|
}
|
|
26
26
|
return apiUrl;
|
|
27
27
|
}
|
|
28
|
+
function loadConfig(apiKey = process.env.SYSTEMDOX_API_KEY) {
|
|
29
|
+
if (!apiKey) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"SYSTEMDOX_API_KEY is required. Generate one at your SystemDox settings page."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const apiUrl = requireHttpsApiUrl(
|
|
35
|
+
process.env.SYSTEMDOX_API_URL ?? API_URL_DEFAULT
|
|
36
|
+
);
|
|
37
|
+
return {
|
|
38
|
+
apiKey,
|
|
39
|
+
apiUrl,
|
|
40
|
+
cacheTtlMs: parseInt(process.env.SYSTEMDOX_CACHE_TTL ?? "300", 10) * 1e3,
|
|
41
|
+
defaultOrg: process.env.SYSTEMDOX_DEFAULT_ORG
|
|
42
|
+
};
|
|
43
|
+
}
|
|
28
44
|
|
|
29
45
|
// src/lib/team-setup-files.ts
|
|
30
46
|
var SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -97,6 +113,31 @@ async function apiKeyFor(workspace, env = process.env) {
|
|
|
97
113
|
const entry = (await readCredentials())[workspace];
|
|
98
114
|
return typeof entry?.apiKey === "string" && entry.apiKey ? entry.apiKey : void 0;
|
|
99
115
|
}
|
|
116
|
+
async function localApiKey(env = process.env) {
|
|
117
|
+
if (env.SYSTEMDOX_API_KEY) return env.SYSTEMDOX_API_KEY;
|
|
118
|
+
const keys = Object.entries(await readCredentials()).filter(
|
|
119
|
+
(e) => typeof e[1]?.apiKey === "string" && e[1].apiKey.length > 0
|
|
120
|
+
);
|
|
121
|
+
const wanted = env.SYSTEMDOX_WORKSPACE;
|
|
122
|
+
if (wanted) {
|
|
123
|
+
const key = keys.find(([ws]) => ws === wanted)?.[1].apiKey;
|
|
124
|
+
if (key) return key;
|
|
125
|
+
throw new Error(
|
|
126
|
+
`~/.claude/systemdox/credentials.json holds no key for ${wanted} (SYSTEMDOX_WORKSPACE). Set SYSTEMDOX_API_KEY, or run npx -y @systemdox/mcp-server setup.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
if (keys.length === 1) return keys[0][1].apiKey;
|
|
130
|
+
if (keys.length > 1) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`~/.claude/systemdox/credentials.json holds keys for ${keys.map(([ws]) => ws).join(", ")}: set SYSTEMDOX_WORKSPACE to the workspace to use, or SYSTEMDOX_API_KEY to its key.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
throw new Error("No SystemDox key. Set SYSTEMDOX_API_KEY, or run npx -y @systemdox/mcp-server setup.");
|
|
136
|
+
}
|
|
137
|
+
async function loadLocalConfig(env = process.env) {
|
|
138
|
+
const apiKey = await localApiKey(env);
|
|
139
|
+
return loadConfig(apiKey);
|
|
140
|
+
}
|
|
100
141
|
function apiUrlFrom(env = process.env) {
|
|
101
142
|
return requireHttpsApiUrl(env.SYSTEMDOX_API_URL || API_URL_DEFAULT);
|
|
102
143
|
}
|
|
@@ -174,6 +215,8 @@ export {
|
|
|
174
215
|
credentialsPath,
|
|
175
216
|
homeDir,
|
|
176
217
|
isWorkspace,
|
|
218
|
+
loadLocalConfig,
|
|
219
|
+
localApiKey,
|
|
177
220
|
marketplaceWorkspace,
|
|
178
221
|
pluginDir,
|
|
179
222
|
pluginRoot,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `setup`'s first step: write the SystemDox MCP server into an AI tool's
|
|
3
|
+
* config (Claude Code's project `.mcp.json` or `~/.claude.json`, Cursor's,
|
|
4
|
+
* VS Code's). The team setup (`setup-team.ts`) follows it.
|
|
5
|
+
*
|
|
6
|
+
* The key is stored once (specs/changes/team-setup/contract.md "The API key",
|
|
7
|
+
* proposal item 7): in `~/.claude/systemdox/credentials.json` for the key's
|
|
8
|
+
* workspace, readable by the member alone. The server entry this step writes
|
|
9
|
+
* carries no key; the local server reads it from SYSTEMDOX_API_KEY, then from
|
|
10
|
+
* credentials.json (`loadLocalConfig`). A key an earlier `setup` wrote into
|
|
11
|
+
* the entry is removed from it, and nothing else in that file changes.
|
|
12
|
+
*/
|
|
13
|
+
import type { TeamSetup } from "./lib/team-setup-types.js";
|
|
14
|
+
export interface McpServerEntry {
|
|
15
|
+
command: string;
|
|
16
|
+
args: string[];
|
|
17
|
+
env?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export interface McpConfigTarget {
|
|
20
|
+
name: string;
|
|
21
|
+
path: string;
|
|
22
|
+
detected: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface McpSetupOptions {
|
|
25
|
+
out: (line: string) => void;
|
|
26
|
+
err: (line: string) => void;
|
|
27
|
+
ask: (question: string) => Promise<string>;
|
|
28
|
+
/** The folder whose project configs are offered (default: the current folder). */
|
|
29
|
+
cwd?: string;
|
|
30
|
+
env?: NodeJS.ProcessEnv;
|
|
31
|
+
/** Checks the key against the API (default: `GET /v1/health`). */
|
|
32
|
+
validateKey?: (apiKey: string, apiUrl: string) => Promise<boolean>;
|
|
33
|
+
/** Names the key's workspace (default: `GET /team-setup` with the key). */
|
|
34
|
+
client?: (apiKey: string, apiUrl: string) => {
|
|
35
|
+
getOwnTeamSetup(): Promise<TeamSetup>;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export type McpSetupResult = {
|
|
39
|
+
code: 0;
|
|
40
|
+
apiKey: string;
|
|
41
|
+
apiUrl: string;
|
|
42
|
+
workspace: string;
|
|
43
|
+
} | {
|
|
44
|
+
code: 1;
|
|
45
|
+
};
|
|
46
|
+
export declare function findConfigTargets(cwd?: string): McpConfigTarget[];
|
|
47
|
+
/**
|
|
48
|
+
* The `systemdox` server entry: the command and args, and in `env` only
|
|
49
|
+
* SYSTEMDOX_API_URL when it is not the default. Never the key. Other variables
|
|
50
|
+
* the member set on an existing entry are kept, and so is a `${NAME}`
|
|
51
|
+
* reference for SYSTEMDOX_API_KEY (the member's own environment, not a key).
|
|
52
|
+
* `workspace` is set as SYSTEMDOX_WORKSPACE when credentials.json holds keys
|
|
53
|
+
* for several workspaces, so the server knows which one to use.
|
|
54
|
+
*/
|
|
55
|
+
export declare function serverEntry(apiUrl: string, existing?: unknown, workspace?: string): McpServerEntry;
|
|
56
|
+
/**
|
|
57
|
+
* Set the `systemdox` entry in the config at `path`, creating the file when
|
|
58
|
+
* absent; every other byte of an existing file is kept. Returns true when the
|
|
59
|
+
* entry held a key, which it no longer does.
|
|
60
|
+
*/
|
|
61
|
+
export declare function writeServerEntry(path: string, apiUrl: string, workspace?: string): Promise<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* The first step of `setup`. Every line goes to `opts.out` / `opts.err`;
|
|
64
|
+
* code 1 means nothing was changed.
|
|
65
|
+
*/
|
|
66
|
+
export declare function setupMcpServer(opts: McpSetupOptions): Promise<McpSetupResult>;
|