@structured-vibe-coding/core 0.14.3 → 0.16.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/defaults/mcp.yaml +53 -0
- package/dist/{agents-WL3PNTJL.js → agents-7NS5LFEZ.js} +2 -2
- package/dist/{chunk-HOH43IQ2.js → chunk-24EXBX7P.js} +4 -4
- package/dist/{chunk-S7SHVKG4.js → chunk-GR7KIAR2.js} +4 -4
- package/dist/chunk-KYWETNFU.js +147 -0
- package/dist/{chunk-C725DWSB.js → chunk-RRBKQ76B.js} +32 -1
- package/dist/chunk-VD3CPFAI.js +236 -0
- package/dist/gather-74DQ35QX.js +15 -0
- package/dist/{greenfield-SY3SB5OT.js → greenfield-3ZH5OASX.js} +2 -2
- package/dist/index.d.ts +398 -1
- package/dist/index.js +82 -24
- package/dist/sources-PF45EUH2.js +24 -0
- package/package.json +2 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# External MCP *sources* that sdd will *call* (sdd = client).
|
|
2
|
+
# Not the same as `sdd mcp serve` (that exposes sdd tools *to* agents).
|
|
3
|
+
#
|
|
4
|
+
# Use cases:
|
|
5
|
+
# - Org UI/UX / design-system MCP
|
|
6
|
+
# - Internal API catalog MCP
|
|
7
|
+
# - Third-party or custom AST / code-search MCP
|
|
8
|
+
#
|
|
9
|
+
# sdd matches sources by stage / workflow / keywords / intents, then invokes
|
|
10
|
+
# the configured tool and can embed results in agent handoff.
|
|
11
|
+
#
|
|
12
|
+
# Add via CLI:
|
|
13
|
+
# sdd mcp sources add --id design-system --command npx --arg -y --arg @acme/ds-mcp \
|
|
14
|
+
# --stages design,implement --intents ui,design --tool search_components \
|
|
15
|
+
# --tool-arg query={{query}}
|
|
16
|
+
#
|
|
17
|
+
version: 1
|
|
18
|
+
auto_fetch_on_handoff: true
|
|
19
|
+
max_chars_per_source: 6000
|
|
20
|
+
sources: []
|
|
21
|
+
|
|
22
|
+
# Example (uncomment and edit):
|
|
23
|
+
#
|
|
24
|
+
# sources:
|
|
25
|
+
# - id: design-system
|
|
26
|
+
# description: Acme design system components and tokens
|
|
27
|
+
# command: npx
|
|
28
|
+
# args: ["-y", "@acme/design-system-mcp"]
|
|
29
|
+
# priority: 20
|
|
30
|
+
# when:
|
|
31
|
+
# stages: [design, implement, stories]
|
|
32
|
+
# workflows: [feature, enterprise-feature]
|
|
33
|
+
# intents: [ui, design, component]
|
|
34
|
+
# keywords: [button, token, theme, component]
|
|
35
|
+
# invoke:
|
|
36
|
+
# tool: search_components
|
|
37
|
+
# args:
|
|
38
|
+
# query: "{{query}}"
|
|
39
|
+
#
|
|
40
|
+
# - id: code-ast
|
|
41
|
+
# description: AST / symbol search for this monorepo (external engine)
|
|
42
|
+
# command: npx
|
|
43
|
+
# args: ["-y", "@example/ast-search-mcp"]
|
|
44
|
+
# cwd: "{{projectRoot}}"
|
|
45
|
+
# priority: 30
|
|
46
|
+
# when:
|
|
47
|
+
# stages: [implement, code_research, local_verify]
|
|
48
|
+
# intents: [code, implement]
|
|
49
|
+
# invoke:
|
|
50
|
+
# tool: search
|
|
51
|
+
# args:
|
|
52
|
+
# query: "{{query}}"
|
|
53
|
+
# root: "{{projectRoot}}"
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
removeOtherAgentHosts,
|
|
20
20
|
renderThinAgent,
|
|
21
21
|
writeAgentHandoff
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GR7KIAR2.js";
|
|
23
|
+
import "./chunk-RRBKQ76B.js";
|
|
23
24
|
import "./chunk-OJFMJHNL.js";
|
|
24
|
-
import "./chunk-C725DWSB.js";
|
|
25
25
|
import "./chunk-A752UVPF.js";
|
|
26
26
|
import "./chunk-67AUAGNV.js";
|
|
27
27
|
import "./chunk-7MJYPJMR.js";
|
|
@@ -245,7 +245,7 @@ async function createChange(input) {
|
|
|
245
245
|
await materializeStageArtifacts(projectRoot, config, id, workflow, meta, firstStage);
|
|
246
246
|
await setActiveChange(projectRoot, config, id);
|
|
247
247
|
try {
|
|
248
|
-
const { refreshActiveAgentContext } = await import("./agents-
|
|
248
|
+
const { refreshActiveAgentContext } = await import("./agents-7NS5LFEZ.js");
|
|
249
249
|
await refreshActiveAgentContext(projectRoot);
|
|
250
250
|
} catch {
|
|
251
251
|
}
|
|
@@ -333,7 +333,7 @@ async function advanceStage(projectRoot, config, changeId, opts) {
|
|
|
333
333
|
stage2
|
|
334
334
|
);
|
|
335
335
|
try {
|
|
336
|
-
const { refreshActiveAgentContext } = await import("./agents-
|
|
336
|
+
const { refreshActiveAgentContext } = await import("./agents-7NS5LFEZ.js");
|
|
337
337
|
await refreshActiveAgentContext(projectRoot);
|
|
338
338
|
} catch {
|
|
339
339
|
}
|
|
@@ -380,7 +380,7 @@ async function advanceStage(projectRoot, config, changeId, opts) {
|
|
|
380
380
|
stage
|
|
381
381
|
);
|
|
382
382
|
try {
|
|
383
|
-
const { refreshActiveAgentContext } = await import("./agents-
|
|
383
|
+
const { refreshActiveAgentContext } = await import("./agents-7NS5LFEZ.js");
|
|
384
384
|
await refreshActiveAgentContext(projectRoot);
|
|
385
385
|
} catch {
|
|
386
386
|
}
|
|
@@ -484,7 +484,7 @@ async function completeChange(projectRoot, config, changeId) {
|
|
|
484
484
|
let promoted;
|
|
485
485
|
if (ctx.meta.workflow === "greenfield" || ctx.meta.flags?.greenfield === true) {
|
|
486
486
|
try {
|
|
487
|
-
const { promoteGreenfieldToMemory: promoteGreenfieldToMemory2 } = await import("./greenfield-
|
|
487
|
+
const { promoteGreenfieldToMemory: promoteGreenfieldToMemory2 } = await import("./greenfield-3ZH5OASX.js");
|
|
488
488
|
promoted = await promoteGreenfieldToMemory2(projectRoot, config, changeId);
|
|
489
489
|
} catch {
|
|
490
490
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
loadConfig
|
|
3
|
-
} from "./chunk-OJFMJHNL.js";
|
|
4
1
|
import {
|
|
5
2
|
buildAgentPrompt,
|
|
6
3
|
formatStatus
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RRBKQ76B.js";
|
|
5
|
+
import {
|
|
6
|
+
loadConfig
|
|
7
|
+
} from "./chunk-OJFMJHNL.js";
|
|
8
8
|
import {
|
|
9
9
|
buildContext,
|
|
10
10
|
getActiveChangeId
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sddRoot
|
|
3
|
+
} from "./chunk-7MJYPJMR.js";
|
|
4
|
+
import {
|
|
5
|
+
ensureDir,
|
|
6
|
+
pathExists,
|
|
7
|
+
readYaml,
|
|
8
|
+
writeYaml
|
|
9
|
+
} from "./chunk-EPFURATC.js";
|
|
10
|
+
|
|
11
|
+
// src/mcp/sources.ts
|
|
12
|
+
import { join } from "pathe";
|
|
13
|
+
|
|
14
|
+
// src/mcp/types.ts
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
var McpWhenSchema = z.object({
|
|
17
|
+
/** Empty = all stages */
|
|
18
|
+
stages: z.array(z.string()).default([]),
|
|
19
|
+
/** Empty = all workflows */
|
|
20
|
+
workflows: z.array(z.string()).default([]),
|
|
21
|
+
/** Match title/query (case-insensitive substring) */
|
|
22
|
+
keywords: z.array(z.string()).default([]),
|
|
23
|
+
/**
|
|
24
|
+
* High-level intent tags the operator or tool may pass:
|
|
25
|
+
* code | ui | design | api | docs | data
|
|
26
|
+
*/
|
|
27
|
+
intents: z.array(z.string()).default([])
|
|
28
|
+
});
|
|
29
|
+
var McpInvokeSchema = z.object({
|
|
30
|
+
/** Tool name on the remote MCP server */
|
|
31
|
+
tool: z.string(),
|
|
32
|
+
/**
|
|
33
|
+
* Static args + templates:
|
|
34
|
+
* {{query}} {{title}} {{stage}} {{workflow}} {{projectRoot}}
|
|
35
|
+
*/
|
|
36
|
+
args: z.record(z.unknown()).default({})
|
|
37
|
+
});
|
|
38
|
+
var McpSourceSchema = z.object({
|
|
39
|
+
id: z.string().min(1),
|
|
40
|
+
description: z.string().default(""),
|
|
41
|
+
/** stdio only in v1 */
|
|
42
|
+
transport: z.enum(["stdio"]).default("stdio"),
|
|
43
|
+
command: z.string().min(1),
|
|
44
|
+
args: z.array(z.string()).default([]),
|
|
45
|
+
env: z.record(z.string()).default({}),
|
|
46
|
+
/** Working directory (default: project root). Supports {{projectRoot}} */
|
|
47
|
+
cwd: z.string().optional(),
|
|
48
|
+
enabled: z.boolean().default(true),
|
|
49
|
+
/** Higher runs first when gathering */
|
|
50
|
+
priority: z.number().default(0),
|
|
51
|
+
when: McpWhenSchema.default({}),
|
|
52
|
+
/**
|
|
53
|
+
* How sdd calls this source when auto-gathering for a stage.
|
|
54
|
+
* If omitted, `sdd mcp fetch` still works with an explicit --tool.
|
|
55
|
+
*/
|
|
56
|
+
invoke: McpInvokeSchema.optional(),
|
|
57
|
+
/** Optional allowlist of tool names (documentation / validation) */
|
|
58
|
+
tools: z.array(z.string()).optional()
|
|
59
|
+
});
|
|
60
|
+
var McpConfigSchema = z.object({
|
|
61
|
+
version: z.number().default(1),
|
|
62
|
+
/**
|
|
63
|
+
* When true, handoff generation calls matching sources with `invoke` and
|
|
64
|
+
* embeds results under "External MCP context".
|
|
65
|
+
*/
|
|
66
|
+
auto_fetch_on_handoff: z.boolean().default(true),
|
|
67
|
+
/** Max chars of MCP output embedded into handoff per source */
|
|
68
|
+
max_chars_per_source: z.number().default(6e3),
|
|
69
|
+
sources: z.array(McpSourceSchema).default([])
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// src/mcp/sources.ts
|
|
73
|
+
function mcpConfigPath(projectRoot) {
|
|
74
|
+
return join(sddRoot(projectRoot), "mcp.yaml");
|
|
75
|
+
}
|
|
76
|
+
function defaultMcpConfig() {
|
|
77
|
+
return McpConfigSchema.parse({
|
|
78
|
+
version: 1,
|
|
79
|
+
auto_fetch_on_handoff: true,
|
|
80
|
+
max_chars_per_source: 6e3,
|
|
81
|
+
sources: []
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function loadMcpConfig(projectRoot) {
|
|
85
|
+
const path = mcpConfigPath(projectRoot);
|
|
86
|
+
if (!await pathExists(path)) {
|
|
87
|
+
return defaultMcpConfig();
|
|
88
|
+
}
|
|
89
|
+
const raw = await readYaml(path);
|
|
90
|
+
return McpConfigSchema.parse(raw ?? {});
|
|
91
|
+
}
|
|
92
|
+
async function saveMcpConfig(projectRoot, config) {
|
|
93
|
+
await ensureDir(sddRoot(projectRoot));
|
|
94
|
+
const path = mcpConfigPath(projectRoot);
|
|
95
|
+
await writeYaml(path, McpConfigSchema.parse(config));
|
|
96
|
+
return path;
|
|
97
|
+
}
|
|
98
|
+
async function ensureMcpConfig(projectRoot) {
|
|
99
|
+
const path = mcpConfigPath(projectRoot);
|
|
100
|
+
if (!await pathExists(path)) {
|
|
101
|
+
const cfg = defaultMcpConfig();
|
|
102
|
+
await saveMcpConfig(projectRoot, cfg);
|
|
103
|
+
return cfg;
|
|
104
|
+
}
|
|
105
|
+
return loadMcpConfig(projectRoot);
|
|
106
|
+
}
|
|
107
|
+
async function addMcpSource(projectRoot, source) {
|
|
108
|
+
const cfg = await ensureMcpConfig(projectRoot);
|
|
109
|
+
const parsed = McpSourceSchema.parse(source);
|
|
110
|
+
const rest = cfg.sources.filter((s) => s.id !== parsed.id);
|
|
111
|
+
cfg.sources = [...rest, parsed].sort((a, b) => b.priority - a.priority);
|
|
112
|
+
await saveMcpConfig(projectRoot, cfg);
|
|
113
|
+
return cfg;
|
|
114
|
+
}
|
|
115
|
+
async function removeMcpSource(projectRoot, id) {
|
|
116
|
+
const cfg = await ensureMcpConfig(projectRoot);
|
|
117
|
+
cfg.sources = cfg.sources.filter((s) => s.id !== id);
|
|
118
|
+
await saveMcpConfig(projectRoot, cfg);
|
|
119
|
+
return cfg;
|
|
120
|
+
}
|
|
121
|
+
function interpolate(value, vars) {
|
|
122
|
+
return value.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
|
|
123
|
+
}
|
|
124
|
+
function interpolateArgs(args, vars) {
|
|
125
|
+
const out = {};
|
|
126
|
+
for (const [k, v] of Object.entries(args)) {
|
|
127
|
+
if (typeof v === "string") out[k] = interpolate(v, vars);
|
|
128
|
+
else out[k] = v;
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
McpWhenSchema,
|
|
135
|
+
McpInvokeSchema,
|
|
136
|
+
McpSourceSchema,
|
|
137
|
+
McpConfigSchema,
|
|
138
|
+
mcpConfigPath,
|
|
139
|
+
defaultMcpConfig,
|
|
140
|
+
loadMcpConfig,
|
|
141
|
+
saveMcpConfig,
|
|
142
|
+
ensureMcpConfig,
|
|
143
|
+
addMcpSource,
|
|
144
|
+
removeMcpSource,
|
|
145
|
+
interpolate,
|
|
146
|
+
interpolateArgs
|
|
147
|
+
};
|
|
@@ -106,10 +106,41 @@ async function buildAgentPrompt(ctx, config, projectRoot) {
|
|
|
106
106
|
`2. If present, read: \`changes/${ctx.id}/code-context.md\` (regenerate if stale)`
|
|
107
107
|
);
|
|
108
108
|
parts.push(
|
|
109
|
-
`
|
|
109
|
+
`3. Org libraries / remote AST: configure \`.sdd/mcp.yaml\` and \`sdd mcp fetch\` (see External MCP context below)`
|
|
110
|
+
);
|
|
111
|
+
parts.push(
|
|
112
|
+
`Do not dump unbounded source into the prompt; prefer sliced / MCP output.`
|
|
110
113
|
);
|
|
111
114
|
parts.push("");
|
|
112
115
|
}
|
|
116
|
+
try {
|
|
117
|
+
const { loadMcpConfig } = await import("./sources-PF45EUH2.js");
|
|
118
|
+
const {
|
|
119
|
+
gatherMcpContextForChange,
|
|
120
|
+
formatMcpContextForHandoff
|
|
121
|
+
} = await import("./gather-74DQ35QX.js");
|
|
122
|
+
const mcpCfg = await loadMcpConfig(projectRoot);
|
|
123
|
+
if (mcpCfg.auto_fetch_on_handoff && mcpCfg.sources.length) {
|
|
124
|
+
const fetched = await gatherMcpContextForChange(projectRoot, ctx);
|
|
125
|
+
const block = formatMcpContextForHandoff(
|
|
126
|
+
fetched.filter((r) => r.ok || r.error)
|
|
127
|
+
);
|
|
128
|
+
if (block) {
|
|
129
|
+
parts.push(block);
|
|
130
|
+
}
|
|
131
|
+
} else if (mcpCfg.sources.length === 0) {
|
|
132
|
+
parts.push(`## External MCP sources`);
|
|
133
|
+
parts.push("");
|
|
134
|
+
parts.push(
|
|
135
|
+
`No sources in \`.sdd/mcp.yaml\` yet. To attach org libraries / AST engines:`
|
|
136
|
+
);
|
|
137
|
+
parts.push(
|
|
138
|
+
`\`sdd mcp sources add --help\` \xB7 docs: Configure MCP sources`
|
|
139
|
+
);
|
|
140
|
+
parts.push("");
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
113
144
|
parts.push(
|
|
114
145
|
`When done with this stage, the human will run \`sdd next\` or \`sdd verify\` / \`sdd complete\`.`
|
|
115
146
|
);
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
interpolate,
|
|
3
|
+
interpolateArgs,
|
|
4
|
+
loadMcpConfig
|
|
5
|
+
} from "./chunk-KYWETNFU.js";
|
|
6
|
+
|
|
7
|
+
// src/mcp/client.ts
|
|
8
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10
|
+
function contentToText(result) {
|
|
11
|
+
const parts = result.content ?? [];
|
|
12
|
+
return parts.map((p) => p.type === "text" ? p.text ?? "" : JSON.stringify(p)).join("\n").trim();
|
|
13
|
+
}
|
|
14
|
+
async function withMcpSource(source, projectRoot, fn) {
|
|
15
|
+
const vars = { projectRoot };
|
|
16
|
+
const cwd = source.cwd ? interpolate(source.cwd, vars) : projectRoot;
|
|
17
|
+
const env = {
|
|
18
|
+
...process.env,
|
|
19
|
+
...source.env,
|
|
20
|
+
SDD_PROJECT_ROOT: projectRoot
|
|
21
|
+
};
|
|
22
|
+
const transport = new StdioClientTransport({
|
|
23
|
+
command: source.command,
|
|
24
|
+
args: source.args,
|
|
25
|
+
cwd,
|
|
26
|
+
env
|
|
27
|
+
});
|
|
28
|
+
const client = new Client({
|
|
29
|
+
name: "sdd-mcp-client",
|
|
30
|
+
version: "0.14.0"
|
|
31
|
+
});
|
|
32
|
+
await client.connect(transport);
|
|
33
|
+
try {
|
|
34
|
+
return await fn(client);
|
|
35
|
+
} finally {
|
|
36
|
+
try {
|
|
37
|
+
await client.close();
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function listMcpSourceTools(source, projectRoot) {
|
|
43
|
+
return withMcpSource(source, projectRoot, async (client) => {
|
|
44
|
+
const listed = await client.listTools();
|
|
45
|
+
return listed.tools.map((t) => ({
|
|
46
|
+
name: t.name,
|
|
47
|
+
description: t.description
|
|
48
|
+
}));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async function callMcpSourceTool(source, projectRoot, tool, args) {
|
|
52
|
+
try {
|
|
53
|
+
if (source.tools?.length && !source.tools.includes(tool)) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
text: "",
|
|
57
|
+
error: `Tool "${tool}" not in allowlist for source ${source.id}: ${source.tools.join(", ")}`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return await withMcpSource(source, projectRoot, async (client) => {
|
|
61
|
+
const result = await client.callTool({ name: tool, arguments: args });
|
|
62
|
+
const text = contentToText(result);
|
|
63
|
+
const isError = Boolean(result.isError);
|
|
64
|
+
return {
|
|
65
|
+
ok: !isError,
|
|
66
|
+
text: text || (isError ? "(empty error result)" : "(empty)"),
|
|
67
|
+
error: isError ? text || "tool returned isError" : void 0
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
} catch (err) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
text: "",
|
|
74
|
+
error: err instanceof Error ? err.message : String(err)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/mcp/match.ts
|
|
80
|
+
function includesCI(list, value) {
|
|
81
|
+
const v = value.toLowerCase();
|
|
82
|
+
return list.some((x) => x.toLowerCase() === v);
|
|
83
|
+
}
|
|
84
|
+
function matchMcpSources(sources, ctx) {
|
|
85
|
+
const stage = ctx.stage ?? "";
|
|
86
|
+
const workflow = ctx.workflow ?? "";
|
|
87
|
+
const query = (ctx.query ?? "").toLowerCase();
|
|
88
|
+
const intents = (ctx.intents ?? []).map((i) => i.toLowerCase());
|
|
89
|
+
const matched = sources.filter((s) => {
|
|
90
|
+
if (!s.enabled) return false;
|
|
91
|
+
const w = s.when;
|
|
92
|
+
if (w.stages.length && stage && !includesCI(w.stages, stage)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (w.workflows.length && workflow && !includesCI(w.workflows, workflow)) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (w.intents.length && intents.length) {
|
|
99
|
+
const hit = w.intents.some((i) => intents.includes(i.toLowerCase()));
|
|
100
|
+
if (!hit) return false;
|
|
101
|
+
}
|
|
102
|
+
if (w.keywords.length && query) {
|
|
103
|
+
const hit = w.keywords.some((k) => query.includes(k.toLowerCase()));
|
|
104
|
+
if (!hit) return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
});
|
|
108
|
+
return matched.sort((a, b) => b.priority - a.priority);
|
|
109
|
+
}
|
|
110
|
+
function explainMatch(source, ctx) {
|
|
111
|
+
const bits = [];
|
|
112
|
+
if (source.when.stages.length) {
|
|
113
|
+
bits.push(`stages=[${source.when.stages.join(",")}]`);
|
|
114
|
+
} else bits.push("stages=*");
|
|
115
|
+
if (source.when.workflows.length) {
|
|
116
|
+
bits.push(`workflows=[${source.when.workflows.join(",")}]`);
|
|
117
|
+
}
|
|
118
|
+
if (source.when.intents.length) {
|
|
119
|
+
bits.push(`intents=[${source.when.intents.join(",")}]`);
|
|
120
|
+
}
|
|
121
|
+
if (source.when.keywords.length) {
|
|
122
|
+
bits.push(`keywords=[${source.when.keywords.join(",")}]`);
|
|
123
|
+
}
|
|
124
|
+
const ok = matchMcpSources([source], ctx).length > 0;
|
|
125
|
+
return `${ok ? "MATCH" : "skip"} ${source.id} (${bits.join(" ")}) stage=${ctx.stage ?? "?"} workflow=${ctx.workflow ?? "?"}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/mcp/gather.ts
|
|
129
|
+
async function gatherMcpContext(opts) {
|
|
130
|
+
const cfg = await loadMcpConfig(opts.projectRoot);
|
|
131
|
+
let sources = matchMcpSources(cfg.sources, opts.match);
|
|
132
|
+
if (opts.sourceIds?.length) {
|
|
133
|
+
const allow = new Set(opts.sourceIds);
|
|
134
|
+
sources = sources.filter((s) => allow.has(s.id));
|
|
135
|
+
}
|
|
136
|
+
const vars = {
|
|
137
|
+
projectRoot: opts.projectRoot,
|
|
138
|
+
query: opts.match.query ?? "",
|
|
139
|
+
title: opts.match.query ?? "",
|
|
140
|
+
stage: opts.match.stage ?? "",
|
|
141
|
+
workflow: opts.match.workflow ?? ""
|
|
142
|
+
};
|
|
143
|
+
const results = [];
|
|
144
|
+
for (const source of sources) {
|
|
145
|
+
const tool = opts.tool ?? source.invoke?.tool;
|
|
146
|
+
if (!tool) {
|
|
147
|
+
if (opts.requireInvoke !== false && !opts.tool) {
|
|
148
|
+
results.push({
|
|
149
|
+
sourceId: source.id,
|
|
150
|
+
tool: "(none)",
|
|
151
|
+
ok: false,
|
|
152
|
+
text: "",
|
|
153
|
+
error: "No invoke.tool configured. Set invoke in .sdd/mcp.yaml or pass --tool."
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const baseArgs = opts.args ?? source.invoke?.args ?? {};
|
|
159
|
+
const args = interpolateArgs(
|
|
160
|
+
baseArgs,
|
|
161
|
+
vars
|
|
162
|
+
);
|
|
163
|
+
const called = await callMcpSourceTool(
|
|
164
|
+
source,
|
|
165
|
+
opts.projectRoot,
|
|
166
|
+
tool,
|
|
167
|
+
args
|
|
168
|
+
);
|
|
169
|
+
const max = cfg.max_chars_per_source ?? 6e3;
|
|
170
|
+
let text = called.text;
|
|
171
|
+
if (text.length > max) {
|
|
172
|
+
text = `${text.slice(0, max)}
|
|
173
|
+
|
|
174
|
+
\u2026(truncated at max_chars_per_source=${max})`;
|
|
175
|
+
}
|
|
176
|
+
results.push({
|
|
177
|
+
sourceId: source.id,
|
|
178
|
+
tool,
|
|
179
|
+
ok: called.ok,
|
|
180
|
+
text,
|
|
181
|
+
error: called.error
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
186
|
+
async function gatherMcpContextForChange(projectRoot, ctx, extra) {
|
|
187
|
+
const cfg = await loadMcpConfig(projectRoot);
|
|
188
|
+
if (!cfg.auto_fetch_on_handoff && !extra?.query) {
|
|
189
|
+
}
|
|
190
|
+
return gatherMcpContext({
|
|
191
|
+
projectRoot,
|
|
192
|
+
match: {
|
|
193
|
+
stage: ctx.meta.stage,
|
|
194
|
+
workflow: ctx.meta.workflow,
|
|
195
|
+
query: extra?.query ?? ctx.meta.title,
|
|
196
|
+
intents: extra?.intents
|
|
197
|
+
},
|
|
198
|
+
requireInvoke: true
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function formatMcpContextForHandoff(results) {
|
|
202
|
+
if (!results.length) return "";
|
|
203
|
+
const parts = [
|
|
204
|
+
"## External MCP context",
|
|
205
|
+
"",
|
|
206
|
+
"Pulled from project-configured MCP *sources* (`.sdd/mcp.yaml`).",
|
|
207
|
+
"Use this instead of guessing org libraries / design systems / remote AST indexes.",
|
|
208
|
+
""
|
|
209
|
+
];
|
|
210
|
+
for (const r of results) {
|
|
211
|
+
parts.push(`### Source \`${r.sourceId}\` (tool: \`${r.tool}\`)`);
|
|
212
|
+
parts.push("");
|
|
213
|
+
if (!r.ok) {
|
|
214
|
+
parts.push(`_Error: ${r.error ?? "failed"}_`);
|
|
215
|
+
} else {
|
|
216
|
+
parts.push(r.text || "_(empty)_");
|
|
217
|
+
}
|
|
218
|
+
parts.push("");
|
|
219
|
+
}
|
|
220
|
+
return parts.join("\n");
|
|
221
|
+
}
|
|
222
|
+
function listMatchingSourceIds(sources, match) {
|
|
223
|
+
return matchMcpSources(sources, match).map((s) => s.id);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export {
|
|
227
|
+
withMcpSource,
|
|
228
|
+
listMcpSourceTools,
|
|
229
|
+
callMcpSourceTool,
|
|
230
|
+
matchMcpSources,
|
|
231
|
+
explainMatch,
|
|
232
|
+
gatherMcpContext,
|
|
233
|
+
gatherMcpContextForChange,
|
|
234
|
+
formatMcpContextForHandoff,
|
|
235
|
+
listMatchingSourceIds
|
|
236
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatMcpContextForHandoff,
|
|
3
|
+
gatherMcpContext,
|
|
4
|
+
gatherMcpContextForChange,
|
|
5
|
+
listMatchingSourceIds
|
|
6
|
+
} from "./chunk-VD3CPFAI.js";
|
|
7
|
+
import "./chunk-KYWETNFU.js";
|
|
8
|
+
import "./chunk-7MJYPJMR.js";
|
|
9
|
+
import "./chunk-EPFURATC.js";
|
|
10
|
+
export {
|
|
11
|
+
formatMcpContextForHandoff,
|
|
12
|
+
gatherMcpContext,
|
|
13
|
+
gatherMcpContextForChange,
|
|
14
|
+
listMatchingSourceIds
|
|
15
|
+
};
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
startFeatureFromBacklog,
|
|
7
7
|
startGreenfield,
|
|
8
8
|
updateFeatureStatus
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-24EXBX7P.js";
|
|
10
|
+
import "./chunk-RRBKQ76B.js";
|
|
11
11
|
import "./chunk-A752UVPF.js";
|
|
12
12
|
import "./chunk-67AUAGNV.js";
|
|
13
13
|
import "./chunk-7MJYPJMR.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
3
|
|
|
3
4
|
declare const GateSchema: z.ZodObject<{
|
|
4
5
|
type: z.ZodDefault<z.ZodEnum<["none", "soft", "hard"]>>;
|
|
@@ -1410,6 +1411,7 @@ declare function defaultsRoot(): string;
|
|
|
1410
1411
|
declare function defaultWorkflowsDir(): string;
|
|
1411
1412
|
declare function defaultTemplatesDir(): string;
|
|
1412
1413
|
declare function defaultMemoryDir(): string;
|
|
1414
|
+
declare function defaultMcpYamlPath(): string;
|
|
1413
1415
|
|
|
1414
1416
|
declare function pathExists(path: string): Promise<boolean>;
|
|
1415
1417
|
declare function ensureDir(path: string): Promise<void>;
|
|
@@ -1762,4 +1764,399 @@ declare function updateFeatureStatus(backlogPath: string, featureId: string, sta
|
|
|
1762
1764
|
*/
|
|
1763
1765
|
declare function promoteGreenfieldToMemory(projectRoot: string, config: Config, changeId: string): Promise<string[]>;
|
|
1764
1766
|
|
|
1765
|
-
|
|
1767
|
+
/**
|
|
1768
|
+
* External MCP *sources* that sdd consumes (sdd = MCP client).
|
|
1769
|
+
* Distinct from `sdd mcp serve` (sdd as MCP server for agents).
|
|
1770
|
+
*/
|
|
1771
|
+
declare const McpWhenSchema: z.ZodObject<{
|
|
1772
|
+
/** Empty = all stages */
|
|
1773
|
+
stages: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1774
|
+
/** Empty = all workflows */
|
|
1775
|
+
workflows: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1776
|
+
/** Match title/query (case-insensitive substring) */
|
|
1777
|
+
keywords: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1778
|
+
/**
|
|
1779
|
+
* High-level intent tags the operator or tool may pass:
|
|
1780
|
+
* code | ui | design | api | docs | data
|
|
1781
|
+
*/
|
|
1782
|
+
intents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1783
|
+
}, "strip", z.ZodTypeAny, {
|
|
1784
|
+
stages: string[];
|
|
1785
|
+
keywords: string[];
|
|
1786
|
+
workflows: string[];
|
|
1787
|
+
intents: string[];
|
|
1788
|
+
}, {
|
|
1789
|
+
stages?: string[] | undefined;
|
|
1790
|
+
keywords?: string[] | undefined;
|
|
1791
|
+
workflows?: string[] | undefined;
|
|
1792
|
+
intents?: string[] | undefined;
|
|
1793
|
+
}>;
|
|
1794
|
+
declare const McpInvokeSchema: z.ZodObject<{
|
|
1795
|
+
/** Tool name on the remote MCP server */
|
|
1796
|
+
tool: z.ZodString;
|
|
1797
|
+
/**
|
|
1798
|
+
* Static args + templates:
|
|
1799
|
+
* {{query}} {{title}} {{stage}} {{workflow}} {{projectRoot}}
|
|
1800
|
+
*/
|
|
1801
|
+
args: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1802
|
+
}, "strip", z.ZodTypeAny, {
|
|
1803
|
+
tool: string;
|
|
1804
|
+
args: Record<string, unknown>;
|
|
1805
|
+
}, {
|
|
1806
|
+
tool: string;
|
|
1807
|
+
args?: Record<string, unknown> | undefined;
|
|
1808
|
+
}>;
|
|
1809
|
+
declare const McpSourceSchema: z.ZodObject<{
|
|
1810
|
+
id: z.ZodString;
|
|
1811
|
+
description: z.ZodDefault<z.ZodString>;
|
|
1812
|
+
/** stdio only in v1 */
|
|
1813
|
+
transport: z.ZodDefault<z.ZodEnum<["stdio"]>>;
|
|
1814
|
+
command: z.ZodString;
|
|
1815
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1816
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1817
|
+
/** Working directory (default: project root). Supports {{projectRoot}} */
|
|
1818
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
1819
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1820
|
+
/** Higher runs first when gathering */
|
|
1821
|
+
priority: z.ZodDefault<z.ZodNumber>;
|
|
1822
|
+
when: z.ZodDefault<z.ZodObject<{
|
|
1823
|
+
/** Empty = all stages */
|
|
1824
|
+
stages: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1825
|
+
/** Empty = all workflows */
|
|
1826
|
+
workflows: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1827
|
+
/** Match title/query (case-insensitive substring) */
|
|
1828
|
+
keywords: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1829
|
+
/**
|
|
1830
|
+
* High-level intent tags the operator or tool may pass:
|
|
1831
|
+
* code | ui | design | api | docs | data
|
|
1832
|
+
*/
|
|
1833
|
+
intents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1834
|
+
}, "strip", z.ZodTypeAny, {
|
|
1835
|
+
stages: string[];
|
|
1836
|
+
keywords: string[];
|
|
1837
|
+
workflows: string[];
|
|
1838
|
+
intents: string[];
|
|
1839
|
+
}, {
|
|
1840
|
+
stages?: string[] | undefined;
|
|
1841
|
+
keywords?: string[] | undefined;
|
|
1842
|
+
workflows?: string[] | undefined;
|
|
1843
|
+
intents?: string[] | undefined;
|
|
1844
|
+
}>>;
|
|
1845
|
+
/**
|
|
1846
|
+
* How sdd calls this source when auto-gathering for a stage.
|
|
1847
|
+
* If omitted, `sdd mcp fetch` still works with an explicit --tool.
|
|
1848
|
+
*/
|
|
1849
|
+
invoke: z.ZodOptional<z.ZodObject<{
|
|
1850
|
+
/** Tool name on the remote MCP server */
|
|
1851
|
+
tool: z.ZodString;
|
|
1852
|
+
/**
|
|
1853
|
+
* Static args + templates:
|
|
1854
|
+
* {{query}} {{title}} {{stage}} {{workflow}} {{projectRoot}}
|
|
1855
|
+
*/
|
|
1856
|
+
args: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1857
|
+
}, "strip", z.ZodTypeAny, {
|
|
1858
|
+
tool: string;
|
|
1859
|
+
args: Record<string, unknown>;
|
|
1860
|
+
}, {
|
|
1861
|
+
tool: string;
|
|
1862
|
+
args?: Record<string, unknown> | undefined;
|
|
1863
|
+
}>>;
|
|
1864
|
+
/** Optional allowlist of tool names (documentation / validation) */
|
|
1865
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1866
|
+
}, "strip", z.ZodTypeAny, {
|
|
1867
|
+
id: string;
|
|
1868
|
+
description: string;
|
|
1869
|
+
when: {
|
|
1870
|
+
stages: string[];
|
|
1871
|
+
keywords: string[];
|
|
1872
|
+
workflows: string[];
|
|
1873
|
+
intents: string[];
|
|
1874
|
+
};
|
|
1875
|
+
priority: number;
|
|
1876
|
+
args: string[];
|
|
1877
|
+
transport: "stdio";
|
|
1878
|
+
command: string;
|
|
1879
|
+
env: Record<string, string>;
|
|
1880
|
+
enabled: boolean;
|
|
1881
|
+
cwd?: string | undefined;
|
|
1882
|
+
invoke?: {
|
|
1883
|
+
tool: string;
|
|
1884
|
+
args: Record<string, unknown>;
|
|
1885
|
+
} | undefined;
|
|
1886
|
+
tools?: string[] | undefined;
|
|
1887
|
+
}, {
|
|
1888
|
+
id: string;
|
|
1889
|
+
command: string;
|
|
1890
|
+
description?: string | undefined;
|
|
1891
|
+
when?: {
|
|
1892
|
+
stages?: string[] | undefined;
|
|
1893
|
+
keywords?: string[] | undefined;
|
|
1894
|
+
workflows?: string[] | undefined;
|
|
1895
|
+
intents?: string[] | undefined;
|
|
1896
|
+
} | undefined;
|
|
1897
|
+
priority?: number | undefined;
|
|
1898
|
+
args?: string[] | undefined;
|
|
1899
|
+
transport?: "stdio" | undefined;
|
|
1900
|
+
env?: Record<string, string> | undefined;
|
|
1901
|
+
cwd?: string | undefined;
|
|
1902
|
+
enabled?: boolean | undefined;
|
|
1903
|
+
invoke?: {
|
|
1904
|
+
tool: string;
|
|
1905
|
+
args?: Record<string, unknown> | undefined;
|
|
1906
|
+
} | undefined;
|
|
1907
|
+
tools?: string[] | undefined;
|
|
1908
|
+
}>;
|
|
1909
|
+
declare const McpConfigSchema: z.ZodObject<{
|
|
1910
|
+
version: z.ZodDefault<z.ZodNumber>;
|
|
1911
|
+
/**
|
|
1912
|
+
* When true, handoff generation calls matching sources with `invoke` and
|
|
1913
|
+
* embeds results under "External MCP context".
|
|
1914
|
+
*/
|
|
1915
|
+
auto_fetch_on_handoff: z.ZodDefault<z.ZodBoolean>;
|
|
1916
|
+
/** Max chars of MCP output embedded into handoff per source */
|
|
1917
|
+
max_chars_per_source: z.ZodDefault<z.ZodNumber>;
|
|
1918
|
+
sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
1919
|
+
id: z.ZodString;
|
|
1920
|
+
description: z.ZodDefault<z.ZodString>;
|
|
1921
|
+
/** stdio only in v1 */
|
|
1922
|
+
transport: z.ZodDefault<z.ZodEnum<["stdio"]>>;
|
|
1923
|
+
command: z.ZodString;
|
|
1924
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1925
|
+
env: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
1926
|
+
/** Working directory (default: project root). Supports {{projectRoot}} */
|
|
1927
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
1928
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1929
|
+
/** Higher runs first when gathering */
|
|
1930
|
+
priority: z.ZodDefault<z.ZodNumber>;
|
|
1931
|
+
when: z.ZodDefault<z.ZodObject<{
|
|
1932
|
+
/** Empty = all stages */
|
|
1933
|
+
stages: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1934
|
+
/** Empty = all workflows */
|
|
1935
|
+
workflows: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1936
|
+
/** Match title/query (case-insensitive substring) */
|
|
1937
|
+
keywords: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1938
|
+
/**
|
|
1939
|
+
* High-level intent tags the operator or tool may pass:
|
|
1940
|
+
* code | ui | design | api | docs | data
|
|
1941
|
+
*/
|
|
1942
|
+
intents: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1943
|
+
}, "strip", z.ZodTypeAny, {
|
|
1944
|
+
stages: string[];
|
|
1945
|
+
keywords: string[];
|
|
1946
|
+
workflows: string[];
|
|
1947
|
+
intents: string[];
|
|
1948
|
+
}, {
|
|
1949
|
+
stages?: string[] | undefined;
|
|
1950
|
+
keywords?: string[] | undefined;
|
|
1951
|
+
workflows?: string[] | undefined;
|
|
1952
|
+
intents?: string[] | undefined;
|
|
1953
|
+
}>>;
|
|
1954
|
+
/**
|
|
1955
|
+
* How sdd calls this source when auto-gathering for a stage.
|
|
1956
|
+
* If omitted, `sdd mcp fetch` still works with an explicit --tool.
|
|
1957
|
+
*/
|
|
1958
|
+
invoke: z.ZodOptional<z.ZodObject<{
|
|
1959
|
+
/** Tool name on the remote MCP server */
|
|
1960
|
+
tool: z.ZodString;
|
|
1961
|
+
/**
|
|
1962
|
+
* Static args + templates:
|
|
1963
|
+
* {{query}} {{title}} {{stage}} {{workflow}} {{projectRoot}}
|
|
1964
|
+
*/
|
|
1965
|
+
args: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1966
|
+
}, "strip", z.ZodTypeAny, {
|
|
1967
|
+
tool: string;
|
|
1968
|
+
args: Record<string, unknown>;
|
|
1969
|
+
}, {
|
|
1970
|
+
tool: string;
|
|
1971
|
+
args?: Record<string, unknown> | undefined;
|
|
1972
|
+
}>>;
|
|
1973
|
+
/** Optional allowlist of tool names (documentation / validation) */
|
|
1974
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1975
|
+
}, "strip", z.ZodTypeAny, {
|
|
1976
|
+
id: string;
|
|
1977
|
+
description: string;
|
|
1978
|
+
when: {
|
|
1979
|
+
stages: string[];
|
|
1980
|
+
keywords: string[];
|
|
1981
|
+
workflows: string[];
|
|
1982
|
+
intents: string[];
|
|
1983
|
+
};
|
|
1984
|
+
priority: number;
|
|
1985
|
+
args: string[];
|
|
1986
|
+
transport: "stdio";
|
|
1987
|
+
command: string;
|
|
1988
|
+
env: Record<string, string>;
|
|
1989
|
+
enabled: boolean;
|
|
1990
|
+
cwd?: string | undefined;
|
|
1991
|
+
invoke?: {
|
|
1992
|
+
tool: string;
|
|
1993
|
+
args: Record<string, unknown>;
|
|
1994
|
+
} | undefined;
|
|
1995
|
+
tools?: string[] | undefined;
|
|
1996
|
+
}, {
|
|
1997
|
+
id: string;
|
|
1998
|
+
command: string;
|
|
1999
|
+
description?: string | undefined;
|
|
2000
|
+
when?: {
|
|
2001
|
+
stages?: string[] | undefined;
|
|
2002
|
+
keywords?: string[] | undefined;
|
|
2003
|
+
workflows?: string[] | undefined;
|
|
2004
|
+
intents?: string[] | undefined;
|
|
2005
|
+
} | undefined;
|
|
2006
|
+
priority?: number | undefined;
|
|
2007
|
+
args?: string[] | undefined;
|
|
2008
|
+
transport?: "stdio" | undefined;
|
|
2009
|
+
env?: Record<string, string> | undefined;
|
|
2010
|
+
cwd?: string | undefined;
|
|
2011
|
+
enabled?: boolean | undefined;
|
|
2012
|
+
invoke?: {
|
|
2013
|
+
tool: string;
|
|
2014
|
+
args?: Record<string, unknown> | undefined;
|
|
2015
|
+
} | undefined;
|
|
2016
|
+
tools?: string[] | undefined;
|
|
2017
|
+
}>, "many">>;
|
|
2018
|
+
}, "strip", z.ZodTypeAny, {
|
|
2019
|
+
version: number;
|
|
2020
|
+
auto_fetch_on_handoff: boolean;
|
|
2021
|
+
max_chars_per_source: number;
|
|
2022
|
+
sources: {
|
|
2023
|
+
id: string;
|
|
2024
|
+
description: string;
|
|
2025
|
+
when: {
|
|
2026
|
+
stages: string[];
|
|
2027
|
+
keywords: string[];
|
|
2028
|
+
workflows: string[];
|
|
2029
|
+
intents: string[];
|
|
2030
|
+
};
|
|
2031
|
+
priority: number;
|
|
2032
|
+
args: string[];
|
|
2033
|
+
transport: "stdio";
|
|
2034
|
+
command: string;
|
|
2035
|
+
env: Record<string, string>;
|
|
2036
|
+
enabled: boolean;
|
|
2037
|
+
cwd?: string | undefined;
|
|
2038
|
+
invoke?: {
|
|
2039
|
+
tool: string;
|
|
2040
|
+
args: Record<string, unknown>;
|
|
2041
|
+
} | undefined;
|
|
2042
|
+
tools?: string[] | undefined;
|
|
2043
|
+
}[];
|
|
2044
|
+
}, {
|
|
2045
|
+
version?: number | undefined;
|
|
2046
|
+
auto_fetch_on_handoff?: boolean | undefined;
|
|
2047
|
+
max_chars_per_source?: number | undefined;
|
|
2048
|
+
sources?: {
|
|
2049
|
+
id: string;
|
|
2050
|
+
command: string;
|
|
2051
|
+
description?: string | undefined;
|
|
2052
|
+
when?: {
|
|
2053
|
+
stages?: string[] | undefined;
|
|
2054
|
+
keywords?: string[] | undefined;
|
|
2055
|
+
workflows?: string[] | undefined;
|
|
2056
|
+
intents?: string[] | undefined;
|
|
2057
|
+
} | undefined;
|
|
2058
|
+
priority?: number | undefined;
|
|
2059
|
+
args?: string[] | undefined;
|
|
2060
|
+
transport?: "stdio" | undefined;
|
|
2061
|
+
env?: Record<string, string> | undefined;
|
|
2062
|
+
cwd?: string | undefined;
|
|
2063
|
+
enabled?: boolean | undefined;
|
|
2064
|
+
invoke?: {
|
|
2065
|
+
tool: string;
|
|
2066
|
+
args?: Record<string, unknown> | undefined;
|
|
2067
|
+
} | undefined;
|
|
2068
|
+
tools?: string[] | undefined;
|
|
2069
|
+
}[] | undefined;
|
|
2070
|
+
}>;
|
|
2071
|
+
type McpWhen = z.infer<typeof McpWhenSchema>;
|
|
2072
|
+
type McpInvoke = z.infer<typeof McpInvokeSchema>;
|
|
2073
|
+
type McpSource = z.infer<typeof McpSourceSchema>;
|
|
2074
|
+
type McpConfig = z.infer<typeof McpConfigSchema>;
|
|
2075
|
+
interface McpMatchContext {
|
|
2076
|
+
stage?: string;
|
|
2077
|
+
workflow?: string;
|
|
2078
|
+
/** Free text: change title, user query, task line */
|
|
2079
|
+
query?: string;
|
|
2080
|
+
/** Explicit intent tags from CLI/agent */
|
|
2081
|
+
intents?: string[];
|
|
2082
|
+
}
|
|
2083
|
+
interface McpFetchResult {
|
|
2084
|
+
sourceId: string;
|
|
2085
|
+
tool: string;
|
|
2086
|
+
ok: boolean;
|
|
2087
|
+
text: string;
|
|
2088
|
+
error?: string;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
declare function mcpConfigPath(projectRoot: string): string;
|
|
2092
|
+
declare function defaultMcpConfig(): McpConfig;
|
|
2093
|
+
/**
|
|
2094
|
+
* Example sources (commented in written file via description only —
|
|
2095
|
+
* we write a real empty config + README-style top comment is hard in YAML;
|
|
2096
|
+
* document examples in docs).
|
|
2097
|
+
*/
|
|
2098
|
+
declare function loadMcpConfig(projectRoot: string): Promise<McpConfig>;
|
|
2099
|
+
declare function saveMcpConfig(projectRoot: string, config: McpConfig): Promise<string>;
|
|
2100
|
+
declare function ensureMcpConfig(projectRoot: string): Promise<McpConfig>;
|
|
2101
|
+
declare function addMcpSource(projectRoot: string, source: McpSource): Promise<McpConfig>;
|
|
2102
|
+
declare function removeMcpSource(projectRoot: string, id: string): Promise<McpConfig>;
|
|
2103
|
+
declare function interpolate(value: string, vars: Record<string, string>): string;
|
|
2104
|
+
declare function interpolateArgs(args: Record<string, unknown>, vars: Record<string, string>): Record<string, unknown>;
|
|
2105
|
+
|
|
2106
|
+
/**
|
|
2107
|
+
* Decide which configured MCP sources apply for this stage / workflow / query.
|
|
2108
|
+
*
|
|
2109
|
+
* 1. enabled
|
|
2110
|
+
* 2. when.stages → stage must match (if stage known)
|
|
2111
|
+
* 3. when.workflows → workflow must match (if workflow known)
|
|
2112
|
+
* 4. when.intents + caller passed intents → require intersection
|
|
2113
|
+
* 5. when.keywords + query present → require a keyword substring hit
|
|
2114
|
+
*
|
|
2115
|
+
* So: stage routing always; intents/keywords refine when the caller provides signals.
|
|
2116
|
+
*/
|
|
2117
|
+
declare function matchMcpSources(sources: McpSource[], ctx: McpMatchContext): McpSource[];
|
|
2118
|
+
/** Human explanation of match for CLI */
|
|
2119
|
+
declare function explainMatch(source: McpSource, ctx: McpMatchContext): string;
|
|
2120
|
+
|
|
2121
|
+
/**
|
|
2122
|
+
* sdd as MCP *client* — connect to external stdio MCP servers and call tools.
|
|
2123
|
+
*/
|
|
2124
|
+
|
|
2125
|
+
interface CallMcpToolResult {
|
|
2126
|
+
ok: boolean;
|
|
2127
|
+
text: string;
|
|
2128
|
+
error?: string;
|
|
2129
|
+
}
|
|
2130
|
+
/**
|
|
2131
|
+
* One-shot: spawn source, list tools or call tool, then close.
|
|
2132
|
+
*/
|
|
2133
|
+
declare function withMcpSource<T>(source: McpSource, projectRoot: string, fn: (client: Client) => Promise<T>): Promise<T>;
|
|
2134
|
+
declare function listMcpSourceTools(source: McpSource, projectRoot: string): Promise<{
|
|
2135
|
+
name: string;
|
|
2136
|
+
description?: string;
|
|
2137
|
+
}[]>;
|
|
2138
|
+
declare function callMcpSourceTool(source: McpSource, projectRoot: string, tool: string, args: Record<string, unknown>): Promise<CallMcpToolResult>;
|
|
2139
|
+
|
|
2140
|
+
interface GatherMcpOptions {
|
|
2141
|
+
projectRoot: string;
|
|
2142
|
+
match: McpMatchContext;
|
|
2143
|
+
/** Only these source ids (default: all matching) */
|
|
2144
|
+
sourceIds?: string[];
|
|
2145
|
+
/** Force tool/args instead of source.invoke */
|
|
2146
|
+
tool?: string;
|
|
2147
|
+
args?: Record<string, unknown>;
|
|
2148
|
+
/** Skip sources without invoke unless tool override */
|
|
2149
|
+
requireInvoke?: boolean;
|
|
2150
|
+
}
|
|
2151
|
+
/**
|
|
2152
|
+
* Call matching external MCP sources and collect text for agents / handoff.
|
|
2153
|
+
*/
|
|
2154
|
+
declare function gatherMcpContext(opts: GatherMcpOptions): Promise<McpFetchResult[]>;
|
|
2155
|
+
declare function gatherMcpContextForChange(projectRoot: string, ctx: ChangeContext, extra?: {
|
|
2156
|
+
query?: string;
|
|
2157
|
+
intents?: string[];
|
|
2158
|
+
}): Promise<McpFetchResult[]>;
|
|
2159
|
+
declare function formatMcpContextForHandoff(results: McpFetchResult[]): string;
|
|
2160
|
+
declare function listMatchingSourceIds(sources: McpSource[], match: McpMatchContext): string[];
|
|
2161
|
+
|
|
2162
|
+
export { AGENT_INTEGRATIONS, AGENT_TARGET_OPTIONS, ALL_AGENT_TARGETS, type AdapterExtractResult, AdapterRegistry, type AdvanceResult, type AgentIntegration, type AgentTarget, type AgentTargetOption, type ArtifactDef, ArtifactDefSchema, type BuildRefinePlanOptions, type CallMcpToolResult, type ChangeContext, type ChangeMeta, ChangeMetaSchema, type CodeContextCaps, type CodeContextGap, type CodeContextGapCode, type CodeContextRequest, type CodeContextResult, type CodeContextSummary, type CodeSlice, type Complexity, type Config, ConfigSchema, type CreateChangeInput, DEFAULT_CODE_CONTEXT_CAPS, DEFAULT_INIT_INTEGRATION, type FocusPlan, type Gate, GateSchema, type GatherMcpOptions, type GenerateCodeContextDeps, type GreenfieldFeature, type InitOptions, type InitResult, type InstallAgentOptions, type InstallAgentResult, type InstallAgentsOptions, type InstallAgentsResult, type InstalledAgentSnapshot, type LanguageAdapter, type McpConfig, McpConfigSchema, type McpFetchResult, type McpInvoke, McpInvokeSchema, type McpMatchContext, type McpSource, McpSourceSchema, type McpWhen, McpWhenSchema, PROTOCOL_MD, type RefineArtifactRef, type RefineMode, type RefinePlan, SDD_AGENT_ROLES, SDD_DIR, type SddAgentRole, type SddAgentRoleId, type Stage, StageSchema, type StartFeatureInput, type StartGreenfieldInput, type StartGreenfieldResult, type SymbolInfo, type SymbolKind, VerifyCommandSchema, type VerifyResult, type Workflow, WorkflowSchema, activePointerPath, activeStages, addMcpSource, advanceStage, agentHostPaths, agentKickoffMessage, approveGate, archiveDir, buildAgentPrompt, buildContext, buildRefinePlan, callMcpSourceTool, canLeaveStage, changeDirName, changeMetaPath, changePath, changesDir, classifyPath, clearActiveIf, completeChange, configPath, copyDir, copyDirSkipExisting, createChange, defaultConfig, defaultMcpConfig, defaultMcpYamlPath, defaultMemoryDir, defaultTemplatesDir, defaultWorkflowsDir, defaultsRoot, domainsDir, ensureDir, ensureMcpConfig, explainMatch, fallbackAdapter, fallbackIncompleteStageId, findFeaturesBacklogPath, firstActiveStageId, formatJsonSummary, formatMcpContextForHandoff, formatStatus, gatherMcpContext, gatherMcpContextForChange, generateCodeContext, getActiveChangeId, getIntegration, getStage, incompletePriorStageErrors, inferComplexity, initProject, installAgentIntegration, installAgentIntegrations, integrationKeyFor, interpolate, interpolateArgs, isIgnoredPath, isInitialized, isSecretPath, isStageSkipped, isSubstantiveArtifactContent, listBacklogFeatures, listChanges, listDirs, listFiles, listMatchingSourceIds, listMcpSourceTools, listWorkflowNames, loadChangeMeta, loadConfig, loadInstalledAgent, loadMcpConfig, loadWorkflow, matchMcpSources, mcpConfigPath, memoryDir, mergeCaps, nextStageId, nowIso, optionForTarget, parseAgentTargets, parseFeaturesBacklog, parseIntegration, pathExists, promoteGreenfieldToMemory, readText, readYaml, recommendWorkflow, refreshActiveAgentContext, removeMcpSource, removeOtherAgentHosts, removePath, renderThinAgent, resolveChangeId, resolveFocus, resolveStages, runLocalVerify, saveChangeMeta, saveConfig, saveMcpConfig, sddRoot, setActiveChange, shouldAutoSkip, skipStage, slugify, startFeatureFromBacklog, startGreenfield, switchWorkflow, templatesDir, todayIsoDate, tokenizeKeywords, typescriptAdapter, uniqueChangeDirName, updateFeatureStatus, withMcpSource, workflowsDir, writeAgentHandoff, writeRefineBrief, writeText, writeTextIfMissing, writeYaml };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
advanceStage,
|
|
3
|
+
approveGate,
|
|
4
|
+
canLeaveStage,
|
|
5
|
+
completeChange,
|
|
6
|
+
createChange,
|
|
7
|
+
fallbackIncompleteStageId,
|
|
8
|
+
findFeaturesBacklogPath,
|
|
9
|
+
incompletePriorStageErrors,
|
|
10
|
+
isSubstantiveArtifactContent,
|
|
11
|
+
listBacklogFeatures,
|
|
12
|
+
parseFeaturesBacklog,
|
|
13
|
+
promoteGreenfieldToMemory,
|
|
14
|
+
skipStage,
|
|
15
|
+
startFeatureFromBacklog,
|
|
16
|
+
startGreenfield,
|
|
17
|
+
switchWorkflow,
|
|
18
|
+
updateFeatureStatus
|
|
19
|
+
} from "./chunk-24EXBX7P.js";
|
|
20
|
+
import {
|
|
21
|
+
callMcpSourceTool,
|
|
22
|
+
explainMatch,
|
|
23
|
+
formatMcpContextForHandoff,
|
|
24
|
+
gatherMcpContext,
|
|
25
|
+
gatherMcpContextForChange,
|
|
26
|
+
listMatchingSourceIds,
|
|
27
|
+
listMcpSourceTools,
|
|
28
|
+
matchMcpSources,
|
|
29
|
+
withMcpSource
|
|
30
|
+
} from "./chunk-VD3CPFAI.js";
|
|
31
|
+
import {
|
|
32
|
+
McpConfigSchema,
|
|
33
|
+
McpInvokeSchema,
|
|
34
|
+
McpSourceSchema,
|
|
35
|
+
McpWhenSchema,
|
|
36
|
+
addMcpSource,
|
|
37
|
+
defaultMcpConfig,
|
|
38
|
+
ensureMcpConfig,
|
|
39
|
+
interpolate,
|
|
40
|
+
interpolateArgs,
|
|
41
|
+
loadMcpConfig,
|
|
42
|
+
mcpConfigPath,
|
|
43
|
+
removeMcpSource,
|
|
44
|
+
saveMcpConfig
|
|
45
|
+
} from "./chunk-KYWETNFU.js";
|
|
1
46
|
import {
|
|
2
47
|
AGENT_INTEGRATIONS,
|
|
3
48
|
AGENT_TARGET_OPTIONS,
|
|
@@ -19,36 +64,17 @@ import {
|
|
|
19
64
|
removeOtherAgentHosts,
|
|
20
65
|
renderThinAgent,
|
|
21
66
|
writeAgentHandoff
|
|
22
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-GR7KIAR2.js";
|
|
68
|
+
import {
|
|
69
|
+
buildAgentPrompt,
|
|
70
|
+
formatStatus
|
|
71
|
+
} from "./chunk-RRBKQ76B.js";
|
|
23
72
|
import {
|
|
24
73
|
defaultConfig,
|
|
25
74
|
isInitialized,
|
|
26
75
|
loadConfig,
|
|
27
76
|
saveConfig
|
|
28
77
|
} from "./chunk-OJFMJHNL.js";
|
|
29
|
-
import {
|
|
30
|
-
advanceStage,
|
|
31
|
-
approveGate,
|
|
32
|
-
canLeaveStage,
|
|
33
|
-
completeChange,
|
|
34
|
-
createChange,
|
|
35
|
-
fallbackIncompleteStageId,
|
|
36
|
-
findFeaturesBacklogPath,
|
|
37
|
-
incompletePriorStageErrors,
|
|
38
|
-
isSubstantiveArtifactContent,
|
|
39
|
-
listBacklogFeatures,
|
|
40
|
-
parseFeaturesBacklog,
|
|
41
|
-
promoteGreenfieldToMemory,
|
|
42
|
-
skipStage,
|
|
43
|
-
startFeatureFromBacklog,
|
|
44
|
-
startGreenfield,
|
|
45
|
-
switchWorkflow,
|
|
46
|
-
updateFeatureStatus
|
|
47
|
-
} from "./chunk-HOH43IQ2.js";
|
|
48
|
-
import {
|
|
49
|
-
buildAgentPrompt,
|
|
50
|
-
formatStatus
|
|
51
|
-
} from "./chunk-C725DWSB.js";
|
|
52
78
|
import {
|
|
53
79
|
activeStages,
|
|
54
80
|
buildContext,
|
|
@@ -144,6 +170,9 @@ function defaultTemplatesDir() {
|
|
|
144
170
|
function defaultMemoryDir() {
|
|
145
171
|
return join(defaultsRoot(), "memory");
|
|
146
172
|
}
|
|
173
|
+
function defaultMcpYamlPath() {
|
|
174
|
+
return join(defaultsRoot(), "mcp.yaml");
|
|
175
|
+
}
|
|
147
176
|
|
|
148
177
|
// src/init.ts
|
|
149
178
|
async function initProject(opts) {
|
|
@@ -173,6 +202,12 @@ async function initProject(opts) {
|
|
|
173
202
|
await copyDir(tSrc, tDest);
|
|
174
203
|
created.push(tDest);
|
|
175
204
|
}
|
|
205
|
+
const mcpSrc = defaultMcpYamlPath();
|
|
206
|
+
const mcpDest = mcpConfigPath(projectRoot);
|
|
207
|
+
if (await pathExists(mcpSrc)) {
|
|
208
|
+
const wrote = await writeTextIfMissing(mcpDest, await readText(mcpSrc));
|
|
209
|
+
if (wrote) created.push(mcpDest);
|
|
210
|
+
}
|
|
176
211
|
const mDest = memoryDir(projectRoot, config);
|
|
177
212
|
await ensureDir(mDest);
|
|
178
213
|
const mSrc = defaultMemoryDir();
|
|
@@ -2098,6 +2133,10 @@ export {
|
|
|
2098
2133
|
DEFAULT_CODE_CONTEXT_CAPS,
|
|
2099
2134
|
DEFAULT_INIT_INTEGRATION,
|
|
2100
2135
|
GateSchema,
|
|
2136
|
+
McpConfigSchema,
|
|
2137
|
+
McpInvokeSchema,
|
|
2138
|
+
McpSourceSchema,
|
|
2139
|
+
McpWhenSchema,
|
|
2101
2140
|
PROTOCOL_MD,
|
|
2102
2141
|
SDD_AGENT_ROLES,
|
|
2103
2142
|
SDD_DIR,
|
|
@@ -2106,6 +2145,7 @@ export {
|
|
|
2106
2145
|
WorkflowSchema,
|
|
2107
2146
|
activePointerPath,
|
|
2108
2147
|
activeStages,
|
|
2148
|
+
addMcpSource,
|
|
2109
2149
|
advanceStage,
|
|
2110
2150
|
agentHostPaths,
|
|
2111
2151
|
agentKickoffMessage,
|
|
@@ -2114,6 +2154,7 @@ export {
|
|
|
2114
2154
|
buildAgentPrompt,
|
|
2115
2155
|
buildContext,
|
|
2116
2156
|
buildRefinePlan,
|
|
2157
|
+
callMcpSourceTool,
|
|
2117
2158
|
canLeaveStage,
|
|
2118
2159
|
changeDirName,
|
|
2119
2160
|
changeMetaPath,
|
|
@@ -2127,18 +2168,25 @@ export {
|
|
|
2127
2168
|
copyDirSkipExisting,
|
|
2128
2169
|
createChange,
|
|
2129
2170
|
defaultConfig,
|
|
2171
|
+
defaultMcpConfig,
|
|
2172
|
+
defaultMcpYamlPath,
|
|
2130
2173
|
defaultMemoryDir,
|
|
2131
2174
|
defaultTemplatesDir,
|
|
2132
2175
|
defaultWorkflowsDir,
|
|
2133
2176
|
defaultsRoot,
|
|
2134
2177
|
domainsDir,
|
|
2135
2178
|
ensureDir,
|
|
2179
|
+
ensureMcpConfig,
|
|
2180
|
+
explainMatch,
|
|
2136
2181
|
fallbackAdapter,
|
|
2137
2182
|
fallbackIncompleteStageId,
|
|
2138
2183
|
findFeaturesBacklogPath,
|
|
2139
2184
|
firstActiveStageId,
|
|
2140
2185
|
formatJsonSummary,
|
|
2186
|
+
formatMcpContextForHandoff,
|
|
2141
2187
|
formatStatus,
|
|
2188
|
+
gatherMcpContext,
|
|
2189
|
+
gatherMcpContextForChange,
|
|
2142
2190
|
generateCodeContext,
|
|
2143
2191
|
getActiveChangeId,
|
|
2144
2192
|
getIntegration,
|
|
@@ -2149,6 +2197,8 @@ export {
|
|
|
2149
2197
|
installAgentIntegration,
|
|
2150
2198
|
installAgentIntegrations,
|
|
2151
2199
|
integrationKeyFor,
|
|
2200
|
+
interpolate,
|
|
2201
|
+
interpolateArgs,
|
|
2152
2202
|
isIgnoredPath,
|
|
2153
2203
|
isInitialized,
|
|
2154
2204
|
isSecretPath,
|
|
@@ -2158,11 +2208,16 @@ export {
|
|
|
2158
2208
|
listChanges,
|
|
2159
2209
|
listDirs,
|
|
2160
2210
|
listFiles,
|
|
2211
|
+
listMatchingSourceIds,
|
|
2212
|
+
listMcpSourceTools,
|
|
2161
2213
|
listWorkflowNames,
|
|
2162
2214
|
loadChangeMeta,
|
|
2163
2215
|
loadConfig,
|
|
2164
2216
|
loadInstalledAgent,
|
|
2217
|
+
loadMcpConfig,
|
|
2165
2218
|
loadWorkflow,
|
|
2219
|
+
matchMcpSources,
|
|
2220
|
+
mcpConfigPath,
|
|
2166
2221
|
memoryDir,
|
|
2167
2222
|
mergeCaps,
|
|
2168
2223
|
nextStageId,
|
|
@@ -2177,6 +2232,7 @@ export {
|
|
|
2177
2232
|
readYaml,
|
|
2178
2233
|
recommendWorkflow,
|
|
2179
2234
|
refreshActiveAgentContext,
|
|
2235
|
+
removeMcpSource,
|
|
2180
2236
|
removeOtherAgentHosts,
|
|
2181
2237
|
removePath,
|
|
2182
2238
|
renderThinAgent,
|
|
@@ -2186,6 +2242,7 @@ export {
|
|
|
2186
2242
|
runLocalVerify,
|
|
2187
2243
|
saveChangeMeta,
|
|
2188
2244
|
saveConfig,
|
|
2245
|
+
saveMcpConfig,
|
|
2189
2246
|
sddRoot,
|
|
2190
2247
|
setActiveChange,
|
|
2191
2248
|
shouldAutoSkip,
|
|
@@ -2200,6 +2257,7 @@ export {
|
|
|
2200
2257
|
typescriptAdapter,
|
|
2201
2258
|
uniqueChangeDirName,
|
|
2202
2259
|
updateFeatureStatus,
|
|
2260
|
+
withMcpSource,
|
|
2203
2261
|
workflowsDir,
|
|
2204
2262
|
writeAgentHandoff,
|
|
2205
2263
|
writeRefineBrief,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addMcpSource,
|
|
3
|
+
defaultMcpConfig,
|
|
4
|
+
ensureMcpConfig,
|
|
5
|
+
interpolate,
|
|
6
|
+
interpolateArgs,
|
|
7
|
+
loadMcpConfig,
|
|
8
|
+
mcpConfigPath,
|
|
9
|
+
removeMcpSource,
|
|
10
|
+
saveMcpConfig
|
|
11
|
+
} from "./chunk-KYWETNFU.js";
|
|
12
|
+
import "./chunk-7MJYPJMR.js";
|
|
13
|
+
import "./chunk-EPFURATC.js";
|
|
14
|
+
export {
|
|
15
|
+
addMcpSource,
|
|
16
|
+
defaultMcpConfig,
|
|
17
|
+
ensureMcpConfig,
|
|
18
|
+
interpolate,
|
|
19
|
+
interpolateArgs,
|
|
20
|
+
loadMcpConfig,
|
|
21
|
+
mcpConfigPath,
|
|
22
|
+
removeMcpSource,
|
|
23
|
+
saveMcpConfig
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@structured-vibe-coding/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Core engine for sdd — local Spec-Driven Development workflows, change packs, greenfield, and agent handoff",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
20
21
|
"pathe": "^2.0.3",
|
|
21
22
|
"typescript": "^5.8.2",
|
|
22
23
|
"yaml": "^2.7.0",
|