@virsanghavi/axis-server 1.0.9 → 1.1.1

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.
@@ -1,2 +1,31 @@
1
- # Project Context
1
+ # Axis — Project Context
2
2
 
3
+ ## Overview
4
+ Axis is a distributed orchestration layer for parallel AI coding agents. It enables multiple agents (Cursor, Claude Code, Windsurf, Codex, Antigravity, etc.) to work on the same codebase simultaneously without collisions or context drift.
5
+
6
+ The core value proposition: **agents that coordinate like a team, not individuals who overwrite each other.**
7
+
8
+ ## Architecture
9
+ - **Frontend**: Next.js 14 (App Router) deployed on Vercel. Tailwind CSS, Framer Motion. Auth via Supabase.
10
+ - **Backend**: Next.js API routes + Supabase (Postgres, RLS, RPC functions). Stripe for billing.
11
+ - **MCP Server**: `@virsanghavi/axis-server` — an npm package that exposes Axis tools via the Model Context Protocol. Runs locally in each agent's IDE.
12
+ - **State**: All shared state (locks, jobs, notepad, sessions, embeddings) lives in Supabase, scoped per project. The MCP server syncs local state with the remote API.
13
+ - **File structure**:
14
+ - `shared-context/frontend/` — the web app (dashboard, billing, docs, auth)
15
+ - `shared-context/packages/axis-server/` — the MCP server package
16
+ - `shared-context/supabase/` — schema, migrations, RPC functions
17
+ - `.axis/instructions/` — soul files read by all agents via MCP
18
+
19
+ ## Core Features
20
+ 1. **Job Board**: Agents post, claim, and complete tasks. Priority-based, dependency-aware. Prevents duplicate work.
21
+ 2. **File Locking**: Atomic, per-file locks with 30-minute TTL. Agents call `propose_file_access` before editing. Prevents merge conflicts.
22
+ 3. **Live Notepad**: Real-time shared memory. Agents log progress so others know what's happening. Cleared on `finalize_session`.
23
+ 4. **Context Mirroring**: `get_project_soul` returns this file + conventions to ground agents in project reality.
24
+ 5. **RAG Search**: `search_codebase` and `search_docs` for semantic search over indexed files and documentation.
25
+ 6. **Session Management**: `finalize_session` archives the notepad, clears locks, resets for new work.
26
+ 7. **Billing**: Stripe-based Pro tier ($25/mo) with API key management, usage tracking, and retention flow.
27
+
28
+ ## Deployment
29
+ - Frontend: Vercel (auto-deploy from `shared-context/frontend/`)
30
+ - Database: Supabase (hosted Postgres)
31
+ - MCP Server: Published to npm, run locally via `npx @virsanghavi/axis-server`
@@ -1,2 +1,62 @@
1
- # Coding Conventions
1
+ # Axis — Coding Conventions & Agent Norms
2
2
 
3
+ ## Language Standards
4
+ - **TypeScript** for all frontend and API code. Strict mode. No `any` unless absolutely necessary.
5
+ - **SQL** for Supabase migrations. Use `IF NOT EXISTS` / `IF EXISTS` for idempotency.
6
+ - **HTML/CSS/JS** for standalone tools (e.g. sandbox apps). Single-file, no frameworks, no build step.
7
+
8
+ ## Styling
9
+ - Tailwind CSS exclusively. No custom CSS files unless for animations.
10
+ - Dark theme: `bg-[#050505]`, `text-white`, `border-white/5`. Light panels: `bg-white/95`, `text-neutral-900`.
11
+ - Typography: `lowercase` class on page wrappers. `font-mono` for technical content. `tracking-tight` default.
12
+ - Components: Minimal, no component library. Custom components in `components/`.
13
+
14
+ ## Testing
15
+ - Manual testing via browser and MCP tool calls.
16
+ - Health endpoint at `/api/health` checks Supabase and Stripe connectivity.
17
+
18
+ ## Code Patterns
19
+ - API routes use `getSessionFromRequest` for auth, `getClientIp` + `rateLimit` for rate limiting.
20
+ - Supabase queries use `.ilike('email', ...)` for case-insensitive email matching.
21
+ - Stripe customer IDs come from DB (`profiles.stripe_customer_id`). Never hardcode customer IDs.
22
+ - All Stripe routes have "no such customer" self-healing: look up by email, update DB, retry.
23
+
24
+ ---
25
+
26
+ ## Agent Behavioral Norms
27
+
28
+ ### Plan Before Write — The Core Invariant
29
+
30
+ **No agent writes code unless it either owns a file lock OR has explicitly declined the job board for a scoped reason.**
31
+
32
+ On non-trivial tasks (2+ files, new features, refactors):
33
+ 1. Break work into jobs → `post_job`
34
+ 2. Claim before editing → `claim_next_job`
35
+ 3. Lock before writing → `propose_file_access` with a **descriptive intent**
36
+ 4. Complete when done → `complete_job` with outcome
37
+
38
+ Direct edits without a job are allowed only for:
39
+ - Single-line fixes, typos, config tweaks
40
+ - Clearly scoped changes the user asked for directly
41
+
42
+ ### Force Unlock Policy
43
+
44
+ `force_unlock` is a **last resort, not a convenience tool.**
45
+
46
+ Rules:
47
+ 1. **Never** call `force_unlock` on a file you didn't lock unless:
48
+ - The lock has been held for >25 minutes (close to TTL expiry), AND
49
+ - The locking agent is clearly not responding or has crashed
50
+ 2. **Always** provide a specific reason (e.g. "Agent claude-code crashed 20 minutes ago, lock on auth.ts is blocking progress")
51
+ 3. **Never** force-unlock to skip coordination. If another agent holds a lock, work on something else.
52
+ 4. Prefer waiting for TTL expiry (30 min) over force-unlocking.
53
+
54
+ ### Lock Hygiene
55
+ - Always provide descriptive `intent` when locking (e.g. "Refactor auth middleware to use JWT validation" — not "editing file")
56
+ - Release locks early by completing jobs when done
57
+ - Call `finalize_session` at end of session to clean up all locks
58
+
59
+ ### Shared Memory
60
+ - Call `update_shared_context` after completing meaningful steps
61
+ - Log decisions, not just actions (e.g. "Chose JWT over session tokens because...")
62
+ - Other agents read the notepad in real-time — write for them
@@ -13,6 +13,42 @@ import dotenv2 from "dotenv";
13
13
  import fs from "fs/promises";
14
14
  import path from "path";
15
15
  import { Mutex } from "async-mutex";
16
+
17
+ // ../../src/utils/logger.ts
18
+ var Logger = class {
19
+ level = "info" /* INFO */;
20
+ setLevel(level) {
21
+ this.level = level;
22
+ }
23
+ log(level, message, meta) {
24
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
25
+ console.error(JSON.stringify({
26
+ timestamp,
27
+ level,
28
+ message,
29
+ ...meta
30
+ }));
31
+ }
32
+ debug(message, meta) {
33
+ if (this.level === "debug" /* DEBUG */) this.log("debug" /* DEBUG */, message, meta);
34
+ }
35
+ info(message, meta) {
36
+ this.log("info" /* INFO */, message, meta);
37
+ }
38
+ warn(message, meta) {
39
+ this.log("warn" /* WARN */, message, meta);
40
+ }
41
+ error(message, error, meta) {
42
+ this.log("error" /* ERROR */, message, {
43
+ ...meta,
44
+ error: error instanceof Error ? error.message : String(error),
45
+ stack: error instanceof Error ? error.stack : void 0
46
+ });
47
+ }
48
+ };
49
+ var logger = new Logger();
50
+
51
+ // ../../src/local/context-manager.ts
16
52
  import * as fsSync from "fs";
17
53
  function getEffectiveInstructionsDir() {
18
54
  const cwd = process.cwd();
@@ -131,45 +167,105 @@ var ContextManager = class {
131
167
  throw new Error("SHARED_CONTEXT_API_URL not configured.");
132
168
  }
133
169
  const endpoint = this.apiUrl.endsWith("/v1") ? `${this.apiUrl}/search` : `${this.apiUrl}/v1/search`;
134
- const response = await fetch(endpoint, {
135
- method: "POST",
136
- headers: {
137
- "Content-Type": "application/json",
138
- "Authorization": `Bearer ${this.apiSecret || ""}`
139
- },
140
- body: JSON.stringify({ query, projectName })
141
- });
142
- if (!response.ok) {
143
- const text = await response.text();
144
- throw new Error(`API Error ${response.status}: ${text}`);
145
- }
146
- const result = await response.json();
147
- if (result.results && Array.isArray(result.results)) {
148
- return result.results.map(
149
- (r) => `[Similarity: ${(r.similarity * 100).toFixed(1)}%] ${r.content}`
150
- ).join("\n\n---\n\n") || "No results found.";
170
+ const maxRetries = 3;
171
+ const baseDelay = 1e3;
172
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
173
+ const controller = new AbortController();
174
+ const timeout = setTimeout(() => controller.abort(), 15e3);
175
+ try {
176
+ const response = await fetch(endpoint, {
177
+ method: "POST",
178
+ headers: {
179
+ "Content-Type": "application/json",
180
+ "Authorization": `Bearer ${this.apiSecret || ""}`
181
+ },
182
+ body: JSON.stringify({ query, projectName }),
183
+ signal: controller.signal
184
+ });
185
+ clearTimeout(timeout);
186
+ if (!response.ok) {
187
+ const text = await response.text();
188
+ if (response.status >= 400 && response.status < 500) {
189
+ throw new Error(`API Error ${response.status}: ${text}`);
190
+ }
191
+ if (attempt < maxRetries) {
192
+ const delay = baseDelay * Math.pow(2, attempt - 1);
193
+ logger.warn(`[searchContext] 5xx error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`);
194
+ await new Promise((r) => setTimeout(r, delay));
195
+ continue;
196
+ }
197
+ throw new Error(`API Error ${response.status}: ${text}`);
198
+ }
199
+ const result = await response.json();
200
+ if (result.results && Array.isArray(result.results)) {
201
+ return result.results.map(
202
+ (r) => `[Similarity: ${(r.similarity * 100).toFixed(1)}%] ${r.content}`
203
+ ).join("\n\n---\n\n") || "No results found.";
204
+ }
205
+ throw new Error("No results format recognized.");
206
+ } catch (e) {
207
+ clearTimeout(timeout);
208
+ if (e.message.startsWith("API Error 4")) throw e;
209
+ if (attempt < maxRetries) {
210
+ const delay = baseDelay * Math.pow(2, attempt - 1);
211
+ logger.warn(`[searchContext] Network/timeout error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries}): ${e.message}`);
212
+ await new Promise((r) => setTimeout(r, delay));
213
+ continue;
214
+ }
215
+ throw e;
216
+ }
151
217
  }
152
- throw new Error("No results format recognized.");
218
+ throw new Error("searchContext: unexpected end of retry loop");
153
219
  }
154
220
  async embedContent(items, projectName = "default") {
155
221
  if (!this.apiUrl) {
156
- console.warn("Skipping RAG embedding: SHARED_CONTEXT_API_URL not configured.");
222
+ logger.warn("Skipping RAG embedding: SHARED_CONTEXT_API_URL not configured.");
157
223
  return;
158
224
  }
159
225
  const endpoint = this.apiUrl.endsWith("/v1") ? `${this.apiUrl}/embed` : `${this.apiUrl}/v1/embed`;
160
- const response = await fetch(endpoint, {
161
- method: "POST",
162
- headers: {
163
- "Content-Type": "application/json",
164
- "Authorization": `Bearer ${this.apiSecret || ""}`
165
- },
166
- body: JSON.stringify({ items, projectName })
167
- });
168
- if (!response.ok) {
169
- const text = await response.text();
170
- throw new Error(`API Error ${response.status}: ${text}`);
226
+ const maxRetries = 3;
227
+ const baseDelay = 1e3;
228
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
229
+ const controller = new AbortController();
230
+ const timeout = setTimeout(() => controller.abort(), 15e3);
231
+ try {
232
+ const response = await fetch(endpoint, {
233
+ method: "POST",
234
+ headers: {
235
+ "Content-Type": "application/json",
236
+ "Authorization": `Bearer ${this.apiSecret || ""}`
237
+ },
238
+ body: JSON.stringify({ items, projectName }),
239
+ signal: controller.signal
240
+ });
241
+ clearTimeout(timeout);
242
+ if (!response.ok) {
243
+ const text = await response.text();
244
+ if (response.status >= 400 && response.status < 500) {
245
+ throw new Error(`API Error ${response.status}: ${text}`);
246
+ }
247
+ if (attempt < maxRetries) {
248
+ const delay = baseDelay * Math.pow(2, attempt - 1);
249
+ logger.warn(`[embedContent] 5xx error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`);
250
+ await new Promise((r) => setTimeout(r, delay));
251
+ continue;
252
+ }
253
+ throw new Error(`API Error ${response.status}: ${text}`);
254
+ }
255
+ return await response.json();
256
+ } catch (e) {
257
+ clearTimeout(timeout);
258
+ if (e.message.startsWith("API Error 4")) throw e;
259
+ if (attempt < maxRetries) {
260
+ const delay = baseDelay * Math.pow(2, attempt - 1);
261
+ logger.warn(`[embedContent] Network/timeout error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries}): ${e.message}`);
262
+ await new Promise((r) => setTimeout(r, delay));
263
+ continue;
264
+ }
265
+ logger.warn(`[embedContent] Failed after ${maxRetries} attempts: ${e.message}. Skipping embed.`);
266
+ return;
267
+ }
171
268
  }
172
- return await response.json();
173
269
  }
174
270
  };
175
271
 
@@ -178,44 +274,16 @@ import { Mutex as Mutex2 } from "async-mutex";
178
274
  import { createClient } from "@supabase/supabase-js";
179
275
  import fs2 from "fs/promises";
180
276
  import path2 from "path";
181
-
182
- // ../../src/utils/logger.ts
183
- var Logger = class {
184
- level = "info" /* INFO */;
185
- setLevel(level) {
186
- this.level = level;
187
- }
188
- log(level, message, meta) {
189
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
190
- console.error(JSON.stringify({
191
- timestamp,
192
- level,
193
- message,
194
- ...meta
195
- }));
196
- }
197
- debug(message, meta) {
198
- if (this.level === "debug" /* DEBUG */) this.log("debug" /* DEBUG */, message, meta);
199
- }
200
- info(message, meta) {
201
- this.log("info" /* INFO */, message, meta);
202
- }
203
- warn(message, meta) {
204
- this.log("warn" /* WARN */, message, meta);
205
- }
206
- error(message, error, meta) {
207
- this.log("error" /* ERROR */, message, {
208
- ...meta,
209
- error: error instanceof Error ? error.message : String(error),
210
- stack: error instanceof Error ? error.stack : void 0
211
- });
212
- }
213
- };
214
- var logger = new Logger();
215
-
216
- // ../../src/local/nerve-center.ts
217
277
  var STATE_FILE = process.env.NERVE_CENTER_STATE_FILE || path2.join(process.cwd(), "history", "nerve-center-state.json");
218
278
  var LOCK_TIMEOUT_DEFAULT = 30 * 60 * 1e3;
279
+ var CIRCUIT_FAILURE_THRESHOLD = 5;
280
+ var CIRCUIT_COOLDOWN_MS = 6e4;
281
+ var CircuitOpenError = class extends Error {
282
+ constructor() {
283
+ super("Circuit breaker open \u2014 remote API temporarily unavailable, falling back to local");
284
+ this.name = "CircuitOpenError";
285
+ }
286
+ };
219
287
  var NerveCenter = class {
220
288
  mutex;
221
289
  state;
@@ -227,6 +295,8 @@ var NerveCenter = class {
227
295
  // Renamed backing field
228
296
  projectName;
229
297
  useSupabase;
298
+ _circuitFailures = 0;
299
+ _circuitOpenUntil = 0;
230
300
  /**
231
301
  * @param contextManager - Instance of ContextManager for legacy operations
232
302
  * @param options - Configuration options for state persistence and timeouts
@@ -335,40 +405,88 @@ var NerveCenter = class {
335
405
  logger.error("[callCoordination] Remote API not configured - apiUrl is:", this.contextManager.apiUrl);
336
406
  throw new Error("Remote API not configured");
337
407
  }
408
+ if (this._circuitFailures >= CIRCUIT_FAILURE_THRESHOLD && Date.now() < this._circuitOpenUntil) {
409
+ logger.warn(`[callCoordination] Circuit breaker OPEN \u2014 skipping remote call (resets at ${new Date(this._circuitOpenUntil).toISOString()})`);
410
+ throw new CircuitOpenError();
411
+ }
412
+ if (this._circuitFailures >= CIRCUIT_FAILURE_THRESHOLD && Date.now() >= this._circuitOpenUntil) {
413
+ logger.info("[callCoordination] Circuit breaker half-open \u2014 allowing probe request");
414
+ }
338
415
  const url = this.contextManager.apiUrl.endsWith("/v1") ? `${this.contextManager.apiUrl}/${endpoint}` : `${this.contextManager.apiUrl}/v1/${endpoint}`;
339
416
  logger.info(`[callCoordination] Full URL: ${method} ${url}`);
340
417
  logger.info(`[callCoordination] Request body: ${body ? JSON.stringify({ ...body, projectName: this.projectName }) : "none"}`);
341
- try {
342
- const response = await fetch(url, {
343
- method,
344
- headers: {
345
- "Content-Type": "application/json",
346
- "Authorization": `Bearer ${this.contextManager.apiSecret || ""}`
347
- },
348
- body: body ? JSON.stringify({ ...body, projectName: this.projectName }) : void 0
349
- });
350
- logger.info(`[callCoordination] Response status: ${response.status} ${response.statusText}`);
351
- if (!response.ok) {
352
- const text = await response.text();
353
- logger.error(`[callCoordination] API Error Response (${response.status}): ${text}`);
354
- if (response.status === 401) {
355
- throw new Error(`Authentication failed (401): ${text}. Check if API key is valid and exists in api_keys table.`);
356
- } else if (response.status === 500) {
357
- throw new Error(`Server error (500): ${text}. Check Vercel logs for details.`);
358
- } else {
359
- throw new Error(`API Error (${response.status}): ${text}`);
418
+ const maxRetries = 3;
419
+ const baseDelay = 1e3;
420
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
421
+ const controller = new AbortController();
422
+ const timeout = setTimeout(() => controller.abort(), 1e4);
423
+ try {
424
+ const response = await fetch(url, {
425
+ method,
426
+ headers: {
427
+ "Content-Type": "application/json",
428
+ "Authorization": `Bearer ${this.contextManager.apiSecret || ""}`
429
+ },
430
+ body: body ? JSON.stringify({ ...body, projectName: this.projectName }) : void 0,
431
+ signal: controller.signal
432
+ });
433
+ clearTimeout(timeout);
434
+ logger.info(`[callCoordination] Response status: ${response.status} ${response.statusText}`);
435
+ if (!response.ok) {
436
+ const text = await response.text();
437
+ logger.error(`[callCoordination] API Error Response (${response.status}): ${text}`);
438
+ if (response.status >= 400 && response.status < 500) {
439
+ if (response.status === 401) {
440
+ throw new Error(`Authentication failed (401): ${text}. Check if API key is valid and exists in api_keys table.`);
441
+ }
442
+ throw new Error(`API Error (${response.status}): ${text}`);
443
+ }
444
+ if (attempt < maxRetries) {
445
+ const delay = baseDelay * Math.pow(2, attempt - 1);
446
+ logger.warn(`[callCoordination] 5xx error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries})`);
447
+ await new Promise((r) => setTimeout(r, delay));
448
+ continue;
449
+ }
450
+ this._circuitFailures++;
451
+ if (this._circuitFailures >= CIRCUIT_FAILURE_THRESHOLD) {
452
+ this._circuitOpenUntil = Date.now() + CIRCUIT_COOLDOWN_MS;
453
+ logger.error(`[callCoordination] Circuit breaker OPENED after ${this._circuitFailures} consecutive failures`);
454
+ }
455
+ throw new Error(`Server error (${response.status}): ${text}. Check Vercel logs for details.`);
360
456
  }
457
+ if (this._circuitFailures > 0) {
458
+ logger.info(`[callCoordination] Request succeeded, resetting circuit breaker (was at ${this._circuitFailures} failures)`);
459
+ this._circuitFailures = 0;
460
+ this._circuitOpenUntil = 0;
461
+ }
462
+ const jsonResult = await response.json();
463
+ logger.info(`[callCoordination] Success - Response: ${JSON.stringify(jsonResult).substring(0, 200)}...`);
464
+ return jsonResult;
465
+ } catch (e) {
466
+ clearTimeout(timeout);
467
+ if (e instanceof CircuitOpenError) throw e;
468
+ if (e.message.includes("Authentication failed") || e.message.includes("API Error (4")) {
469
+ throw e;
470
+ }
471
+ if (attempt < maxRetries) {
472
+ const delay = baseDelay * Math.pow(2, attempt - 1);
473
+ logger.warn(`[callCoordination] Network/timeout error, retrying in ${delay}ms (attempt ${attempt}/${maxRetries}): ${e.message}`);
474
+ await new Promise((r) => setTimeout(r, delay));
475
+ continue;
476
+ }
477
+ this._circuitFailures++;
478
+ if (this._circuitFailures >= CIRCUIT_FAILURE_THRESHOLD) {
479
+ this._circuitOpenUntil = Date.now() + CIRCUIT_COOLDOWN_MS;
480
+ logger.error(`[callCoordination] Circuit breaker OPENED after ${this._circuitFailures} consecutive failures`);
481
+ }
482
+ logger.error(`[callCoordination] Fetch failed after ${maxRetries} attempts: ${e.message}`, e);
483
+ if (e.message.includes("401")) {
484
+ throw new Error(`API Authentication Error: ${e.message}. Verify AXIS_API_KEY in MCP config matches a key in the api_keys table.`);
485
+ }
486
+ throw e;
361
487
  }
362
- const jsonResult = await response.json();
363
- logger.info(`[callCoordination] Success - Response: ${JSON.stringify(jsonResult).substring(0, 200)}...`);
364
- return jsonResult;
365
- } catch (e) {
366
- logger.error(`[callCoordination] Fetch failed: ${e.message}`, e);
367
- if (e.message.includes("Authentication failed") || e.message.includes("401")) {
368
- throw new Error(`API Authentication Error: ${e.message}. Verify AXIS_API_KEY in MCP config matches a key in the api_keys table.`);
369
- }
370
- throw e;
371
488
  }
489
+ throw new Error("callCoordination: unexpected end of retry loop");
372
490
  }
373
491
  jobFromRecord(record) {
374
492
  return {
@@ -479,6 +597,7 @@ var NerveCenter = class {
479
597
  p_text: text
480
598
  });
481
599
  } catch (e) {
600
+ logger.warn("Notepad RPC append failed", e);
482
601
  }
483
602
  }
484
603
  if (this.contextManager.apiUrl) {
@@ -955,7 +1074,7 @@ var RagEngine = class {
955
1074
  }
956
1075
  async indexContent(filePath, content) {
957
1076
  if (!this.projectId) {
958
- console.error("RAG: Project ID missing.");
1077
+ logger.error("RAG: Project ID missing.");
959
1078
  return false;
960
1079
  }
961
1080
  try {
@@ -973,13 +1092,13 @@ var RagEngine = class {
973
1092
  metadata: { filePath }
974
1093
  });
975
1094
  if (error) {
976
- console.error("RAG Insert Error:", error);
1095
+ logger.error("RAG Insert Error:", error);
977
1096
  return false;
978
1097
  }
979
1098
  logger.info(`Indexed ${filePath}`);
980
1099
  return true;
981
1100
  } catch (e) {
982
- console.error("RAG Error:", e);
1101
+ logger.error("RAG Error:", e);
983
1102
  return false;
984
1103
  }
985
1104
  }
@@ -998,12 +1117,12 @@ var RagEngine = class {
998
1117
  p_project_id: this.projectId
999
1118
  });
1000
1119
  if (error || !data) {
1001
- console.error("RAG Search DB Error:", error);
1120
+ logger.error("RAG Search DB Error:", error);
1002
1121
  return [];
1003
1122
  }
1004
1123
  return data.map((d) => d.content);
1005
1124
  } catch (e) {
1006
- console.error("RAG Search Fail:", e);
1125
+ logger.error("RAG Search Fail:", e);
1007
1126
  return [];
1008
1127
  }
1009
1128
  }
@@ -1037,7 +1156,7 @@ if (process.env.SHARED_CONTEXT_API_URL || process.env.AXIS_API_KEY) {
1037
1156
  }
1038
1157
  if (!envLoaded) {
1039
1158
  logger.warn("No configuration found from MCP client (mcp.json) or .env.local");
1040
- logger.warn("MCP server will use default API URL: https://aicontext.vercel.app/api/v1");
1159
+ logger.warn("MCP server will use default API URL: https://useaxis.dev/api/v1");
1041
1160
  }
1042
1161
  }
1043
1162
  logger.info("=== Axis MCP Server Starting ===");
@@ -1049,7 +1168,7 @@ logger.info("Environment check:", {
1049
1168
  hasSUPABASE_SERVICE_ROLE_KEY: !!process.env.SUPABASE_SERVICE_ROLE_KEY,
1050
1169
  PROJECT_NAME: process.env.PROJECT_NAME || "default"
1051
1170
  });
1052
- var apiUrl = process.env.SHARED_CONTEXT_API_URL || process.env.AXIS_API_URL || "https://aicontext.vercel.app/api/v1";
1171
+ var apiUrl = process.env.SHARED_CONTEXT_API_URL || process.env.AXIS_API_URL || "https://useaxis.dev/api/v1";
1053
1172
  var apiSecret = process.env.AXIS_API_KEY || process.env.SHARED_CONTEXT_API_SECRET || process.env.AXIS_API_SECRET;
1054
1173
  var useRemoteApiOnly = !!process.env.SHARED_CONTEXT_API_URL || !!process.env.AXIS_API_KEY;
1055
1174
  if (useRemoteApiOnly) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@virsanghavi/axis-server",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "Axis MCP Server CLI",
5
5
  "main": "dist/index.js",
6
6
  "bin": {