@structured-vibe-coding/core 0.21.0 → 0.22.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.
@@ -26,10 +26,11 @@ import {
26
26
  renderProtocolMd,
27
27
  renderThinAgent,
28
28
  writeAgentHandoff
29
- } from "./chunk-5GLH6ZWU.js";
30
- import "./chunk-AERAWOAK.js";
29
+ } from "./chunk-WCYVBZC4.js";
30
+ import "./chunk-QE6RMJUS.js";
31
31
  import "./chunk-TNWFMRIA.js";
32
- import "./chunk-MHODNFIL.js";
32
+ import "./chunk-47GWMUCR.js";
33
+ import "./chunk-4BRO7BOJ.js";
33
34
  import "./chunk-O5SP6X5R.js";
34
35
  export {
35
36
  AGENT_INTEGRATIONS,
@@ -0,0 +1,153 @@
1
+ import {
2
+ interpolate
3
+ } from "./chunk-4BRO7BOJ.js";
4
+
5
+ // src/errors.ts
6
+ var SddError = class extends Error {
7
+ code;
8
+ hint;
9
+ exitCode;
10
+ constructor(message, options) {
11
+ super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
12
+ this.name = "SddError";
13
+ this.code = options?.code ?? "SDD_ERROR";
14
+ this.hint = options?.hint;
15
+ this.exitCode = options?.exitCode ?? 1;
16
+ }
17
+ };
18
+ function isSddError(err) {
19
+ return err instanceof SddError;
20
+ }
21
+ function errorMessage(err) {
22
+ if (err instanceof Error) return err.message;
23
+ return String(err);
24
+ }
25
+
26
+ // src/env.ts
27
+ function toProcessEnv(base, extra) {
28
+ const out = {};
29
+ for (const [k, v] of Object.entries(base)) {
30
+ if (v !== void 0) out[k] = String(v);
31
+ }
32
+ if (extra) {
33
+ for (const [k, v] of Object.entries(extra)) {
34
+ if (v !== void 0) out[k] = String(v);
35
+ }
36
+ }
37
+ return out;
38
+ }
39
+
40
+ // src/version.ts
41
+ var SDD_CORE_VERSION = "0.22.0" ? "0.22.0" : "0.0.0-dev";
42
+
43
+ // src/mcp/client.ts
44
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
45
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
46
+ function mcpTimeoutMs() {
47
+ const raw = process.env.SDD_MCP_TIMEOUT_MS;
48
+ if (raw) {
49
+ const n = Number(raw);
50
+ if (Number.isFinite(n) && n > 0) return n;
51
+ }
52
+ return 3e4;
53
+ }
54
+ function contentToText(result) {
55
+ const parts = result.content ?? [];
56
+ return parts.map((p) => p.type === "text" ? p.text ?? "" : JSON.stringify(p)).join("\n").trim();
57
+ }
58
+ async function withTimeout(promise, ms, label) {
59
+ let timer;
60
+ try {
61
+ return await Promise.race([
62
+ promise,
63
+ new Promise((_, reject) => {
64
+ timer = setTimeout(() => {
65
+ reject(
66
+ new SddError(`MCP ${label} timed out after ${ms}ms`, {
67
+ code: "MCP_TIMEOUT",
68
+ hint: "Raise SDD_MCP_TIMEOUT_MS or fix the source server."
69
+ })
70
+ );
71
+ }, ms);
72
+ })
73
+ ]);
74
+ } finally {
75
+ if (timer) clearTimeout(timer);
76
+ }
77
+ }
78
+ async function withMcpSource(source, projectRoot, fn) {
79
+ const vars = { projectRoot };
80
+ const cwd = source.cwd ? interpolate(source.cwd, vars) : projectRoot;
81
+ const env = toProcessEnv(process.env, {
82
+ ...source.env,
83
+ SDD_PROJECT_ROOT: projectRoot
84
+ });
85
+ const transport = new StdioClientTransport({
86
+ command: source.command,
87
+ args: source.args,
88
+ cwd,
89
+ env
90
+ });
91
+ const client = new Client({
92
+ name: "sdd-mcp-client",
93
+ version: SDD_CORE_VERSION
94
+ });
95
+ const ms = mcpTimeoutMs();
96
+ await withTimeout(client.connect(transport), ms, `connect (${source.id})`);
97
+ try {
98
+ return await withTimeout(fn(client), ms, `call (${source.id})`);
99
+ } finally {
100
+ try {
101
+ await client.close();
102
+ } catch {
103
+ }
104
+ }
105
+ }
106
+ async function listMcpSourceTools(source, projectRoot) {
107
+ return withMcpSource(source, projectRoot, async (client) => {
108
+ const listed = await client.listTools();
109
+ return listed.tools.map((t) => ({
110
+ name: t.name,
111
+ description: t.description
112
+ }));
113
+ });
114
+ }
115
+ async function callMcpSourceTool(source, projectRoot, tool, args) {
116
+ try {
117
+ if (source.tools?.length && !source.tools.includes(tool)) {
118
+ return {
119
+ ok: false,
120
+ text: "",
121
+ error: `Tool "${tool}" not in allowlist for source ${source.id}: ${source.tools.join(", ")}`
122
+ };
123
+ }
124
+ return await withMcpSource(source, projectRoot, async (client) => {
125
+ const result = await client.callTool({ name: tool, arguments: args });
126
+ const text = contentToText(result);
127
+ const isError = Boolean(result.isError);
128
+ return {
129
+ ok: !isError,
130
+ text: text || (isError ? "(empty error result)" : "(empty)"),
131
+ error: isError ? text || "tool returned isError" : void 0
132
+ };
133
+ });
134
+ } catch (err) {
135
+ return {
136
+ ok: false,
137
+ text: "",
138
+ error: err instanceof Error ? err.message : String(err)
139
+ };
140
+ }
141
+ }
142
+
143
+ export {
144
+ SddError,
145
+ isSddError,
146
+ errorMessage,
147
+ toProcessEnv,
148
+ SDD_CORE_VERSION,
149
+ mcpTimeoutMs,
150
+ withMcpSource,
151
+ listMcpSourceTools,
152
+ callMcpSourceTool
153
+ };
@@ -6,8 +6,13 @@ import {
6
6
  shouldAutoSkip
7
7
  } from "./chunk-TNWFMRIA.js";
8
8
  import {
9
- SddError
10
- } from "./chunk-MHODNFIL.js";
9
+ SddError,
10
+ callMcpSourceTool,
11
+ mcpTimeoutMs
12
+ } from "./chunk-47GWMUCR.js";
13
+ import {
14
+ loadMcpConfig
15
+ } from "./chunk-4BRO7BOJ.js";
11
16
  import {
12
17
  activePointerPath,
13
18
  changesPathRel,
@@ -196,7 +201,9 @@ var SearchConfigSchema = z.object({
196
201
  k: z.number().int().min(1).max(100).default(20),
197
202
  embeddings: z.boolean().default(false),
198
203
  budgets: BudgetSchema.default({ default: 12e3 }),
199
- exclude: z.array(z.string().min(1)).default([])
204
+ exclude: z.array(z.string().min(1)).default([]),
205
+ mcp_source: z.string().min(1).optional(),
206
+ mcp_tool: z.string().min(1).optional()
200
207
  });
201
208
  function budgetForStage(config, stage) {
202
209
  if (!stage) return config.budgets.default;
@@ -221,22 +228,13 @@ async function loadSearchConfig(projectRoot) {
221
228
 
222
229
  // src/search/pack.ts
223
230
  var EN_DASH = "\u2013";
224
- function searchPreamble(query, scope, budget, hybrid = false) {
225
- if (hybrid) {
226
- return `# Search
227
- Query: ${query}
228
- Scope: ${scope}
229
- Provider: builtin
230
- Mode: hybrid
231
- Budget: ${budget}
232
-
233
- `;
234
- }
231
+ function searchPreamble(query, scope, budget, hybrid = false, provider = "builtin") {
232
+ const mode = hybrid ? "Mode: hybrid\n" : "";
235
233
  return `# Search
236
234
  Query: ${query}
237
235
  Scope: ${scope}
238
- Provider: builtin
239
- Budget: ${budget}
236
+ Provider: ${provider}
237
+ ${mode}Budget: ${budget}
240
238
 
241
239
  `;
242
240
  }
@@ -2331,6 +2329,173 @@ async function searchProject(projectRoot, query, options, runtime) {
2331
2329
  };
2332
2330
  }
2333
2331
 
2332
+ // src/search/mcp-provider.ts
2333
+ var McpSearchError = class extends Error {
2334
+ constructor() {
2335
+ super("Search provider is unavailable.");
2336
+ this.name = "McpSearchError";
2337
+ }
2338
+ };
2339
+ function emptyStats(considered = 0, reindexed = 0) {
2340
+ return {
2341
+ provider: "mcp",
2342
+ files: 0,
2343
+ chunks: 0,
2344
+ lastIndexFilesConsidered: considered,
2345
+ lastIndexFilesReindexed: reindexed,
2346
+ lastIndexChunksReindexed: 0,
2347
+ lastIndexChunksEmbedded: 0,
2348
+ indexedCommit: null
2349
+ };
2350
+ }
2351
+ function isSafeRelativePath(path) {
2352
+ if (!path || path.startsWith("/") || path.startsWith("\\")) return false;
2353
+ if (path.length >= 2 && path.charCodeAt(1) === 58) {
2354
+ const c = path.charCodeAt(0);
2355
+ if (c >= 65 && c <= 90 || c >= 97 && c <= 122) return false;
2356
+ }
2357
+ const parts = path.replaceAll("\\", "/").split("/");
2358
+ for (const part of parts) {
2359
+ if (part.length === 0 || part === "." || part === "..") return false;
2360
+ }
2361
+ return true;
2362
+ }
2363
+ function withTimeout(promise, ms) {
2364
+ return new Promise((resolve, reject) => {
2365
+ const timer = setTimeout(() => reject(new McpSearchError()), ms);
2366
+ promise.then(
2367
+ (value) => {
2368
+ clearTimeout(timer);
2369
+ resolve(value);
2370
+ },
2371
+ () => {
2372
+ clearTimeout(timer);
2373
+ reject(new McpSearchError());
2374
+ }
2375
+ );
2376
+ });
2377
+ }
2378
+ function allowedPaths(paths, exclude) {
2379
+ const kept = [];
2380
+ for (const raw of paths) {
2381
+ const path = raw.replaceAll("\\", "/");
2382
+ if (!isSafeRelativePath(path) || exclude(path)) continue;
2383
+ kept.push(path);
2384
+ }
2385
+ return kept;
2386
+ }
2387
+ function positive(value) {
2388
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) return void 0;
2389
+ return value;
2390
+ }
2391
+ function firstLine(body) {
2392
+ const nl = body.indexOf("\n");
2393
+ return nl === -1 ? body : body.slice(0, nl);
2394
+ }
2395
+ function asHit(value, scope, exclude) {
2396
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
2397
+ const rec = value;
2398
+ if (typeof rec.path !== "string") return void 0;
2399
+ const path = rec.path.replaceAll("\\", "/");
2400
+ if (!isSafeRelativePath(path) || exclude(path)) return void 0;
2401
+ const startLine2 = positive(rec.startLine);
2402
+ const endLine2 = positive(rec.endLine);
2403
+ if (startLine2 === void 0 || endLine2 === void 0 || endLine2 < startLine2) return void 0;
2404
+ if (typeof rec.symbol !== "string") return void 0;
2405
+ const symbol = rec.symbol.trim();
2406
+ if (!symbol || typeof rec.body !== "string") return void 0;
2407
+ const signature = typeof rec.signature === "string" ? rec.signature : firstLine(rec.body);
2408
+ const language = typeof rec.language === "string" ? rec.language : "";
2409
+ const score = typeof rec.score === "number" && Number.isFinite(rec.score) ? rec.score : 0;
2410
+ return { scope, path, startLine: startLine2, endLine: endLine2, symbol, score, signature, body: rec.body, language };
2411
+ }
2412
+ function parseHits(text, scope, exclude) {
2413
+ let parsed;
2414
+ try {
2415
+ parsed = JSON.parse(text);
2416
+ } catch {
2417
+ throw new McpSearchError();
2418
+ }
2419
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new McpSearchError();
2420
+ const hits = parsed.hits;
2421
+ if (!Array.isArray(hits)) throw new McpSearchError();
2422
+ const out = [];
2423
+ for (const hit of hits) {
2424
+ const row = asHit(hit, scope, exclude);
2425
+ if (row) out.push(row);
2426
+ }
2427
+ return out;
2428
+ }
2429
+ async function connect(input) {
2430
+ const exclude = await loadExcluder(input.projectRoot, input.search.exclude);
2431
+ let sources = [];
2432
+ try {
2433
+ const cfg = await loadMcpConfig(input.projectRoot);
2434
+ sources = cfg.sources.filter((source2) => source2.enabled);
2435
+ } catch {
2436
+ throw new McpSearchError();
2437
+ }
2438
+ const named = input.search.mcp_source;
2439
+ const source = named ? sources.find((item) => item.id === named) : sources.length === 1 ? sources[0] : void 0;
2440
+ if (!source) throw new McpSearchError();
2441
+ const tool = input.search.mcp_tool || source.invoke?.tool;
2442
+ if (!tool) throw new McpSearchError();
2443
+ if (source.tools?.length && !source.tools.includes(tool)) throw new McpSearchError();
2444
+ const call = input.call ?? (async (req) => {
2445
+ const result = await callMcpSourceTool(source, input.projectRoot, req.tool, req.args);
2446
+ return { ok: result.ok, text: result.text };
2447
+ });
2448
+ return { sourceId: source.id, tool, exclude, call };
2449
+ }
2450
+ function openMcpSearchProvider(input) {
2451
+ const timeoutMs = input.timeoutMs ?? mcpTimeoutMs();
2452
+ let ready3;
2453
+ async function load() {
2454
+ if (ready3) return ready3;
2455
+ ready3 = await connect(input);
2456
+ return ready3;
2457
+ }
2458
+ return {
2459
+ id: "mcp",
2460
+ async index(changed) {
2461
+ const session = await load();
2462
+ if (!changed) return emptyStats();
2463
+ const paths = allowedPaths(changed, session.exclude);
2464
+ if (paths.length === 0) return emptyStats(changed.length);
2465
+ const result = await withTimeout(
2466
+ session.call({ sourceId: session.sourceId, tool: session.tool, args: { paths } }),
2467
+ timeoutMs
2468
+ );
2469
+ if (!result.ok) throw new McpSearchError();
2470
+ return emptyStats(changed.length, paths.length);
2471
+ },
2472
+ async search(query, options) {
2473
+ const session = await load();
2474
+ const args = { query, scope: options.scope };
2475
+ const result = await withTimeout(
2476
+ session.call({ sourceId: session.sourceId, tool: session.tool, args }),
2477
+ timeoutMs
2478
+ );
2479
+ if (!result.ok) throw new McpSearchError();
2480
+ const hits = parseHits(result.text, options.scope, session.exclude);
2481
+ const preamble = searchPreamble(query, options.scope, options.budget, false, "mcp");
2482
+ const packed = packHits({ preamble, hits, budget: options.budget });
2483
+ return {
2484
+ provider: "mcp",
2485
+ query,
2486
+ scope: options.scope,
2487
+ budget: options.budget,
2488
+ usedTokens: packed.usedTokens,
2489
+ hits: packed.hits,
2490
+ text: packed.text
2491
+ };
2492
+ },
2493
+ stats() {
2494
+ return Promise.resolve(emptyStats());
2495
+ }
2496
+ };
2497
+ }
2498
+
2334
2499
  // src/search/registry.ts
2335
2500
  var extra = /* @__PURE__ */ new Map();
2336
2501
  function registerSearchProvider(provider) {
@@ -2347,13 +2512,18 @@ function joinWarning(left, right) {
2347
2512
  ${right}`;
2348
2513
  return left || right;
2349
2514
  }
2350
- function resolveSearchProvider(projectRoot, config, search, runtime) {
2515
+ function resolveSearchProvider(projectRoot, config, search, runtime, run) {
2351
2516
  const builtin = createBuiltinProvider(projectRoot, config, runtime);
2352
2517
  const name = search.provider || "builtin";
2353
2518
  if (name === "builtin") return builtin;
2354
2519
  const registered = extra.get(name);
2355
- let active = registered ?? builtin;
2356
- let warning = registered ? void 0 : fallbackWarning(name);
2520
+ let active = name === "mcp" ? openMcpSearchProvider({
2521
+ projectRoot,
2522
+ search,
2523
+ call: run?.mcpCall,
2524
+ timeoutMs: run?.mcpTimeoutMs
2525
+ }) : registered ?? builtin;
2526
+ let warning = name === "mcp" || registered ? void 0 : fallbackWarning(name);
2357
2527
  const mark = () => {
2358
2528
  warning = fallbackWarning(name);
2359
2529
  active = builtin;
@@ -2373,7 +2543,6 @@ function resolveSearchProvider(projectRoot, config, search, runtime) {
2373
2543
  try {
2374
2544
  const result = await active.search(query, options);
2375
2545
  result.warning = joinWarning(warning, result.warning);
2376
- result.provider = "builtin";
2377
2546
  return result;
2378
2547
  } catch (err) {
2379
2548
  if (active.id === "builtin") throw err;
@@ -2404,12 +2573,11 @@ async function buildRetrievedInner(projectRoot, config, title, stage, budget, ru
2404
2573
  return `Retrieved context skipped: ${safeMessage(err, projectRoot)}.`;
2405
2574
  }
2406
2575
  const limit = budget ?? budgetForStage(search, stage);
2407
- const provider = resolveSearchProvider(projectRoot, config, search, runtime);
2576
+ const provider = createBuiltinProvider(projectRoot, config, runtime);
2408
2577
  try {
2409
2578
  await provider.index();
2410
2579
  } catch (err) {
2411
- const message = provider.id === "builtin" ? safeMessage(err, projectRoot) : fallbackWarning(search.provider);
2412
- return `Retrieved context skipped: ${message}.`;
2580
+ return `Retrieved context skipped: ${safeMessage(err, projectRoot)}.`;
2413
2581
  }
2414
2582
  const request = {
2415
2583
  projectRoot,
@@ -2456,13 +2624,12 @@ async function buildRetrievedInner(projectRoot, config, title, stage, budget, ru
2456
2624
  }
2457
2625
  return packed.text;
2458
2626
  } catch (err) {
2459
- const message = search.provider === "builtin" ? safeMessage(err, projectRoot) : fallbackWarning(search.provider);
2460
- return `Retrieved context skipped: ${message}.`;
2627
+ return `Retrieved context skipped: ${safeMessage(err, projectRoot)}.`;
2461
2628
  }
2462
2629
  }
2463
- async function executeSearch(projectRoot, config, query, scope, budget) {
2630
+ async function executeSearch(projectRoot, config, query, scope, budget, run) {
2464
2631
  const search = await loadSearchConfig(projectRoot);
2465
- const provider = resolveSearchProvider(projectRoot, config, search);
2632
+ const provider = resolveSearchProvider(projectRoot, config, search, void 0, run);
2466
2633
  await provider.index();
2467
2634
  const options = {
2468
2635
  scope,
@@ -2668,7 +2835,7 @@ function stringList(value) {
2668
2835
  }
2669
2836
  return out;
2670
2837
  }
2671
- function parseRoleDocument(name, raw) {
2838
+ function splitFrontmatter(raw) {
2672
2839
  const text = raw.replace(/^\uFEFF/, "");
2673
2840
  const nl = text.indexOf("\n");
2674
2841
  if (nl < 0 || text.slice(0, nl).trim() !== "---") return null;
@@ -2682,14 +2849,22 @@ function parseRoleDocument(name, raw) {
2682
2849
  return null;
2683
2850
  }
2684
2851
  if (!data || typeof data !== "object" || Array.isArray(data)) return null;
2685
- const rec = data;
2852
+ return {
2853
+ data,
2854
+ body: rest.slice(close.index + close[0].length).trim()
2855
+ };
2856
+ }
2857
+ function parseRoleDocument(name, raw) {
2858
+ const split = splitFrontmatter(raw);
2859
+ if (!split) return null;
2860
+ const rec = split.data;
2686
2861
  const lists = emptyRoleLists();
2687
2862
  for (const [field2, key] of LIST_FIELDS) {
2688
2863
  const parsed = stringList(rec[key]);
2689
2864
  if (!parsed) return null;
2690
2865
  lists[field2] = parsed;
2691
2866
  }
2692
- const body = rest.slice(close.index + close[0].length).trim();
2867
+ const body = split.body;
2693
2868
  return {
2694
2869
  name,
2695
2870
  label: asText(rec.label),
@@ -2701,7 +2876,7 @@ function parseRoleDocument(name, raw) {
2701
2876
  ...lists
2702
2877
  };
2703
2878
  }
2704
- function renderRole(role) {
2879
+ function renderRole(role, routines) {
2705
2880
  const record = {
2706
2881
  name: role.name,
2707
2882
  label: role.label,
@@ -2710,6 +2885,7 @@ function renderRole(role) {
2710
2885
  pinned: role.pinned,
2711
2886
  hidden: role.hidden
2712
2887
  };
2888
+ if (routines?.keep) record.routines = routines.value;
2713
2889
  for (const [field2, key] of LIST_FIELDS) {
2714
2890
  if (role[field2].length > 0) record[key] = role[field2];
2715
2891
  }
@@ -2748,8 +2924,15 @@ async function readRole(root, name) {
2748
2924
  return null;
2749
2925
  }
2750
2926
  }
2751
- async function writeRole(root, role) {
2752
- await writeText(roleFilePath(root, role.name), renderRole(role));
2927
+ async function keptRoutines(root, name) {
2928
+ const path = roleFilePath(root, name);
2929
+ if (!await pathExists(path)) return void 0;
2930
+ const split = splitFrontmatter(await readText(path));
2931
+ if (!split || !Object.hasOwn(split.data, "routines")) return void 0;
2932
+ return { keep: true, value: split.data.routines };
2933
+ }
2934
+ async function writeRole(root, role, routines) {
2935
+ await writeText(roleFilePath(root, role.name), renderRole(role, routines));
2753
2936
  }
2754
2937
  async function createRole(root, input) {
2755
2938
  const name = canonicalRoleName(input.name);
@@ -2784,7 +2967,7 @@ async function editRole(root, nameInput, patch) {
2784
2967
  if (patch.description !== void 0) role.description = patch.description.trim();
2785
2968
  if (patch.askFirst !== void 0) role.askFirst = patch.askFirst;
2786
2969
  if (patch.stages !== void 0) role.stages = patch.stages;
2787
- await writeRole(root, role);
2970
+ await writeRole(root, role, await keptRoutines(root, name));
2788
2971
  return ok();
2789
2972
  }
2790
2973
  async function setFlag(root, nameInput, flag) {
@@ -2793,7 +2976,7 @@ async function setFlag(root, nameInput, flag) {
2793
2976
  const role = await readRole(root, name);
2794
2977
  if (!role) return fail(ROLE_TEXT.notFound);
2795
2978
  role[flag] = true;
2796
- await writeRole(root, role);
2979
+ await writeRole(root, role, await keptRoutines(root, name));
2797
2980
  return ok();
2798
2981
  }
2799
2982
  function pinRole(root, name) {
@@ -2836,7 +3019,7 @@ async function duplicateRole(root, nameInput) {
2836
3019
  const copyName = canonicalRoleName(`${name} copy`);
2837
3020
  if (!copyName) return fail(ROLE_TEXT.badName);
2838
3021
  if (await pathExists(roleFilePath(root, copyName))) return fail(ROLE_TEXT.exists);
2839
- await writeRole(root, { ...source, name: copyName });
3022
+ await writeRole(root, { ...source, name: copyName }, await keptRoutines(root, name));
2840
3023
  return ok();
2841
3024
  }
2842
3025
  async function deleteRole(root, nameInput) {
@@ -3321,9 +3504,9 @@ async function buildAgentPrompt(ctx, config, projectRoot, budget, runtime) {
3321
3504
  parts.push("");
3322
3505
  }
3323
3506
  try {
3324
- const { loadMcpConfig } = await import("./sources-3TXUPU6V.js");
3325
- const { gatherMcpContextForChange, formatMcpContextForHandoff } = await import("./gather-A3Q4WSPH.js");
3326
- const mcpCfg = await loadMcpConfig(projectRoot);
3507
+ const { loadMcpConfig: loadMcpConfig2 } = await import("./sources-3TXUPU6V.js");
3508
+ const { gatherMcpContextForChange, formatMcpContextForHandoff } = await import("./gather-ZK722X65.js");
3509
+ const mcpCfg = await loadMcpConfig2(projectRoot);
3327
3510
  if (mcpCfg.auto_fetch_on_handoff && mcpCfg.sources.length) {
3328
3511
  const fetched = await gatherMcpContextForChange(projectRoot, ctx);
3329
3512
  const block = formatMcpContextForHandoff(fetched.filter((r) => r.ok || r.error));
@@ -3414,6 +3597,7 @@ export {
3414
3597
  listScopeHits,
3415
3598
  rankScope,
3416
3599
  searchProject,
3600
+ openMcpSearchProvider,
3417
3601
  registerSearchProvider,
3418
3602
  clearRegisteredSearchProviders,
3419
3603
  fallbackWarning,
@@ -3429,6 +3613,7 @@ export {
3429
3613
  conversationDir,
3430
3614
  memoryDir,
3431
3615
  allowFilePath,
3616
+ splitFrontmatter,
3432
3617
  parseRoleDocument,
3433
3618
  rolesListingStage,
3434
3619
  readRole,