@virsanghavi/axis-server 1.7.0 → 1.7.2
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.
|
@@ -51,7 +51,13 @@ Skip jobs ONLY for: single-line fixes, typos, config tweaks.
|
|
|
51
51
|
- Release locks IMMEDIATELY by completing jobs. Never hold a lock while doing unrelated work.
|
|
52
52
|
- `force_unlock` is a **last resort** — only for locks >25 min old from a crashed agent. Always give a reason.
|
|
53
53
|
|
|
54
|
+
### Releasing Locks (CRITICAL — do not skip)
|
|
55
|
+
**Every file you lock MUST be unlocked before your session ends.** Dangling locks block every other agent in the project.
|
|
56
|
+
- **Primary unlock method**: `complete_job` — releases all locks for that job.
|
|
57
|
+
- **Session end**: `finalize_session` — clears ALL remaining locks. Call this before you stop responding.
|
|
58
|
+
- **Self-check**: Before finishing, verify: "Have I completed all jobs and called `finalize_session`?" If not, do it now.
|
|
59
|
+
|
|
54
60
|
### Session Cleanup (MANDATORY)
|
|
55
|
-
- `complete_job` after EVERY finished task — do not accumulate incomplete jobs.
|
|
61
|
+
- `complete_job` after EVERY finished task — do not accumulate incomplete jobs. **This is how locks get released.**
|
|
56
62
|
- `update_shared_context` after meaningful steps — log decisions, not just actions.
|
|
57
|
-
- `finalize_session` when the user's request is fully complete — this is required, not optional.
|
|
63
|
+
- `finalize_session` when the user's request is fully complete — this is required, not optional. **This clears all remaining locks.**
|
package/dist/mcp-server.mjs
CHANGED
|
@@ -906,6 +906,16 @@ ${notepad}`;
|
|
|
906
906
|
} catch (e) {
|
|
907
907
|
if (e.message && e.message.includes("409")) {
|
|
908
908
|
logger.info(`[proposeFileAccess] Lock conflict (409)`);
|
|
909
|
+
let blockingAgent;
|
|
910
|
+
try {
|
|
911
|
+
const jsonMatch = e.message.match(/\{.*\}/s);
|
|
912
|
+
if (jsonMatch) {
|
|
913
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
914
|
+
blockingAgent = parsed.current_lock?.agent_id;
|
|
915
|
+
}
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
this.logLockEvent("BLOCKED", filePath, agentId, blockingAgent, intent);
|
|
909
919
|
return {
|
|
910
920
|
status: "REQUIRES_ORCHESTRATION",
|
|
911
921
|
message: `File '${filePath}' is locked by another agent`
|
|
@@ -1426,11 +1436,18 @@ async function searchFile(filePath, rootDir, keywords) {
|
|
|
1426
1436
|
const relativePath = path3.relative(rootDir, filePath);
|
|
1427
1437
|
const matchedKeywords = keywords.filter((kw) => contentLower.includes(kw));
|
|
1428
1438
|
if (matchedKeywords.length === 0) return null;
|
|
1439
|
+
const coverage = matchedKeywords.length / keywords.length;
|
|
1440
|
+
if (keywords.length >= 3 && coverage < 0.4) return null;
|
|
1441
|
+
if (keywords.length === 2 && matchedKeywords.length < 1) return null;
|
|
1429
1442
|
const lines = content.split("\n");
|
|
1430
|
-
let score = matchedKeywords.length;
|
|
1443
|
+
let score = coverage * coverage * matchedKeywords.length;
|
|
1431
1444
|
const relLower = relativePath.toLowerCase();
|
|
1445
|
+
let pathMatches = 0;
|
|
1432
1446
|
for (const kw of keywords) {
|
|
1433
|
-
if (relLower.includes(kw))
|
|
1447
|
+
if (relLower.includes(kw)) {
|
|
1448
|
+
score += 3;
|
|
1449
|
+
pathMatches++;
|
|
1450
|
+
}
|
|
1434
1451
|
}
|
|
1435
1452
|
const matchingLineIndices = [];
|
|
1436
1453
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -1439,6 +1456,22 @@ async function searchFile(filePath, rootDir, keywords) {
|
|
|
1439
1456
|
matchingLineIndices.push(i);
|
|
1440
1457
|
}
|
|
1441
1458
|
}
|
|
1459
|
+
let proximityBonus = 0;
|
|
1460
|
+
for (let i = 0; i < matchingLineIndices.length; i++) {
|
|
1461
|
+
const windowStart = matchingLineIndices[i];
|
|
1462
|
+
const windowEnd = windowStart + 10;
|
|
1463
|
+
const keywordsInWindow = /* @__PURE__ */ new Set();
|
|
1464
|
+
for (let j = i; j < matchingLineIndices.length && matchingLineIndices[j] <= windowEnd; j++) {
|
|
1465
|
+
const lineLower = lines[matchingLineIndices[j]].toLowerCase();
|
|
1466
|
+
for (const kw of matchedKeywords) {
|
|
1467
|
+
if (lineLower.includes(kw)) keywordsInWindow.add(kw);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
if (keywordsInWindow.size >= 2) {
|
|
1471
|
+
proximityBonus = Math.max(proximityBonus, keywordsInWindow.size * 1.5);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
score += proximityBonus;
|
|
1442
1475
|
score += Math.min(matchingLineIndices.length, 20) * 0.1;
|
|
1443
1476
|
const regions = [];
|
|
1444
1477
|
let lastEnd = -1;
|
|
@@ -1762,10 +1795,16 @@ Agents MUST execute the full Axis workflow without being told:
|
|
|
1762
1795
|
Every non-trivial task MUST follow: post_job \u2192 claim_next_job \u2192 propose_file_access \u2192 (edit) \u2192 complete_job.
|
|
1763
1796
|
Skip ONLY for single-line typo fixes.
|
|
1764
1797
|
|
|
1798
|
+
### Releasing Locks (CRITICAL)
|
|
1799
|
+
Every file you lock MUST be unlocked before your session ends. Dangling locks block all other agents.
|
|
1800
|
+
- complete_job releases locks for that job. Call it IMMEDIATELY after each task.
|
|
1801
|
+
- finalize_session clears ALL remaining locks. Call it before you stop responding.
|
|
1802
|
+
- NEVER end a session while holding locks. Self-check: "Did I call finalize_session?"
|
|
1803
|
+
|
|
1765
1804
|
### Session Cleanup (MANDATORY)
|
|
1766
|
-
- complete_job IMMEDIATELY after finishing each task.
|
|
1805
|
+
- complete_job IMMEDIATELY after finishing each task \u2014 this is how locks get released.
|
|
1767
1806
|
- update_shared_context after meaningful steps.
|
|
1768
|
-
- finalize_session when the user's request is fully complete \u2014 do not wait to be told.
|
|
1807
|
+
- finalize_session when the user's request is fully complete \u2014 do not wait to be told. This clears all remaining locks.
|
|
1769
1808
|
|
|
1770
1809
|
### Force-Unlock Policy
|
|
1771
1810
|
force_unlock is a LAST RESORT \u2014 only for locks >25 min old from a crashed agent. Always give a reason.
|
|
@@ -1922,7 +1961,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1922
1961
|
// --- Decision & Orchestration ---
|
|
1923
1962
|
{
|
|
1924
1963
|
name: "propose_file_access",
|
|
1925
|
-
description: "**CRITICAL: REQUEST FILE LOCK** \u2014 call this before EVERY file edit, no exceptions.\n- Checks if another agent currently holds a lock.\n- Returns `GRANTED` if safe to proceed, or `REQUIRES_ORCHESTRATION` if someone else is editing.\n- Usage: Provide your `agentId` (e.g., 'cursor-agent'), `filePath` (absolute), and `intent` (descriptive \u2014 e.g. 'Refactor auth to use JWT', NOT 'editing file').\n- Locks expire after 30 minutes. Use `force_unlock` only as a last resort for crashed agents.",
|
|
1964
|
+
description: "**CRITICAL: REQUEST FILE LOCK** \u2014 call this before EVERY file edit, no exceptions.\n- Checks if another agent currently holds a lock.\n- Returns `GRANTED` if safe to proceed, or `REQUIRES_ORCHESTRATION` if someone else is editing.\n- Usage: Provide your `agentId` (e.g., 'cursor-agent'), `filePath` (absolute), and `intent` (descriptive \u2014 e.g. 'Refactor auth to use JWT', NOT 'editing file').\n- Locks expire after 30 minutes. Use `force_unlock` only as a last resort for crashed agents.\n- **IMPORTANT**: Every lock you acquire MUST be released. Call `complete_job` when done with each task, and `finalize_session` before ending your session. Dangling locks block all other agents.",
|
|
1926
1965
|
inputSchema: {
|
|
1927
1966
|
type: "object",
|
|
1928
1967
|
properties: {
|
|
@@ -1949,7 +1988,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
1949
1988
|
// --- Permanent Memory ---
|
|
1950
1989
|
{
|
|
1951
1990
|
name: "finalize_session",
|
|
1952
|
-
description: "**MANDATORY SESSION CLEANUP** \u2014 call this automatically when the user's request is fully complete.\n- Archives the current Live Notepad to a permanent session log.\n- Clears
|
|
1991
|
+
description: "**MANDATORY SESSION CLEANUP** \u2014 call this automatically when the user's request is fully complete.\n- Archives the current Live Notepad to a permanent session log.\n- **Clears ALL active file locks** and completed jobs. This is your safety net to ensure no dangling locks.\n- Resets the Live Notepad for the next session.\n- Do NOT wait for the user to say 'we are done.' When all tasks are finished, call this yourself.\n- **CRITICAL**: You MUST call this before ending ANY session. Failing to do so leaves file locks that block all other agents.",
|
|
1953
1992
|
inputSchema: { type: "object", properties: {}, required: [] }
|
|
1954
1993
|
},
|
|
1955
1994
|
{
|
|
@@ -2009,7 +2048,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2009
2048
|
},
|
|
2010
2049
|
{
|
|
2011
2050
|
name: "complete_job",
|
|
2012
|
-
description: "**CLOSE TICKET**: Mark a job as done and release file locks.\n- Call this IMMEDIATELY after finishing each job \u2014 do not accumulate completed-but-unclosed jobs.\n- Requires `outcome` (what was done).\n- If you are not the assigned agent, you must provide the `completionKey`.\n- Leaving jobs open holds locks and blocks other agents.",
|
|
2051
|
+
description: "**CLOSE TICKET**: Mark a job as done and release file locks.\n- Call this IMMEDIATELY after finishing each job \u2014 do not accumulate completed-but-unclosed jobs.\n- Requires `outcome` (what was done).\n- If you are not the assigned agent, you must provide the `completionKey`.\n- **This is the primary way to release file locks.** Leaving jobs open holds locks and blocks other agents.\n- REMINDER: After completing all jobs, you MUST also call `finalize_session` to clear any remaining locks.",
|
|
2013
2052
|
inputSchema: {
|
|
2014
2053
|
type: "object",
|
|
2015
2054
|
properties: {
|