@context-engine-bridge/context-engine-mcp-bridge 0.0.27 → 0.0.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-engine-bridge/context-engine-mcp-bridge",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "description": "Context Engine MCP bridge (http/stdio proxy combining indexer + memory servers)",
5
5
  "bin": {
6
6
  "ctxce": "bin/ctxce.js",
package/src/mcpServer.js CHANGED
@@ -72,40 +72,6 @@ async function listMemoryTools(client) {
72
72
  }
73
73
  }
74
74
 
75
- function withTimeout(promise, ms, label) {
76
- return new Promise((resolve, reject) => {
77
- let settled = false;
78
- const timer = setTimeout(() => {
79
- if (settled) {
80
- return;
81
- }
82
- settled = true;
83
- const errorMessage =
84
- label != null
85
- ? `[ctxce] Timeout after ${ms}ms in ${label}`
86
- : `[ctxce] Timeout after ${ms}ms`;
87
- reject(new Error(errorMessage));
88
- }, ms);
89
- promise
90
- .then((value) => {
91
- if (settled) {
92
- return;
93
- }
94
- settled = true;
95
- clearTimeout(timer);
96
- resolve(value);
97
- })
98
- .catch((err) => {
99
- if (settled) {
100
- return;
101
- }
102
- settled = true;
103
- clearTimeout(timer);
104
- reject(err);
105
- });
106
- });
107
- }
108
-
109
75
  function getBridgeToolTimeoutMs() {
110
76
  try {
111
77
  const raw = process.env.CTXCE_TOOL_TIMEOUT_MSEC;
@@ -705,7 +671,7 @@ async function createBridgeServer(options) {
705
671
 
706
672
  let nextIndexerClient = null;
707
673
  try {
708
- const indexerTransport = new StreamableHTTPClientTransport(indexerUrl, transportOpts);
674
+ const indexerTransport = new StreamableHTTPClientTransport(new URL(indexerUrl), transportOpts);
709
675
  const client = new Client(
710
676
  {
711
677
  name: "ctx-context-engine-bridge-http-client",
@@ -729,7 +695,7 @@ async function createBridgeServer(options) {
729
695
  let nextMemoryClient = null;
730
696
  if (memoryUrl) {
731
697
  try {
732
- const memoryTransport = new StreamableHTTPClientTransport(memoryUrl, transportOpts);
698
+ const memoryTransport = new StreamableHTTPClientTransport(new URL(memoryUrl), transportOpts);
733
699
  const client = new Client(
734
700
  {
735
701
  name: "ctx-context-engine-bridge-memory-client",
@@ -860,6 +826,9 @@ async function createBridgeServer(options) {
860
826
  args = maybeRemapToolArgs(name, args, workspace);
861
827
 
862
828
  if (name === "set_session_defaults") {
829
+ if (!indexerClient) {
830
+ throw new Error("Indexer client not connected");
831
+ }
863
832
  const indexerResult = await indexerClient.callTool({ name, arguments: args });
864
833
  if (memoryClient) {
865
834
  try {
package/src/uploader.js CHANGED
@@ -129,33 +129,76 @@ export async function createBundle(workspacePath, options = {}) {
129
129
  log(`[uploader] Found ${files.length} code files`);
130
130
 
131
131
  const bundleId = createHash("sha256").update(Date.now().toString() + Math.random().toString()).digest("hex").slice(0, 16);
132
+ const createdAt = new Date().toISOString();
133
+
134
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ctxce-"));
135
+ const bundleDir = path.join(tmpDir, bundleId);
136
+ const metadataDir = path.join(bundleDir, ".metadata");
137
+ const filesDir = path.join(bundleDir, "files");
138
+
139
+ fs.mkdirSync(metadataDir, { recursive: true });
140
+ fs.mkdirSync(filesDir, { recursive: true });
141
+
142
+ const operations = [];
143
+ const fileHashes = {};
144
+ let totalSize = 0;
145
+
146
+ for (const file of files) {
147
+ const destPath = path.join(filesDir, file.path);
148
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
149
+ fs.copyFileSync(file.fullPath, destPath);
150
+
151
+ const hash = computeFileHash(file.fullPath);
152
+ fileHashes[file.path] = hash;
153
+ totalSize += file.size;
154
+
155
+ operations.push({
156
+ op: "upsert",
157
+ path: file.path,
158
+ size: file.size,
159
+ hash,
160
+ });
161
+ }
132
162
 
133
163
  const manifest = {
164
+ version: "1.0",
134
165
  bundle_id: bundleId,
135
166
  workspace_path: workspacePath,
136
- logical_repo_id: computeLogicalRepoId(workspacePath),
137
- sequence_number: Date.now(),
138
- file_count: files.length,
139
- files: files.map(f => ({
140
- path: f.path,
141
- size: f.size,
142
- hash: computeFileHash(f.fullPath),
143
- })),
144
- created_at: new Date().toISOString(),
167
+ collection_name: computeLogicalRepoId(workspacePath),
168
+ created_at: createdAt,
169
+ sequence_number: null,
170
+ parent_sequence: null,
171
+ operations: {
172
+ created: files.length,
173
+ updated: 0,
174
+ deleted: 0,
175
+ moved: 0,
176
+ },
177
+ total_files: files.length,
178
+ total_size_bytes: totalSize,
179
+ compression: "gzip",
180
+ encoding: "utf-8",
145
181
  };
146
182
 
147
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ctxce-"));
148
- const bundlePath = path.join(tmpDir, `bundle-${bundleId}.tar.gz`);
183
+ fs.writeFileSync(path.join(bundleDir, "manifest.json"), JSON.stringify(manifest, null, 2));
184
+ fs.writeFileSync(path.join(metadataDir, "operations.json"), JSON.stringify({ operations }, null, 2));
185
+ fs.writeFileSync(path.join(metadataDir, "hashes.json"), JSON.stringify({
186
+ workspace_path: workspacePath,
187
+ updated_at: createdAt,
188
+ file_hashes: fileHashes,
189
+ }, null, 2));
190
+
191
+ const bundlePath = path.join(tmpDir, `${bundleId}.tar.gz`);
149
192
 
150
193
  try {
151
194
  await tarCreate(
152
195
  {
153
196
  gzip: true,
154
197
  file: bundlePath,
155
- cwd: workspacePath,
198
+ cwd: tmpDir,
156
199
  portable: true,
157
200
  },
158
- files.map(f => f.path)
201
+ [bundleId]
159
202
  );
160
203
 
161
204
  const bundleSize = fs.statSync(bundlePath).size;
@@ -194,13 +237,13 @@ export async function uploadBundle(bundlePath, manifest, uploadEndpoint, session
194
237
  parts.push(bundleData);
195
238
  parts.push(`\r\n`);
196
239
 
240
+ const logicalRepoId = computeLogicalRepoId(manifest.workspace_path);
197
241
  const fields = {
198
242
  workspace_path: manifest.workspace_path,
199
- collection_name: manifest.logical_repo_id,
200
- sequence_number: String(manifest.sequence_number),
243
+ collection_name: manifest.collection_name || logicalRepoId,
201
244
  force: "true",
202
245
  source_path: manifest.workspace_path,
203
- logical_repo_id: manifest.logical_repo_id,
246
+ logical_repo_id: logicalRepoId,
204
247
  session: sessionId,
205
248
  };
206
249
 
@@ -242,7 +285,11 @@ export async function uploadBundle(bundlePath, manifest, uploadEndpoint, session
242
285
  }
243
286
 
244
287
  if (!resp.ok || !result.success) {
245
- const errorMsg = result.error?.message || result.detail || `HTTP ${resp.status}`;
288
+ let errorMsg = result.error?.message || result.detail || result.error;
289
+ if (typeof errorMsg === "object") {
290
+ errorMsg = JSON.stringify(errorMsg);
291
+ }
292
+ errorMsg = errorMsg || `HTTP ${resp.status}`;
246
293
  log(`[uploader] Upload failed: ${errorMsg}`);
247
294
  return { success: false, error: errorMsg };
248
295
  }