archgraph-argo 0.1.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.
- package/LICENSE +201 -0
- package/README.md +115 -0
- package/argo/package.json +8 -0
- package/argo/rules/intent-architecture-global-rule.md +45 -0
- package/argo/schema/ImplementationToCodingHandoff.schema.json +252 -0
- package/argo/schema/ImplementationToIntentTraceProposal.schema.json +180 -0
- package/argo/schema/IntentToImplementationHandoff.schema.json +75 -0
- package/argo/schema/SystemArchitecture.schema.json +378 -0
- package/argo/schema/archimate3.2.pdf +0 -0
- package/argo/scripts/ARCHITECTURE.md +57 -0
- package/argo/scripts/archimate32-rules.js +12301 -0
- package/argo/scripts/argo-mcp-server.js +629 -0
- package/argo/scripts/argo-paths.js +77 -0
- package/argo/scripts/ensureArgoHarnessEnvironment.js +340 -0
- package/argo/scripts/generateArchitectureDiffPlantuml.js +466 -0
- package/argo/scripts/graph-rag/ARCHITECTURE.md +192 -0
- package/argo/scripts/graph-rag/canonicalProjectionAuthority.js +45 -0
- package/argo/scripts/graph-rag/defaultSemanticRetrieval.js +969 -0
- package/argo/scripts/graph-rag/embeddingQualificationGate.js +59 -0
- package/argo/scripts/graph-rag/externalProductionConfig.js +74 -0
- package/argo/scripts/graph-rag/liveEmbeddingIndexGate.js +129 -0
- package/argo/scripts/graph-rag/liveEmbeddingNeo4jBoundary.js +137 -0
- package/argo/scripts/graph-rag/liveEmbeddingProviderClient.js +49 -0
- package/argo/scripts/graph-rag/liveEmbeddingProviderConfig.js +481 -0
- package/argo/scripts/graph-rag/mutationEmbeddingVectorLifecycle.js +1261 -0
- package/argo/scripts/graph-rag/neo4jNativeRetrieval.js +37 -0
- package/argo/scripts/graph-rag/productionGraphRagRuntime.js +1624 -0
- package/argo/scripts/graph-rag/semantic-persistence/ARCHITECTURE.md +51 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticBackfill.js +241 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticCheckpointStore.js +99 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticNeo4jAdapter.js +149 -0
- package/argo/scripts/graph-rag/semantic-persistence/productionSemanticProjectionStore.js +171 -0
- package/argo/scripts/graph-rag/semanticOperatorError.js +38 -0
- package/argo/scripts/graph-rag/semanticOperatorJourney.js +459 -0
- package/argo/scripts/graph-rag/semanticReadinessAttestationStore.js +398 -0
- package/argo/scripts/graph-rag/systemMetadataCommandAdapter.js +269 -0
- package/argo/scripts/graph-semantics.js +220 -0
- package/argo/scripts/neo4j-system-architecture-store.js +777 -0
- package/argo/scripts/repositoryArgoEnvironment.js +101 -0
- package/argo/scripts/runArchitectureTests.js +583 -0
- package/argo/scripts/semanticOperatorJourneyCli.js +91 -0
- package/argo/scripts/syncSystemArchitectureToNeo4j.js +67 -0
- package/argo/scripts/systemarchitecture-mcp-server.js +2965 -0
- package/argo/scripts/test-executors/_template.js +58 -0
- package/argo/scripts/test-executors/default.js +199 -0
- package/argo/scripts/validateStageHandoff.js +459 -0
- package/argo/scripts/validateSystemArchitecture.js +254 -0
- package/argo/scripts/validateTraceProposal.js +181 -0
- package/argo/scripts/validator-mcp-server.js +377 -0
- package/argo/skills/argo-init/SKILL.md +110 -0
- package/bin/argo-deploy.js +12 -0
- package/install-argo.ps1 +112 -0
- package/package.json +28 -0
- package/vendor/neo4j-driver-6.2.0.tgz +0 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const readline = require('node:readline');
|
|
4
|
+
const { AsyncLocalStorage } = require('node:async_hooks');
|
|
5
|
+
|
|
6
|
+
const validatorMcp = require('./validator-mcp-server.js');
|
|
7
|
+
const systemArchitectureMcp = require('./systemarchitecture-mcp-server.js');
|
|
8
|
+
const {
|
|
9
|
+
semanticOperatorErrorResult,
|
|
10
|
+
} = require('./graph-rag/semanticOperatorError.js');
|
|
11
|
+
const {
|
|
12
|
+
runCanonicalSemanticInit,
|
|
13
|
+
} = require('./graph-rag/semanticOperatorJourney.js');
|
|
14
|
+
const {
|
|
15
|
+
loadRepositoryArgoEnvironment,
|
|
16
|
+
} = require('./repositoryArgoEnvironment.js');
|
|
17
|
+
const {
|
|
18
|
+
getWorkspaceRoot,
|
|
19
|
+
} = require('./argo-paths.js');
|
|
20
|
+
const canonicalSemanticInitStorage = new AsyncLocalStorage();
|
|
21
|
+
|
|
22
|
+
const HANDOFF_FILES_TO_RESET = [
|
|
23
|
+
['.argo', 'temp', 'IntentToImplementationHandoff.json'],
|
|
24
|
+
['.argo', 'temp', 'ImplementationToCodingHandoff.json'],
|
|
25
|
+
];
|
|
26
|
+
const EA_TEMPLATE_PATH_CANDIDATES = [
|
|
27
|
+
['.opencode', 'customtools', 'EA-model-template.feap'],
|
|
28
|
+
['.opencode', 'EA-model-template.feap'],
|
|
29
|
+
['eatool', 'EA-model-template.feap'],
|
|
30
|
+
['EA-model-template.feap'],
|
|
31
|
+
['Argo.feap'],
|
|
32
|
+
];
|
|
33
|
+
const WINDOWS_RESERVED_NAMES = new Set([
|
|
34
|
+
'CON', 'PRN', 'AUX', 'NUL',
|
|
35
|
+
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
|
|
36
|
+
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9',
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const VALIDATOR_TOOL_NAMES = new Set([
|
|
40
|
+
'validateSystemArchitecture',
|
|
41
|
+
'validateStageHandoff',
|
|
42
|
+
'validateTraceProposal',
|
|
43
|
+
'runArchitectureTests',
|
|
44
|
+
]);
|
|
45
|
+
const SYSTEM_ARCHITECTURE_TOOL_NAMES = new Set([
|
|
46
|
+
'getSystemArchitecture',
|
|
47
|
+
'getIntentElementContext',
|
|
48
|
+
'previewSystemArchitectureMutation',
|
|
49
|
+
'applySystemArchitectureMutation',
|
|
50
|
+
'addArchitectureElement',
|
|
51
|
+
'updateArchitectureElement',
|
|
52
|
+
'removeArchitectureElement',
|
|
53
|
+
'addArchitectureRelationship',
|
|
54
|
+
'updateArchitectureRelationship',
|
|
55
|
+
'removeArchitectureRelationship',
|
|
56
|
+
'addArchitectureView',
|
|
57
|
+
'updateArchitectureView',
|
|
58
|
+
'removeArchitectureView',
|
|
59
|
+
'generateArchitectureDiffPlantuml',
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const TOOLS = [
|
|
63
|
+
{
|
|
64
|
+
name: 'initializeWorkspace',
|
|
65
|
+
description: 'Bootstrap an Argo workspace by copying the EA template target and resetting stage handoff artifacts.',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {},
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'validateStageHandoff',
|
|
74
|
+
description: 'Validate Argo stage handoff JSON. Use stage intent-to-implementation or implementation-to-coding, or omit to validate all supported stages.',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
stage: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
enum: ['intent-to-implementation', 'implementation-to-coding'],
|
|
81
|
+
description: 'Optional handoff stage to validate.',
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
additionalProperties: false,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'validateTraceProposal',
|
|
89
|
+
description: 'Validate ImplementationToIntentTraceProposal JSON against .argo/schema/ImplementationToIntentTraceProposal.schema.json and repository path references.',
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
proposalPath: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'Optional proposal path relative to workspace root. Default: design/KG/ImplementationToIntentTraceProposal.json',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
additionalProperties: false,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'runArchitectureTests',
|
|
103
|
+
description: 'Execute explicit architecture testcases from the intent graph and refresh design/KG/test-failure-records.json. This MCP call can exceed client timeouts; if it times out, run the same test runner directly with: node .argo/scripts/runArchitectureTests.js',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
architecturePath: {
|
|
108
|
+
type: 'string',
|
|
109
|
+
description: 'Optional architecture graph path relative to workspace root. Default: design/KG/SystemArchitecture.json',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'generateArchitectureDiffPlantuml',
|
|
117
|
+
description: 'Generate a timestamped PlantUML Markdown tree for current git diff changes in SystemArchitecture.json. The tool compares HEAD and working tree, extracts changed elements/relationships, and writes to .argo/temp/architecture_analysis/.',
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
architecturePath: {
|
|
122
|
+
type: 'string',
|
|
123
|
+
description: 'Optional architecture graph path relative to workspace root. Default: design/KG/SystemArchitecture.json',
|
|
124
|
+
},
|
|
125
|
+
outputDir: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Optional output directory relative to workspace root. Default: .argo/temp/architecture_analysis',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
additionalProperties: false,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'getSystemArchitecture',
|
|
135
|
+
description: 'Start here, but prefer an explicit semantic query instead of an omitted-query full graph read. Provide query.purpose and query.intent to get a compact business/architecture result, then use returned element ids with getIntentElementContext for focused dependency context. Omit query only when an exact full canonical snapshot is explicitly required.',
|
|
136
|
+
inputSchema: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
140
|
+
query: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
description: 'Preferred for ordinary agent reading. Use semantic query instead of full graph reads; combine the returned element ids with getIntentElementContext when deeper local context is needed.',
|
|
143
|
+
properties: {
|
|
144
|
+
purpose: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
enum: ['intent-decision', 'implementation-design', 'coding-repair', 'audit', 'graph-tidy'],
|
|
147
|
+
description: 'Declared reading purpose. Use intent-decision, implementation-design, coding-repair, or audit for semantic retrieval; graph-tidy intentionally bypasses semantic retrieval and may return a full snapshot.',
|
|
148
|
+
},
|
|
149
|
+
intent: { type: 'string', description: 'Natural-language intent for semantic retrieval, for example "summarize business features for high-risk audit".' },
|
|
150
|
+
subject: { type: 'string', description: 'Required for audit; optional anchor/focus id for other semantic purposes.' },
|
|
151
|
+
},
|
|
152
|
+
additionalProperties: true,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
additionalProperties: false,
|
|
156
|
+
},
|
|
157
|
+
outputSchema: systemArchitectureMcp.GET_SYSTEM_ARCHITECTURE_OUTPUT_SCHEMA,
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'getIntentElementContext',
|
|
161
|
+
description: 'read-only query that returns an intent subgraph context for one element. Uses ArchiMate semantic dependency traversal with dependencyDepth and dependentDepth, preserving native subgraph elements, relationships, and views.',
|
|
162
|
+
inputSchema: intentElementContextInputSchema(),
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'previewSystemArchitectureMutation',
|
|
166
|
+
description: 'Use before apply for complex or risky changes. Performs a dry-run of one or more mutations, runs schema, graph, view, and ArchiMate 3.2 validation, and does not write the graph.',
|
|
167
|
+
inputSchema: mutationInputSchema(),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'applySystemArchitectureMutation',
|
|
171
|
+
description: 'Use for multi-step or dependent graph changes that should be validated and written atomically. Prefer focused tools for a single simple add, update, or remove operation.',
|
|
172
|
+
inputSchema: mutationInputSchema(),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'addArchitectureElement',
|
|
176
|
+
description: 'Use for one element. Creates a new element or adds an existing element to view_ids. view_ids is required so elements never exist outside views.',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
required: ['element', 'view_ids'],
|
|
180
|
+
properties: {
|
|
181
|
+
element: { type: 'object' },
|
|
182
|
+
view_ids: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
183
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
184
|
+
},
|
|
185
|
+
additionalProperties: false,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'updateArchitectureElement',
|
|
190
|
+
description: 'Use for one global element metadata patch. Does not change view membership. Element id and type are immutable; remove and re-add to change them.',
|
|
191
|
+
inputSchema: {
|
|
192
|
+
type: 'object',
|
|
193
|
+
required: ['id', 'patch'],
|
|
194
|
+
properties: {
|
|
195
|
+
id: { type: 'string' },
|
|
196
|
+
patch: { type: 'object' },
|
|
197
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
198
|
+
},
|
|
199
|
+
additionalProperties: false,
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'removeArchitectureElement',
|
|
204
|
+
description: 'Use for one element removal. With view_ids, removes only from those views and cascades related relationships in the same views; without view_ids, removes from all views and the graph.',
|
|
205
|
+
inputSchema: {
|
|
206
|
+
type: 'object',
|
|
207
|
+
required: ['id'],
|
|
208
|
+
properties: {
|
|
209
|
+
id: { type: 'string' },
|
|
210
|
+
view_ids: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
211
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
212
|
+
},
|
|
213
|
+
additionalProperties: false,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: 'addArchitectureRelationship',
|
|
218
|
+
description: 'Use for one relationship. Creates a new relationship or adds an existing relationship to view_ids. relationship.type is the ArchiMate 3.2 relationship type and is validated against endpoint element types.',
|
|
219
|
+
inputSchema: {
|
|
220
|
+
type: 'object',
|
|
221
|
+
required: ['relationship', 'view_ids'],
|
|
222
|
+
properties: {
|
|
223
|
+
relationship: { type: 'object' },
|
|
224
|
+
view_ids: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
225
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
226
|
+
},
|
|
227
|
+
additionalProperties: false,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'updateArchitectureRelationship',
|
|
232
|
+
description: 'Use for one global relationship metadata patch, such as name, statement, source_name, or target_name. Relationship id and type are immutable; remove and re-add to change them.',
|
|
233
|
+
inputSchema: {
|
|
234
|
+
type: 'object',
|
|
235
|
+
required: ['id', 'patch'],
|
|
236
|
+
properties: {
|
|
237
|
+
id: { type: 'string' },
|
|
238
|
+
patch: { type: 'object' },
|
|
239
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
240
|
+
},
|
|
241
|
+
additionalProperties: false,
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'removeArchitectureRelationship',
|
|
246
|
+
description: 'Use for one relationship removal. With view_ids, removes only from those views; without view_ids, removes from all views and deletes it from the graph.',
|
|
247
|
+
inputSchema: {
|
|
248
|
+
type: 'object',
|
|
249
|
+
required: ['id'],
|
|
250
|
+
properties: {
|
|
251
|
+
id: { type: 'string' },
|
|
252
|
+
view_ids: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
253
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
254
|
+
},
|
|
255
|
+
additionalProperties: false,
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'addArchitectureView',
|
|
260
|
+
description: 'Use for one view. The graph must have exactly one top-level view named SystemArchitecture; all sub-views must attach to an element with parent_element_id.',
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: 'object',
|
|
263
|
+
required: ['view'],
|
|
264
|
+
properties: {
|
|
265
|
+
view: { type: 'object' },
|
|
266
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
267
|
+
},
|
|
268
|
+
additionalProperties: false,
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'updateArchitectureView',
|
|
273
|
+
description: 'Use for one view metadata or membership patch. Keep the one top-level view named SystemArchitecture and attach sub-views to parent elements.',
|
|
274
|
+
inputSchema: {
|
|
275
|
+
type: 'object',
|
|
276
|
+
required: ['view_id', 'patch'],
|
|
277
|
+
properties: {
|
|
278
|
+
view_id: { type: 'string' },
|
|
279
|
+
patch: { type: 'object' },
|
|
280
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
281
|
+
},
|
|
282
|
+
additionalProperties: false,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: 'removeArchitectureView',
|
|
287
|
+
description: 'Use for one view removal. After removal, every remaining element and relationship must still belong to at least one view.',
|
|
288
|
+
inputSchema: {
|
|
289
|
+
type: 'object',
|
|
290
|
+
required: ['view_id'],
|
|
291
|
+
properties: {
|
|
292
|
+
view_id: { type: 'string' },
|
|
293
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
294
|
+
},
|
|
295
|
+
additionalProperties: false,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
function intentElementContextInputSchema() {
|
|
301
|
+
return {
|
|
302
|
+
type: 'object',
|
|
303
|
+
properties: {
|
|
304
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
305
|
+
elementId: { type: 'string' },
|
|
306
|
+
elementName: { type: 'string' },
|
|
307
|
+
profile: {
|
|
308
|
+
type: 'string',
|
|
309
|
+
enum: ['implementation-design', 'coding-repair', 'audit', 'generic-agent'],
|
|
310
|
+
description: 'Default: generic-agent. Affects workContext enrichment only; subgraph shape stays native.',
|
|
311
|
+
},
|
|
312
|
+
dependencyDepth: { type: 'number', description: 'Default: 2. Semantic dependencies needed by the focus element.' },
|
|
313
|
+
dependentDepth: { type: 'number', description: 'Default: 1. Semantic dependents that rely on the focus element.' },
|
|
314
|
+
associationDepth: { type: 'number', description: 'Default: 1. Association neighbors are expanded at least one layer.' },
|
|
315
|
+
associationNeighborDependencyDepth: { type: 'number', description: 'Default: 0. Optional dependency expansion from association neighbors.' },
|
|
316
|
+
},
|
|
317
|
+
additionalProperties: false,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function mutationInputSchema() {
|
|
322
|
+
return {
|
|
323
|
+
type: 'object',
|
|
324
|
+
required: ['mutations'],
|
|
325
|
+
properties: {
|
|
326
|
+
architecturePath: { type: 'string', description: 'Default: design/KG/SystemArchitecture.json' },
|
|
327
|
+
mutations: {
|
|
328
|
+
type: 'array',
|
|
329
|
+
minItems: 1,
|
|
330
|
+
items: {
|
|
331
|
+
type: 'object',
|
|
332
|
+
required: ['type'],
|
|
333
|
+
properties: {
|
|
334
|
+
type: {
|
|
335
|
+
type: 'string',
|
|
336
|
+
enum: [
|
|
337
|
+
'addElement',
|
|
338
|
+
'updateElement',
|
|
339
|
+
'removeElement',
|
|
340
|
+
'addRelationship',
|
|
341
|
+
'updateRelationship',
|
|
342
|
+
'removeRelationship',
|
|
343
|
+
'addView',
|
|
344
|
+
'updateView',
|
|
345
|
+
'removeView',
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
element: { type: 'object' },
|
|
349
|
+
relationship: { type: 'object' },
|
|
350
|
+
view: { type: 'object' },
|
|
351
|
+
id: { type: 'string' },
|
|
352
|
+
patch: { type: 'object' },
|
|
353
|
+
view_id: { type: 'string' },
|
|
354
|
+
view_ids: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
355
|
+
element_ids: { type: 'array', items: { type: 'string' } },
|
|
356
|
+
relationship_ids: { type: 'array', items: { type: 'string' } },
|
|
357
|
+
},
|
|
358
|
+
additionalProperties: false,
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
additionalProperties: false,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function resolveWorkspaceRoot() {
|
|
367
|
+
return getWorkspaceRoot();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function callTool(name, args = {}, progressToken = null, dependencies = undefined) {
|
|
371
|
+
loadRepositoryArgoEnvironment(resolveWorkspaceRoot());
|
|
372
|
+
if (name === 'initializeWorkspace') {
|
|
373
|
+
const workspace = await initializeWorkspace(resolveWorkspaceRoot());
|
|
374
|
+
const composition = canonicalSemanticInitStorage.getStore()
|
|
375
|
+
|| systemArchitectureMcp.createDefaultCanonicalSemanticInitComposition();
|
|
376
|
+
const semanticLifecycle = await runCanonicalSemanticInit(composition, {
|
|
377
|
+
repositoryRoot: resolveWorkspaceRoot(),
|
|
378
|
+
workspace,
|
|
379
|
+
});
|
|
380
|
+
return toolResult({
|
|
381
|
+
...workspace,
|
|
382
|
+
semanticState: semanticLifecycle.state,
|
|
383
|
+
semanticLifecycle,
|
|
384
|
+
alignment: semanticLifecycle.alignment,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (VALIDATOR_TOOL_NAMES.has(name)) {
|
|
388
|
+
return validatorMcp.callTool(name, args, progressToken);
|
|
389
|
+
}
|
|
390
|
+
if (SYSTEM_ARCHITECTURE_TOOL_NAMES.has(name)) {
|
|
391
|
+
return systemArchitectureMcp.callTool(name, args, dependencies);
|
|
392
|
+
}
|
|
393
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function withCanonicalSemanticInitTestComposition(composition, callback) {
|
|
397
|
+
if (!composition || typeof callback !== 'function') {
|
|
398
|
+
throw new TypeError('Canonical semantic init composition and callback are required');
|
|
399
|
+
}
|
|
400
|
+
return canonicalSemanticInitStorage.run(Object.freeze({ ...composition }), callback);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function initializeWorkspace(workspaceRoot) {
|
|
404
|
+
const workspaceName = path.basename(workspaceRoot);
|
|
405
|
+
const createdFiles = [];
|
|
406
|
+
const updatedFiles = [];
|
|
407
|
+
const removedFiles = [];
|
|
408
|
+
const skippedSteps = [];
|
|
409
|
+
|
|
410
|
+
const templateSourcePath = resolveTemplateSourcePath(workspaceRoot);
|
|
411
|
+
const targetFeapName = buildTargetFileName(workspaceName);
|
|
412
|
+
const targetFeapPath = path.join(workspaceRoot, targetFeapName);
|
|
413
|
+
if (!fs.existsSync(targetFeapPath)) {
|
|
414
|
+
await fs.promises.copyFile(templateSourcePath, targetFeapPath);
|
|
415
|
+
createdFiles.push(normalizeRelativePath(targetFeapName));
|
|
416
|
+
} else {
|
|
417
|
+
skippedSteps.push(`${normalizeRelativePath(targetFeapName)} already exists`);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
for (const handoffPath of HANDOFF_FILES_TO_RESET) {
|
|
421
|
+
const absolutePath = path.join(workspaceRoot, ...handoffPath);
|
|
422
|
+
if (fs.existsSync(absolutePath)) {
|
|
423
|
+
await fs.promises.rm(absolutePath, { force: true });
|
|
424
|
+
removedFiles.push(normalizeRelativePath(path.relative(workspaceRoot, absolutePath)));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
workspaceRoot,
|
|
430
|
+
targetFeapName,
|
|
431
|
+
createdFiles,
|
|
432
|
+
updatedFiles,
|
|
433
|
+
removedFiles,
|
|
434
|
+
skippedSteps,
|
|
435
|
+
status: 'ok',
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function resolveTemplateSourcePath(workspaceRoot) {
|
|
440
|
+
for (const candidate of EA_TEMPLATE_PATH_CANDIDATES) {
|
|
441
|
+
const absolutePath = path.join(workspaceRoot, ...candidate);
|
|
442
|
+
if (fs.existsSync(absolutePath)) {
|
|
443
|
+
return absolutePath;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
throw new Error(`Unable to locate EA template. Checked: ${EA_TEMPLATE_PATH_CANDIDATES.map(candidate => candidate.join('/')).join(', ')}`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function buildTargetFileName(workspaceName) {
|
|
450
|
+
const sanitized = sanitizeFileName(workspaceName) || 'workspace';
|
|
451
|
+
const safeBaseName = WINDOWS_RESERVED_NAMES.has(sanitized.toUpperCase())
|
|
452
|
+
? `${sanitized}_workspace`
|
|
453
|
+
: sanitized;
|
|
454
|
+
return `${safeBaseName}.feap`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function sanitizeFileName(value) {
|
|
458
|
+
return value
|
|
459
|
+
.replace(/[<>:"/\\|?*\x00-\x1F]/g, '_')
|
|
460
|
+
.replace(/[.\s]+$/g, '')
|
|
461
|
+
.trim();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function normalizeRelativePath(value) {
|
|
465
|
+
return String(value).replace(/\\/g, '/');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function toolResult(payload) {
|
|
469
|
+
return {
|
|
470
|
+
content: [
|
|
471
|
+
{
|
|
472
|
+
type: 'text',
|
|
473
|
+
text: JSON.stringify(payload, null, 2),
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
isError: payload.status === 'failed',
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function canonicalInitErrorResult(error) {
|
|
481
|
+
const result = semanticOperatorErrorResult(error);
|
|
482
|
+
if (error.safeSemanticLifecycleMessage !== true) return result;
|
|
483
|
+
const payload = Object.freeze({
|
|
484
|
+
status: 'failed',
|
|
485
|
+
error: Object.freeze({
|
|
486
|
+
...result.error,
|
|
487
|
+
message: error.message,
|
|
488
|
+
}),
|
|
489
|
+
});
|
|
490
|
+
return Object.freeze({
|
|
491
|
+
...result,
|
|
492
|
+
...payload,
|
|
493
|
+
content: Object.freeze([
|
|
494
|
+
Object.freeze({
|
|
495
|
+
type: 'text',
|
|
496
|
+
text: JSON.stringify(payload),
|
|
497
|
+
}),
|
|
498
|
+
]),
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function send(message) {
|
|
503
|
+
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async function handleRequest(request, dependencies = undefined) {
|
|
507
|
+
const { id, method, params } = request;
|
|
508
|
+
|
|
509
|
+
if (method === 'initialize') {
|
|
510
|
+
return {
|
|
511
|
+
jsonrpc: '2.0',
|
|
512
|
+
id,
|
|
513
|
+
result: {
|
|
514
|
+
protocolVersion: '2024-11-05',
|
|
515
|
+
capabilities: { tools: {} },
|
|
516
|
+
serverInfo: {
|
|
517
|
+
name: 'argo',
|
|
518
|
+
version: '1.0.0',
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (method === 'notifications/initialized') {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (method === 'tools/list') {
|
|
529
|
+
// Deduplicate tools by name — last writer wins.
|
|
530
|
+
// Priority order: validatorMcp > systemArchitectureMcp > local TOOLS.
|
|
531
|
+
// This ensures zero duplicate tool names in the response, which would
|
|
532
|
+
// cause VS Code's MCP client to silently drop tools.
|
|
533
|
+
const toolMap = new Map();
|
|
534
|
+
for (const tool of [...TOOLS, ...systemArchitectureMcp.TOOLS, ...validatorMcp.TOOLS]) {
|
|
535
|
+
toolMap.set(tool.name, tool);
|
|
536
|
+
}
|
|
537
|
+
return {
|
|
538
|
+
jsonrpc: '2.0',
|
|
539
|
+
id,
|
|
540
|
+
result: { tools: [...toolMap.values()] },
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (method === 'tools/call') {
|
|
545
|
+
try {
|
|
546
|
+
const progressToken = (params._meta && params._meta.progressToken) || null;
|
|
547
|
+
let activeDependencies = dependencies;
|
|
548
|
+
if (
|
|
549
|
+
!activeDependencies
|
|
550
|
+
&& params.name === 'getSystemArchitecture'
|
|
551
|
+
&& params.arguments
|
|
552
|
+
&& Object.prototype.hasOwnProperty.call(params.arguments, 'query')
|
|
553
|
+
&& params.arguments.query
|
|
554
|
+
&& params.arguments.query.purpose !== 'graph-tidy'
|
|
555
|
+
) {
|
|
556
|
+
activeDependencies = {
|
|
557
|
+
semanticOperatorJourney:
|
|
558
|
+
await systemArchitectureMcp.createDefaultProductionSemanticOperatorJourney(),
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
const result = await callTool(
|
|
562
|
+
params.name,
|
|
563
|
+
params.arguments || {},
|
|
564
|
+
progressToken,
|
|
565
|
+
activeDependencies,
|
|
566
|
+
);
|
|
567
|
+
return { jsonrpc: '2.0', id, result };
|
|
568
|
+
} catch (error) {
|
|
569
|
+
return {
|
|
570
|
+
jsonrpc: '2.0',
|
|
571
|
+
id,
|
|
572
|
+
result: params.name === 'initializeWorkspace'
|
|
573
|
+
? canonicalInitErrorResult(error)
|
|
574
|
+
: semanticOperatorErrorResult(error),
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (method === 'ping') {
|
|
580
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return {
|
|
584
|
+
jsonrpc: '2.0',
|
|
585
|
+
id,
|
|
586
|
+
error: {
|
|
587
|
+
code: -32601,
|
|
588
|
+
message: `Method not found: ${method}`,
|
|
589
|
+
},
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async function main() {
|
|
594
|
+
const rl = readline.createInterface({
|
|
595
|
+
input: process.stdin,
|
|
596
|
+
crlfDelay: Infinity,
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
for await (const line of rl) {
|
|
600
|
+
if (!line.trim()) {
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
let request;
|
|
604
|
+
try {
|
|
605
|
+
request = JSON.parse(line);
|
|
606
|
+
} catch {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
const response = await handleRequest(request);
|
|
610
|
+
if (response) {
|
|
611
|
+
send(response);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (require.main === module) {
|
|
617
|
+
main().catch((error) => {
|
|
618
|
+
console.error(error);
|
|
619
|
+
process.exit(1);
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
module.exports = {
|
|
624
|
+
callTool,
|
|
625
|
+
handleRequest,
|
|
626
|
+
initializeWorkspace,
|
|
627
|
+
main,
|
|
628
|
+
withCanonicalSemanticInitTestComposition,
|
|
629
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared path resolution for the Argo toolchain.
|
|
6
|
+
*
|
|
7
|
+
* The Argo installation can live in one of two layouts:
|
|
8
|
+
* 1. Embedded — `<repository>/.argo` (the historical layout).
|
|
9
|
+
* 2. Global — `<user-home>/.argo` (a machine-wide MCP installation).
|
|
10
|
+
*
|
|
11
|
+
* Every path in the toolchain is therefore either:
|
|
12
|
+
* - an *installation asset* (scripts, schema, test-executors, .env): resolved
|
|
13
|
+
* relative to the Argo root (the `.argo` directory that contains this file), or
|
|
14
|
+
* - a *workspace asset* (design/KG, tests, .argo/temp, handoff files): resolved
|
|
15
|
+
* relative to the active workspace root.
|
|
16
|
+
*
|
|
17
|
+
* The workspace root is resolved from, in priority order:
|
|
18
|
+
* 1. ARGO_REPO_ROOT — explicit override (set by MCP client configs).
|
|
19
|
+
* 2. WORKSPACE_FOLDER — set by some hosts.
|
|
20
|
+
* 3. The embedded repo root, when the Argo installation is still inside a repo
|
|
21
|
+
* (i.e. `<argoRoot>/../design/KG/SystemArchitecture.json` exists).
|
|
22
|
+
* 4. process.cwd() — the MCP client must launch the server with its cwd
|
|
23
|
+
* set to the target workspace root.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
function getArgoRoot() {
|
|
27
|
+
// This module lives at <argoRoot>/scripts/argo-paths.js.
|
|
28
|
+
return path.resolve(__dirname, '..');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getWorkspaceRoot() {
|
|
32
|
+
const explicit = process.env.ARGO_REPO_ROOT || process.env.WORKSPACE_FOLDER;
|
|
33
|
+
if (explicit && String(explicit).trim() !== '') {
|
|
34
|
+
return path.resolve(explicit);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const embedded = path.resolve(getArgoRoot(), '..');
|
|
38
|
+
if (fs.existsSync(path.join(embedded, 'design', 'KG', 'SystemArchitecture.json'))) {
|
|
39
|
+
return embedded;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return path.resolve(process.cwd());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveArgoPath(...segments) {
|
|
46
|
+
return path.resolve(getArgoRoot(), ...segments);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveWorkspacePath(...segments) {
|
|
50
|
+
return path.resolve(getWorkspaceRoot(), ...segments);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getArgoEnvPath() {
|
|
54
|
+
if (process.env.ARGO_ENV_FILE && String(process.env.ARGO_ENV_FILE).trim() !== '') {
|
|
55
|
+
return path.resolve(process.env.ARGO_ENV_FILE);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const globalPath = path.join(getArgoRoot(), '.env');
|
|
59
|
+
if (fs.existsSync(globalPath)) {
|
|
60
|
+
return globalPath;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return path.join(getWorkspaceRoot(), '.argo', '.env');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeRelativePath(value) {
|
|
67
|
+
return String(value == null ? '' : value).replace(/\\/g, '/').replace(/^\/+/, '');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
getArgoRoot,
|
|
72
|
+
getArgoEnvPath,
|
|
73
|
+
getWorkspaceRoot,
|
|
74
|
+
normalizeRelativePath,
|
|
75
|
+
resolveArgoPath,
|
|
76
|
+
resolveWorkspacePath,
|
|
77
|
+
};
|