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,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Test Executor Template
|
|
3
|
+
*
|
|
4
|
+
* Copy this file to `.argo/scripts/test-executors/` with a descriptive name
|
|
5
|
+
* (e.g., `docker.js`, `cloud-run.js`) and implement the required interface.
|
|
6
|
+
*
|
|
7
|
+
* Each executor module must export:
|
|
8
|
+
* name: string — human-readable identifier for logging
|
|
9
|
+
* canHandle(acceptanceCriteria, workspaceRoot): boolean
|
|
10
|
+
* execute(acceptanceCriteria, workspaceRoot): Promise<{exitCode, stdout, stderr}>
|
|
11
|
+
* getCommandPreview(acceptanceCriteria, workspaceRoot): string | null (optional)
|
|
12
|
+
*
|
|
13
|
+
* Auto-discovery: any .js/.cjs/.mjs file in this directory is loaded automatically.
|
|
14
|
+
* Custom executors are tried BEFORE the built-in default executor.
|
|
15
|
+
* If canHandle() returns false, the next executor is tried.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const name = 'my-custom-executor';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Return true if this executor can handle the given acceptanceCriteria.
|
|
22
|
+
* The acceptanceCriteria is the raw value from the architecture graph's testcase.
|
|
23
|
+
*
|
|
24
|
+
* Example criteria formats this executor might handle:
|
|
25
|
+
* - "docker://my-image:tag /tests/run.sh"
|
|
26
|
+
* - "https://ci.example.com/jobs/..."
|
|
27
|
+
* - "cloud-function://us-central1/my-test"
|
|
28
|
+
*/
|
|
29
|
+
function canHandle(acceptanceCriteria, workspaceRoot) {
|
|
30
|
+
// TODO: implement your matching logic
|
|
31
|
+
// Example: return acceptanceCriteria.startsWith('docker://');
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Return a human-readable command preview for logging.
|
|
37
|
+
* Return null if no preview is available.
|
|
38
|
+
*/
|
|
39
|
+
function getCommandPreview(acceptanceCriteria, workspaceRoot) {
|
|
40
|
+
// TODO: return a readable command string
|
|
41
|
+
return `[${name}] ${acceptanceCriteria}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Execute the test and return {exitCode, stdout, stderr}.
|
|
46
|
+
* exitCode: 0 = pass, non-zero = fail, null = execution error
|
|
47
|
+
*/
|
|
48
|
+
async function execute(acceptanceCriteria, workspaceRoot) {
|
|
49
|
+
// TODO: implement your execution logic
|
|
50
|
+
// Example: spawn a Docker container, call a cloud API, etc.
|
|
51
|
+
return {
|
|
52
|
+
exitCode: 1,
|
|
53
|
+
stdout: '',
|
|
54
|
+
stderr: `${name}: not implemented`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { name, canHandle, execute, getCommandPreview };
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Test Executor — file-extension-based execution.
|
|
3
|
+
*
|
|
4
|
+
* This is the built-in executor that handles the original acceptanceCriteria format:
|
|
5
|
+
* a workspace-relative script path, optionally with a pytest node-id selector.
|
|
6
|
+
*
|
|
7
|
+
* Custom executors can be added to this directory; they are auto-discovered by
|
|
8
|
+
* runArchitectureTests.js. Each executor module must export:
|
|
9
|
+
* name: string
|
|
10
|
+
* canHandle(acceptanceCriteria, workspaceRoot): boolean
|
|
11
|
+
* execute(acceptanceCriteria, workspaceRoot): Promise<{exitCode, stdout, stderr}>
|
|
12
|
+
* getCommandPreview(acceptanceCriteria, workspaceRoot): string | null (optional)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { execFile } = require('child_process');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const { promisify } = require('util');
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
getWorkspaceRoot,
|
|
22
|
+
} = require('../argo-paths.js');
|
|
23
|
+
|
|
24
|
+
const execFileAsync = promisify(execFile);
|
|
25
|
+
|
|
26
|
+
const PYTHON_EXECUTABLE = resolvePythonExecutable();
|
|
27
|
+
const TEST_TIMEOUT_MS = readPositiveInteger(process.env.ARGO_TEST_TIMEOUT_MS, 120000);
|
|
28
|
+
|
|
29
|
+
const SUPPORTED_EXTENSIONS = new Set(['.js', '.cjs', '.mjs', '.py', '.ps1', '.cmd', '.bat']);
|
|
30
|
+
|
|
31
|
+
const DISALLOWED_PATTERNS = [
|
|
32
|
+
/[\r\n]/,
|
|
33
|
+
/[|&;<>]/,
|
|
34
|
+
/^['"].*['"]$/,
|
|
35
|
+
/^(?:npm|pnpm|yarn|npx|node|python|py|powershell|pwsh|cmd|bash|sh)\b/i,
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// --- Exported interface ---
|
|
39
|
+
|
|
40
|
+
const name = 'default';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The default executor handles acceptanceCriteria that are workspace-relative
|
|
44
|
+
* script file paths (optionally with ::pytest_node_id selectors).
|
|
45
|
+
*/
|
|
46
|
+
function canHandle(acceptanceCriteria) {
|
|
47
|
+
if (!acceptanceCriteria) return false;
|
|
48
|
+
|
|
49
|
+
for (const pattern of DISALLOWED_PATTERNS) {
|
|
50
|
+
if (pattern.test(acceptanceCriteria)) return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const parsed = parseCriteria(acceptanceCriteria);
|
|
54
|
+
const ext = path.extname(parsed.scriptRelativePath).toLowerCase();
|
|
55
|
+
if (!SUPPORTED_EXTENSIONS.has(ext)) return false;
|
|
56
|
+
|
|
57
|
+
if (parsed.selector && ext !== '.py') return false;
|
|
58
|
+
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getCommandPreview(acceptanceCriteria) {
|
|
63
|
+
const parsed = parseCriteria(acceptanceCriteria);
|
|
64
|
+
if (parsed.selector) {
|
|
65
|
+
return formatCommand('python', ['-m', 'pytest', buildPytestNodeId(parsed)]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const ext = path.extname(parsed.scriptRelativePath).toLowerCase();
|
|
69
|
+
switch (ext) {
|
|
70
|
+
case '.js': case '.cjs': case '.mjs':
|
|
71
|
+
return formatCommand(process.execPath, [parsed.displayPath || parsed.scriptRelativePath]);
|
|
72
|
+
case '.py':
|
|
73
|
+
return formatCommand('python', [parsed.scriptRelativePath]);
|
|
74
|
+
case '.ps1':
|
|
75
|
+
return formatCommand('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', parsed.scriptRelativePath]);
|
|
76
|
+
case '.cmd': case '.bat':
|
|
77
|
+
return formatCommand(parsed.scriptRelativePath, []);
|
|
78
|
+
default:
|
|
79
|
+
return formatCommand(parsed.scriptRelativePath, []);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function execute(acceptanceCriteria, workspaceRoot) {
|
|
84
|
+
const parsed = parseCriteria(acceptanceCriteria);
|
|
85
|
+
const scriptPath = path.join(workspaceRoot, ...parsed.scriptRelativePath.split('/'));
|
|
86
|
+
|
|
87
|
+
if (!fs.existsSync(scriptPath)) {
|
|
88
|
+
return {
|
|
89
|
+
exitCode: null,
|
|
90
|
+
stdout: '',
|
|
91
|
+
stderr: `test script not found: ${acceptanceCriteria}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (parsed.selector) {
|
|
96
|
+
return runPythonPytestNodeId(parsed, workspaceRoot);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const ext = path.extname(scriptPath).toLowerCase();
|
|
100
|
+
switch (ext) {
|
|
101
|
+
case '.js': case '.cjs': case '.mjs':
|
|
102
|
+
return runCommand(process.execPath, [scriptPath], workspaceRoot, parsed.fragment
|
|
103
|
+
? { ARGO_TESTCASE_ANCHOR: parsed.fragment }
|
|
104
|
+
: undefined);
|
|
105
|
+
case '.py':
|
|
106
|
+
return runCommand(PYTHON_EXECUTABLE, [scriptPath], workspaceRoot);
|
|
107
|
+
case '.ps1':
|
|
108
|
+
return runCommand('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath], workspaceRoot);
|
|
109
|
+
case '.cmd': case '.bat':
|
|
110
|
+
return runCommand(scriptPath, [], workspaceRoot);
|
|
111
|
+
default:
|
|
112
|
+
return runCommand(scriptPath, [], workspaceRoot);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// --- Internal helpers ---
|
|
117
|
+
|
|
118
|
+
function parseCriteria(value) {
|
|
119
|
+
const [pathAndFragment, ...selectorParts] = value.split('::');
|
|
120
|
+
const hashIndex = pathAndFragment.indexOf('#');
|
|
121
|
+
const scriptRelativePath = hashIndex >= 0 ? pathAndFragment.slice(0, hashIndex) : pathAndFragment;
|
|
122
|
+
const fragment = hashIndex >= 0 ? pathAndFragment.slice(hashIndex + 1).trim() : undefined;
|
|
123
|
+
return {
|
|
124
|
+
scriptRelativePath: normalizePath(scriptRelativePath),
|
|
125
|
+
displayPath: normalizePath(pathAndFragment),
|
|
126
|
+
fragment,
|
|
127
|
+
selector: selectorParts.length > 0 ? selectorParts.join('::').trim() : undefined,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function buildPytestNodeId(criteria) {
|
|
132
|
+
return criteria.selector
|
|
133
|
+
? `${criteria.scriptRelativePath}::${criteria.selector}`
|
|
134
|
+
: criteria.scriptRelativePath;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function runPythonPytestNodeId(criteria, cwd) {
|
|
138
|
+
return runCommand(PYTHON_EXECUTABLE, ['-m', 'pytest', buildPytestNodeId(criteria)], cwd);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function runCommand(command, args, cwd, extraEnv = undefined) {
|
|
142
|
+
try {
|
|
143
|
+
const { stdout, stderr } = await execFileAsync(command, args, {
|
|
144
|
+
cwd,
|
|
145
|
+
windowsHide: true,
|
|
146
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
147
|
+
timeout: TEST_TIMEOUT_MS,
|
|
148
|
+
env: extraEnv ? { ...process.env, ...extraEnv } : process.env,
|
|
149
|
+
});
|
|
150
|
+
return { exitCode: 0, stdout: stdout.trim(), stderr: stderr.trim() };
|
|
151
|
+
} catch (error) {
|
|
152
|
+
const timedOut = error && (error.killed || error.signal === 'SIGTERM' || error.code === 'ETIMEDOUT');
|
|
153
|
+
return {
|
|
154
|
+
exitCode: typeof error.code === 'number' ? error.code : 1,
|
|
155
|
+
stdout: String(error.stdout || '').trim(),
|
|
156
|
+
stderr: timedOut
|
|
157
|
+
? `Command timed out after ${TEST_TIMEOUT_MS}ms: ${formatCommand(command, args)}`
|
|
158
|
+
: String(error.stderr || error.message || error).trim(),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function resolvePythonExecutable() {
|
|
164
|
+
const workspaceRoot = getWorkspaceRoot();
|
|
165
|
+
|
|
166
|
+
const candidates = process.platform === 'win32'
|
|
167
|
+
? [
|
|
168
|
+
path.join(workspaceRoot, '.venv', 'Scripts', 'python.exe'),
|
|
169
|
+
path.join(workspaceRoot, 'venv', 'Scripts', 'python.exe'),
|
|
170
|
+
]
|
|
171
|
+
: [
|
|
172
|
+
path.join(workspaceRoot, '.venv', 'bin', 'python'),
|
|
173
|
+
path.join(workspaceRoot, 'venv', 'bin', 'python'),
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
for (const candidate of candidates) {
|
|
177
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
178
|
+
}
|
|
179
|
+
return 'python';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function readPositiveInteger(value, fallback) {
|
|
183
|
+
const parsed = Number.parseInt(String(value || ''), 10);
|
|
184
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function normalizePath(value) {
|
|
188
|
+
return String(value).replace(/\\/g, '/').replace(/^\.\//, '').trim();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function formatCommand(command, args) {
|
|
192
|
+
return [quote(command), ...args.map(quote)].join(' ');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function quote(value) {
|
|
196
|
+
return /\s/.test(value) ? `"${value}"` : value;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = { name, canHandle, execute, getCommandPreview };
|