archgraph-argo 0.4.1 → 0.5.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.
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
} = require('./repositoryArgoEnvironment.js');
|
|
17
17
|
const {
|
|
18
18
|
getWorkspaceRoot,
|
|
19
|
+
hasStaticWorkspace,
|
|
20
|
+
setMcpWorkspaceRoots,
|
|
19
21
|
} = require('./argo-paths.js');
|
|
20
22
|
const canonicalSemanticInitStorage = new AsyncLocalStorage();
|
|
21
23
|
|
|
@@ -503,6 +505,59 @@ function send(message) {
|
|
|
503
505
|
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
504
506
|
}
|
|
505
507
|
|
|
508
|
+
let rootRequestSeq = 0;
|
|
509
|
+
let rootRequestInFlight = false;
|
|
510
|
+
let rootRequestTimer = null;
|
|
511
|
+
let rootsSettled = false;
|
|
512
|
+
const pendingRootRequests = new Map();
|
|
513
|
+
const deferredToolCalls = [];
|
|
514
|
+
|
|
515
|
+
function flushDeferredToolCalls() {
|
|
516
|
+
const pending = deferredToolCalls.splice(0);
|
|
517
|
+
for (const request of pending) {
|
|
518
|
+
void (async () => {
|
|
519
|
+
const response = await handleRequest(request);
|
|
520
|
+
if (response) {
|
|
521
|
+
send(response);
|
|
522
|
+
}
|
|
523
|
+
})();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function settleRoots() {
|
|
528
|
+
if (rootsSettled) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
rootsSettled = true;
|
|
532
|
+
if (rootRequestTimer) {
|
|
533
|
+
clearTimeout(rootRequestTimer);
|
|
534
|
+
rootRequestTimer = null;
|
|
535
|
+
}
|
|
536
|
+
rootRequestInFlight = false;
|
|
537
|
+
pendingRootRequests.clear();
|
|
538
|
+
flushDeferredToolCalls();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function requestRoots() {
|
|
542
|
+
if (rootRequestInFlight || rootsSettled) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
rootRequestInFlight = true;
|
|
546
|
+
const id = `argo-roots-${++rootRequestSeq}`;
|
|
547
|
+
rootRequestTimer = setTimeout(() => {
|
|
548
|
+
rootRequestTimer = null;
|
|
549
|
+
rootRequestInFlight = false;
|
|
550
|
+
settleRoots();
|
|
551
|
+
}, 8000);
|
|
552
|
+
pendingRootRequests.set(id, (result) => {
|
|
553
|
+
if (result && Array.isArray(result.roots)) {
|
|
554
|
+
setMcpWorkspaceRoots(result.roots);
|
|
555
|
+
}
|
|
556
|
+
settleRoots();
|
|
557
|
+
});
|
|
558
|
+
send({ jsonrpc: '2.0', id, method: 'roots/list', params: {} });
|
|
559
|
+
}
|
|
560
|
+
|
|
506
561
|
async function handleRequest(request, dependencies = undefined) {
|
|
507
562
|
const { id, method, params } = request;
|
|
508
563
|
|
|
@@ -512,7 +567,7 @@ async function handleRequest(request, dependencies = undefined) {
|
|
|
512
567
|
id,
|
|
513
568
|
result: {
|
|
514
569
|
protocolVersion: '2024-11-05',
|
|
515
|
-
capabilities: { tools: {} },
|
|
570
|
+
capabilities: { tools: {}, roots: { listChanged: true } },
|
|
516
571
|
serverInfo: {
|
|
517
572
|
name: 'argo',
|
|
518
573
|
version: '1.0.0',
|
|
@@ -525,6 +580,14 @@ async function handleRequest(request, dependencies = undefined) {
|
|
|
525
580
|
return null;
|
|
526
581
|
}
|
|
527
582
|
|
|
583
|
+
if (method === 'notifications/roots/list_changed') {
|
|
584
|
+
setMcpWorkspaceRoots(params && params.roots);
|
|
585
|
+
if (params && Array.isArray(params.roots) && params.roots.length > 0) {
|
|
586
|
+
settleRoots();
|
|
587
|
+
}
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
|
|
528
591
|
if (method === 'tools/list') {
|
|
529
592
|
// Deduplicate tools by name — last writer wins.
|
|
530
593
|
// Priority order: validatorMcp > systemArchitectureMcp > local TOOLS.
|
|
@@ -606,10 +669,32 @@ async function main() {
|
|
|
606
669
|
} catch {
|
|
607
670
|
continue;
|
|
608
671
|
}
|
|
672
|
+
|
|
673
|
+
// A JSON-RPC message without a `method` is a response to a server-sent request.
|
|
674
|
+
if (typeof request.method === 'undefined' && request.id !== undefined) {
|
|
675
|
+
const resolver = pendingRootRequests.get(request.id);
|
|
676
|
+
if (resolver) {
|
|
677
|
+
pendingRootRequests.delete(request.id);
|
|
678
|
+
resolver(request.result);
|
|
679
|
+
}
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Workspace-dependent tool calls must wait for roots so the global server
|
|
684
|
+
// targets the current workspace instead of the home directory.
|
|
685
|
+
if (request.method === 'tools/call' && !hasStaticWorkspace() && !rootsSettled) {
|
|
686
|
+
deferredToolCalls.push(request);
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
609
690
|
const response = await handleRequest(request);
|
|
610
691
|
if (response) {
|
|
611
692
|
send(response);
|
|
612
693
|
}
|
|
694
|
+
if ((request.method === 'initialize' || request.method === 'notifications/initialized')
|
|
695
|
+
&& !hasStaticWorkspace()) {
|
|
696
|
+
requestRoots();
|
|
697
|
+
}
|
|
613
698
|
}
|
|
614
699
|
}
|
|
615
700
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('node:fs');
|
|
2
2
|
const path = require('node:path');
|
|
3
|
+
const { fileURLToPath } = require('node:url');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Shared path resolution for the Argo toolchain.
|
|
@@ -28,12 +29,43 @@ function getArgoRoot() {
|
|
|
28
29
|
return path.resolve(__dirname, '..');
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
let mcpWorkspaceRoots = [];
|
|
33
|
+
|
|
34
|
+
function setMcpWorkspaceRoots(roots) {
|
|
35
|
+
mcpWorkspaceRoots = Array.isArray(roots) ? roots : [];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function rootToPath(root) {
|
|
39
|
+
if (!root) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const uri = typeof root === 'string' ? root : root.uri;
|
|
43
|
+
if (typeof uri !== 'string' || uri.trim() === '') {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (uri.startsWith('file://')) {
|
|
47
|
+
try {
|
|
48
|
+
return fileURLToPath(uri);
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return uri;
|
|
54
|
+
}
|
|
55
|
+
|
|
31
56
|
function getWorkspaceRoot() {
|
|
32
57
|
const explicit = process.env.ARGO_REPO_ROOT || process.env.WORKSPACE_FOLDER;
|
|
33
58
|
if (explicit && String(explicit).trim() !== '') {
|
|
34
59
|
return path.resolve(explicit);
|
|
35
60
|
}
|
|
36
61
|
|
|
62
|
+
for (const root of mcpWorkspaceRoots) {
|
|
63
|
+
const rootPath = rootToPath(root);
|
|
64
|
+
if (rootPath) {
|
|
65
|
+
return path.resolve(rootPath);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
37
69
|
const embedded = path.resolve(getArgoRoot(), '..');
|
|
38
70
|
if (fs.existsSync(path.join(embedded, 'design', 'KG', 'SystemArchitecture.json'))) {
|
|
39
71
|
return embedded;
|
|
@@ -42,6 +74,15 @@ function getWorkspaceRoot() {
|
|
|
42
74
|
return path.resolve(process.cwd());
|
|
43
75
|
}
|
|
44
76
|
|
|
77
|
+
function hasStaticWorkspace() {
|
|
78
|
+
const explicit = process.env.ARGO_REPO_ROOT || process.env.WORKSPACE_FOLDER;
|
|
79
|
+
if (explicit && String(explicit).trim() !== '') {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const embedded = path.resolve(getArgoRoot(), '..');
|
|
83
|
+
return fs.existsSync(path.join(embedded, 'design', 'KG', 'SystemArchitecture.json'));
|
|
84
|
+
}
|
|
85
|
+
|
|
45
86
|
function resolveArgoPath(...segments) {
|
|
46
87
|
return path.resolve(getArgoRoot(), ...segments);
|
|
47
88
|
}
|
|
@@ -71,7 +112,9 @@ module.exports = {
|
|
|
71
112
|
getArgoRoot,
|
|
72
113
|
getArgoEnvPath,
|
|
73
114
|
getWorkspaceRoot,
|
|
115
|
+
hasStaticWorkspace,
|
|
74
116
|
normalizeRelativePath,
|
|
75
117
|
resolveArgoPath,
|
|
76
118
|
resolveWorkspacePath,
|
|
119
|
+
setMcpWorkspaceRoots,
|
|
77
120
|
};
|
package/package.json
CHANGED