@minhpnq1807/contextos 0.5.35 → 0.5.37
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.37
|
|
4
|
+
|
|
5
|
+
- **Real-time animated progress bar for `ctx install`:** The progress spinner now updates in-place using raw stderr writes (`\r`) instead of being captured by `streamSetupOutput`. Uses a smooth 10-frame Braille spinner (`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`) with a visual bar (`[████████░░░░]`) that animates at 80ms intervals.
|
|
6
|
+
- **Clean install output:** Reduced verbose per-agent install summary from 10+ lines of paths to a compact 4-line summary (Hooks →, MCP →, Embeddings count, restart instruction). Removed redundant "embedding model already cached" log line from `warmInstallEmbeddings`.
|
|
7
|
+
- **Fix `streamSetupOutput` breaking spinner:** Previously intercepted `process.stderr.write` and converted `\r` carriage returns to newlines, preventing in-place updates. Now only intercepts `console.log` for `│ ` prefixed output, leaving stderr untouched for spinner rendering.
|
|
8
|
+
|
|
9
|
+
## 0.5.36
|
|
10
|
+
|
|
11
|
+
- **Fix ctx_score_context MCP output not rendering in Antigravity editor:** The `content` text block returned by the MCP tool previously only contained raw telemetry JSON, which editors cannot render as user-facing context. Now the tool uses `scheduleContext()` to produce the same human-readable markdown (Critical ContextOS rules, Suggested files, Skills, Workflows) that the hook path generates, and returns it as the primary `content[0].text` block. Telemetry JSON is pushed to a secondary content block. This ensures Antigravity (and any MCP-compatible editor) displays the scored rules and file suggestions.
|
|
12
|
+
- **Fix symlink incompatibility with antigravity-awesome-skills:** `copyDirectory` in `skillshare-sync.js` was preserving symlinks when copying skills, which caused `antigravity-awesome-skills` to crash with "Skipping unsafe destination symlink" on re-install. Now follows symlinks and copies actual file content instead, making output compatible with all tools that write to the same skills directory.
|
|
13
|
+
- **Updated MCP protocol smoke test:** Assertions now validate the two-block content structure — human-readable context first, telemetry JSON last.
|
|
14
|
+
|
|
3
15
|
## 0.5.35
|
|
4
16
|
|
|
5
17
|
- **Add GitHub Copilot agent support:** New `copilot` agent for `ctx install --agent copilot` and `ctx setup`. Creates `.github/copilot-instructions.md` with ContextOS integration marker and configures `ctx-mcp` MCP server in `.vscode/mcp.json`. Copilot is now recognized by Ruler (`ctx sync --rules`) and Skillshare (`ctx sync --skills`) alongside existing codex, claude, and agy agents.
|
package/bin/ctx.js
CHANGED
|
@@ -102,45 +102,42 @@ function normalizeInstallAgent(agent) {
|
|
|
102
102
|
return normalized;
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
|
-
* Intercept console.log
|
|
105
|
+
* Intercept console.log from an async fn,
|
|
106
106
|
* printing each line immediately with "│ " prefix for real-time feedback.
|
|
107
|
+
* stderr is left untouched so \r-based spinner writes render in-place.
|
|
107
108
|
* Returns the collected lines array (for callers that inspect it).
|
|
108
109
|
*/
|
|
109
110
|
async function streamSetupOutput(fn) {
|
|
110
111
|
const lines = [];
|
|
111
112
|
const origLog = console.log;
|
|
112
|
-
const origStderrWrite = process.stderr.write;
|
|
113
113
|
const emit = (text) => {
|
|
114
114
|
lines.push(text);
|
|
115
115
|
origLog(`│ ${text}`);
|
|
116
116
|
};
|
|
117
117
|
console.log = (...args) => emit(args.map(String).join(" "));
|
|
118
|
-
process.stderr.write = (chunk) => {
|
|
119
|
-
const text = String(chunk).replace(/\r/g, "").trim();
|
|
120
|
-
if (text) emit(text);
|
|
121
|
-
return true;
|
|
122
|
-
};
|
|
123
118
|
try {
|
|
124
119
|
await fn();
|
|
125
120
|
} finally {
|
|
126
121
|
console.log = origLog;
|
|
127
|
-
process.stderr.write = origStderrWrite;
|
|
128
122
|
}
|
|
129
123
|
return lines;
|
|
130
124
|
}
|
|
131
125
|
|
|
132
126
|
function createInstallProgress({ quiet = false } = {}) {
|
|
133
|
-
const
|
|
134
|
-
const frames = ["
|
|
127
|
+
const isTTY = !quiet && process.stderr.isTTY;
|
|
128
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
135
129
|
let percent = 0;
|
|
136
130
|
let label = "starting";
|
|
137
131
|
let frame = 0;
|
|
138
132
|
let timer = null;
|
|
133
|
+
// Use the raw stderr binding so streamSetupOutput cannot intercept spinner writes.
|
|
134
|
+
const rawStderrWrite = process.stderr.write.bind(process.stderr);
|
|
139
135
|
|
|
140
136
|
function render() {
|
|
141
|
-
if (!
|
|
142
|
-
const
|
|
143
|
-
|
|
137
|
+
if (!isTTY) return;
|
|
138
|
+
const bar = progressBar(percent);
|
|
139
|
+
const text = ` ${frames[frame % frames.length]} ${bar} ${label}`;
|
|
140
|
+
rawStderrWrite(`\r${text.padEnd(72)}`);
|
|
144
141
|
frame += 1;
|
|
145
142
|
}
|
|
146
143
|
|
|
@@ -148,43 +145,48 @@ function createInstallProgress({ quiet = false } = {}) {
|
|
|
148
145
|
start(initialLabel = "starting") {
|
|
149
146
|
label = initialLabel;
|
|
150
147
|
percent = 0;
|
|
151
|
-
if (
|
|
148
|
+
if (isTTY) {
|
|
152
149
|
render();
|
|
153
|
-
timer = setInterval(render,
|
|
150
|
+
timer = setInterval(render, 80);
|
|
154
151
|
} else if (!quiet) {
|
|
155
|
-
console.log(`[ctx]
|
|
152
|
+
console.log(`[ctx] ${label}...`);
|
|
156
153
|
}
|
|
157
154
|
},
|
|
158
155
|
step(nextPercent, nextLabel) {
|
|
159
156
|
percent = Math.max(percent, Math.min(100, nextPercent));
|
|
160
157
|
label = nextLabel;
|
|
161
|
-
if (
|
|
162
|
-
else if (!quiet) console.log(`[ctx] install ${percent}% ${label}`);
|
|
158
|
+
if (isTTY) render();
|
|
163
159
|
},
|
|
164
160
|
done(finalLabel = "done") {
|
|
165
161
|
percent = 100;
|
|
166
162
|
label = finalLabel;
|
|
167
163
|
if (timer) clearInterval(timer);
|
|
168
164
|
timer = null;
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
if (isTTY) {
|
|
166
|
+
const bar = progressBar(100);
|
|
167
|
+
rawStderrWrite(`\r ✓ ${bar} ${label}`.padEnd(72) + "\n");
|
|
172
168
|
} else if (!quiet) {
|
|
173
|
-
console.log(`[ctx]
|
|
169
|
+
console.log(`[ctx] ✓ ${label}`);
|
|
174
170
|
}
|
|
175
171
|
},
|
|
176
172
|
fail(errorLabel = "failed") {
|
|
177
173
|
label = errorLabel;
|
|
178
174
|
if (timer) clearInterval(timer);
|
|
179
175
|
timer = null;
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
process.stderr.write("\n");
|
|
176
|
+
if (isTTY) {
|
|
177
|
+
rawStderrWrite(`\r ✗ ${errorLabel}`.padEnd(72) + "\n");
|
|
183
178
|
}
|
|
184
179
|
}
|
|
185
180
|
};
|
|
186
181
|
}
|
|
187
182
|
|
|
183
|
+
function progressBar(percent) {
|
|
184
|
+
const width = 20;
|
|
185
|
+
const filled = Math.round(width * percent / 100);
|
|
186
|
+
const empty = width - filled;
|
|
187
|
+
return `[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${String(percent).padStart(3)}%`;
|
|
188
|
+
}
|
|
189
|
+
|
|
188
190
|
function packageVersion() {
|
|
189
191
|
try {
|
|
190
192
|
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"));
|
|
@@ -224,81 +226,60 @@ async function install({ copy = false, agent = "codex" } = {}) {
|
|
|
224
226
|
if (agent === "claude") {
|
|
225
227
|
progress.step(10, "copying package");
|
|
226
228
|
const installRoot = copyPackageRoot({ rootDir, targetRoot: agentInstallRoot("claude") });
|
|
227
|
-
progress.step(
|
|
229
|
+
progress.step(30, "installing hooks");
|
|
228
230
|
const hooksPath = installClaudeHooks({ installRoot, injectPromptContext: inject });
|
|
229
|
-
progress.step(
|
|
231
|
+
progress.step(50, "installing mcp");
|
|
230
232
|
const mcpConfigPath = installClaudeMcp({ installRoot });
|
|
231
|
-
progress.step(
|
|
233
|
+
progress.step(60, "configuring gitignore");
|
|
232
234
|
writeInnerGitignore(installRoot);
|
|
233
235
|
ensureRootGitignore(process.cwd());
|
|
234
|
-
progress.step(
|
|
236
|
+
progress.step(70, "warming embeddings");
|
|
235
237
|
const warmResult = await warmInstallEmbeddings();
|
|
236
|
-
progress.done("claude
|
|
237
|
-
console.log(
|
|
238
|
-
console.log(`
|
|
239
|
-
console.log(`
|
|
240
|
-
console.log(
|
|
241
|
-
console.log(`Embedding model cache: ${modelCacheDir(contextOSDataDir())}`);
|
|
242
|
-
console.log(`Embedding vectors cache: ${warmResult.cachePath}`);
|
|
243
|
-
console.log(`File path embeddings warmed: ${warmResult.fileCount || 0}`);
|
|
244
|
-
console.log(`Skill embeddings warmed: ${warmResult.skillCount || 0}`);
|
|
245
|
-
console.log(`Workflow embeddings warmed: ${warmResult.workflowCount || 0}`);
|
|
246
|
-
console.log(`Prompt context injection: ${inject ? "enabled" : "quiet logging only"}`);
|
|
247
|
-
console.log("Restart Claude Code if it was already running, then submit a task to trigger ContextOS.");
|
|
238
|
+
progress.done("claude ✓");
|
|
239
|
+
console.log(`Hooks → ${hooksPath}`);
|
|
240
|
+
console.log(`MCP → ${mcpConfigPath}`);
|
|
241
|
+
console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
|
|
242
|
+
console.log("Restart Claude Code to activate ContextOS.");
|
|
248
243
|
return;
|
|
249
244
|
}
|
|
250
245
|
|
|
251
246
|
if (agent === "agy") {
|
|
252
247
|
progress.step(10, "copying package");
|
|
253
248
|
const installRoot = copyPackageRoot({ rootDir, targetRoot: agentInstallRoot("agy") });
|
|
254
|
-
progress.step(
|
|
249
|
+
progress.step(30, "installing hooks");
|
|
255
250
|
const hooksPath = installAntigravityHooks({ installRoot, injectPromptContext: inject });
|
|
256
|
-
progress.step(
|
|
251
|
+
progress.step(50, "installing mcp");
|
|
257
252
|
const mcpConfigPaths = installAntigravityMcp({ installRoot });
|
|
258
|
-
progress.step(
|
|
253
|
+
progress.step(60, "configuring gitignore");
|
|
259
254
|
writeInnerGitignore(installRoot);
|
|
260
255
|
ensureRootGitignore(process.cwd());
|
|
261
|
-
progress.step(
|
|
256
|
+
progress.step(70, "warming embeddings");
|
|
262
257
|
const warmResult = await warmInstallEmbeddings();
|
|
263
|
-
progress.done("
|
|
264
|
-
console.log(
|
|
265
|
-
console.log(`
|
|
266
|
-
console.log(`
|
|
267
|
-
console.log(
|
|
268
|
-
console.log(`Embedding model cache: ${modelCacheDir(contextOSDataDir())}`);
|
|
269
|
-
console.log(`Embedding vectors cache: ${warmResult.cachePath}`);
|
|
270
|
-
console.log(`File path embeddings warmed: ${warmResult.fileCount || 0}`);
|
|
271
|
-
console.log(`Skill embeddings warmed: ${warmResult.skillCount || 0}`);
|
|
272
|
-
console.log(`Workflow embeddings warmed: ${warmResult.workflowCount || 0}`);
|
|
273
|
-
console.log(`Prompt context injection: ${inject ? "enabled" : "quiet logging only"}`);
|
|
274
|
-
console.log("Restart Antigravity or agy if it was already running, then submit a task to trigger ContextOS.");
|
|
258
|
+
progress.done("antigravity ✓");
|
|
259
|
+
console.log(`Hooks → ${hooksPath}`);
|
|
260
|
+
console.log(`MCP → ${mcpConfigPaths.join(", ")}`);
|
|
261
|
+
console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
|
|
262
|
+
console.log("Restart Antigravity to activate ContextOS.");
|
|
275
263
|
return;
|
|
276
264
|
}
|
|
277
265
|
|
|
278
266
|
if (agent === "copilot") {
|
|
279
267
|
progress.step(10, "copying package");
|
|
280
268
|
const installRoot = copyPackageRoot({ rootDir, targetRoot: agentInstallRoot("copilot") });
|
|
281
|
-
progress.step(
|
|
269
|
+
progress.step(30, "installing hooks");
|
|
282
270
|
const hooksPath = installCopilotHooks({ cwd: process.cwd(), installRoot });
|
|
283
|
-
progress.step(
|
|
271
|
+
progress.step(50, "installing mcp");
|
|
284
272
|
const mcpConfigPath = installCopilotMcp({ cwd: process.cwd(), installRoot });
|
|
285
|
-
progress.step(
|
|
273
|
+
progress.step(60, "configuring gitignore");
|
|
286
274
|
writeInnerGitignore(installRoot);
|
|
287
275
|
ensureRootGitignore(process.cwd());
|
|
288
|
-
progress.step(
|
|
276
|
+
progress.step(70, "warming embeddings");
|
|
289
277
|
const warmResult = await warmInstallEmbeddings();
|
|
290
|
-
progress.done("copilot
|
|
291
|
-
console.log(
|
|
292
|
-
console.log(`
|
|
293
|
-
console.log(`
|
|
294
|
-
console.log(
|
|
295
|
-
console.log(`Embedding model cache: ${modelCacheDir(contextOSDataDir())}`);
|
|
296
|
-
console.log(`Embedding vectors cache: ${warmResult.cachePath}`);
|
|
297
|
-
console.log(`File path embeddings warmed: ${warmResult.fileCount || 0}`);
|
|
298
|
-
console.log(`Skill embeddings warmed: ${warmResult.skillCount || 0}`);
|
|
299
|
-
console.log(`Workflow embeddings warmed: ${warmResult.workflowCount || 0}`);
|
|
300
|
-
console.log(`Prompt context injection: ${inject ? "enabled" : "quiet logging only"}`);
|
|
301
|
-
console.log("Restart VS Code or Copilot if it was already running, then submit a task to trigger ContextOS.");
|
|
278
|
+
progress.done("copilot ✓");
|
|
279
|
+
console.log(`Instructions → ${hooksPath}`);
|
|
280
|
+
console.log(`MCP → ${mcpConfigPath}`);
|
|
281
|
+
console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
|
|
282
|
+
console.log("Restart VS Code to activate ContextOS.");
|
|
302
283
|
return;
|
|
303
284
|
}
|
|
304
285
|
|
|
@@ -310,38 +291,31 @@ async function install({ copy = false, agent = "codex" } = {}) {
|
|
|
310
291
|
const marketplaceRoot = path.join(codexHome(), "marketplaces", "contextos");
|
|
311
292
|
copyPackageRoot({ rootDir, targetRoot: marketplaceRoot });
|
|
312
293
|
|
|
313
|
-
progress.step(
|
|
294
|
+
progress.step(25, "refreshing codex plugin");
|
|
314
295
|
tryRunCodex(["plugin", "remove", "ctx@contextos"]);
|
|
315
296
|
tryRunCodex(["plugin", "marketplace", "remove", "contextos"]);
|
|
316
297
|
tryRunCodex(["mcp", "remove", "ctx-mcp"]);
|
|
317
298
|
runCodex(["plugin", "marketplace", "add", marketplaceRoot]);
|
|
318
299
|
runCodex(["plugin", "add", "ctx@contextos"]);
|
|
319
|
-
progress.step(
|
|
300
|
+
progress.step(45, "installing mcp");
|
|
320
301
|
runCodex(["mcp", "add", "ctx-mcp", "--", "node", path.join(marketplaceRoot, "plugins", "ctx", "mcp", "server.js")]);
|
|
321
|
-
progress.step(
|
|
302
|
+
progress.step(55, "installing telemetry proxies");
|
|
322
303
|
const proxyResult = installMcpTelemetryProxies({ codexHome: codexHome(), marketplaceRoot });
|
|
323
|
-
progress.step(
|
|
304
|
+
progress.step(65, "installing hooks");
|
|
324
305
|
const hooksPath = installGlobalHooks({ codexHome: codexHome(), marketplaceRoot, injectPromptContext: inject });
|
|
325
306
|
|
|
326
|
-
progress.step(
|
|
307
|
+
progress.step(70, "configuring gitignore");
|
|
327
308
|
writeInnerGitignore(marketplaceRoot);
|
|
328
309
|
ensureRootGitignore(process.cwd());
|
|
329
310
|
|
|
330
|
-
progress.step(
|
|
311
|
+
progress.step(80, "warming embeddings");
|
|
331
312
|
const warmResult = await warmInstallEmbeddings();
|
|
332
|
-
progress.done("codex
|
|
333
|
-
console.log(
|
|
334
|
-
console.log(`
|
|
335
|
-
console.log(`
|
|
336
|
-
console.log(
|
|
337
|
-
console.log(
|
|
338
|
-
console.log(`Embedding model cache: ${modelCacheDir(contextOSDataDir())}`);
|
|
339
|
-
console.log(`Embedding vectors cache: ${warmResult.cachePath}`);
|
|
340
|
-
console.log(`File path embeddings warmed: ${warmResult.fileCount || 0}`);
|
|
341
|
-
console.log(`Skill embeddings warmed: ${warmResult.skillCount || 0}`);
|
|
342
|
-
console.log(`Workflow embeddings warmed: ${warmResult.workflowCount || 0}`);
|
|
343
|
-
console.log(`Prompt context injection: ${inject ? "enabled" : "quiet logging only"}`);
|
|
344
|
-
console.log("Restart Codex if it was already running, then submit a task to trigger ContextOS.");
|
|
313
|
+
progress.done("codex ✓");
|
|
314
|
+
console.log(`Hooks → ${hooksPath}`);
|
|
315
|
+
console.log(`MCP → ctx-mcp installed`);
|
|
316
|
+
console.log(`Proxies → ${proxyResult.wrapped.length ? proxyResult.wrapped.map((item) => item.name).join(", ") : "none changed"}`);
|
|
317
|
+
console.log(`Embeddings: ${warmResult.fileCount || 0} files, ${warmResult.skillCount || 0} skills`);
|
|
318
|
+
console.log("Restart Codex to activate ContextOS.");
|
|
345
319
|
} catch (error) {
|
|
346
320
|
progress.fail("install failed");
|
|
347
321
|
throw error;
|
|
@@ -351,9 +325,6 @@ async function install({ copy = false, agent = "codex" } = {}) {
|
|
|
351
325
|
async function warmInstallEmbeddings() {
|
|
352
326
|
const dataDir = contextOSDataDir();
|
|
353
327
|
const modelReady = isModelCacheReady(dataDir);
|
|
354
|
-
console.log(modelReady
|
|
355
|
-
? "Required local embedding model already cached."
|
|
356
|
-
: "Preparing required local embedding model...");
|
|
357
328
|
const result = await warmRuleEmbeddings({
|
|
358
329
|
rules: [
|
|
359
330
|
{ content: "Always use project rules that are semantically relevant to the user prompt." },
|
package/package.json
CHANGED
|
@@ -330,11 +330,18 @@ function copyDirectory(sourceDir, targetDir) {
|
|
|
330
330
|
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
331
331
|
const source = path.join(sourceDir, entry.name);
|
|
332
332
|
const target = path.join(targetDir, entry.name);
|
|
333
|
-
if (entry.
|
|
333
|
+
if (entry.isSymbolicLink()) {
|
|
334
|
+
// Follow symlinks and copy real content to avoid incompatibility
|
|
335
|
+
// with tools like antigravity-awesome-skills that reject symlinks.
|
|
336
|
+
const real = fs.realpathSync(source);
|
|
337
|
+
const stat = fs.statSync(real);
|
|
338
|
+
if (stat.isDirectory()) {
|
|
339
|
+
copyDirectory(real, target);
|
|
340
|
+
} else if (stat.isFile()) {
|
|
341
|
+
fs.copyFileSync(real, target);
|
|
342
|
+
}
|
|
343
|
+
} else if (entry.isDirectory()) {
|
|
334
344
|
copyDirectory(source, target);
|
|
335
|
-
} else if (entry.isSymbolicLink()) {
|
|
336
|
-
const link = fs.readlinkSync(source);
|
|
337
|
-
fs.symlinkSync(link, target);
|
|
338
345
|
} else if (entry.isFile()) {
|
|
339
346
|
fs.copyFileSync(source, target);
|
|
340
347
|
}
|
|
@@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
import { scoreContext } from "../lib/score-context.js";
|
|
5
|
+
import { scheduleContext } from "../lib/scheduler.js";
|
|
5
6
|
|
|
6
7
|
export function createContextOSMcpServer({ dataDir }) {
|
|
7
8
|
const server = new McpServer({
|
|
@@ -51,13 +52,31 @@ export function createContextOSMcpServer({ dataDir }) {
|
|
|
51
52
|
skills: args.skills,
|
|
52
53
|
workflows: args.workflows
|
|
53
54
|
});
|
|
55
|
+
|
|
56
|
+
// Format the same human-readable context that the hook path produces
|
|
57
|
+
const scheduled = scheduleContext({
|
|
58
|
+
rules: result.scoredRules,
|
|
59
|
+
relevantFiles: result.suggestedFiles,
|
|
60
|
+
suggestedSkills: result.suggestedSkills,
|
|
61
|
+
suggestedWorkflows: result.suggestedWorkflows
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const contextText = scheduled.additionalContext || "";
|
|
65
|
+
const contentBlocks = [];
|
|
66
|
+
|
|
67
|
+
// Primary block: human-readable rules, files, skills, workflows
|
|
68
|
+
if (contextText) {
|
|
69
|
+
contentBlocks.push({ type: "text", text: contextText });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Secondary block: telemetry metadata
|
|
73
|
+
contentBlocks.push({
|
|
74
|
+
type: "text",
|
|
75
|
+
text: JSON.stringify(result.telemetry)
|
|
76
|
+
});
|
|
77
|
+
|
|
54
78
|
return {
|
|
55
|
-
content:
|
|
56
|
-
{
|
|
57
|
-
type: "text",
|
|
58
|
-
text: JSON.stringify(result.telemetry)
|
|
59
|
-
}
|
|
60
|
-
],
|
|
79
|
+
content: contentBlocks,
|
|
61
80
|
structuredContent: {
|
|
62
81
|
scoredRules: result.scoredRules,
|
|
63
82
|
suggestedFiles: result.suggestedFiles,
|
|
@@ -70,3 +89,4 @@ export function createContextOSMcpServer({ dataDir }) {
|
|
|
70
89
|
|
|
71
90
|
return server;
|
|
72
91
|
}
|
|
92
|
+
|