archgraph-argo 0.10.42 → 0.10.44

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.
Files changed (36) hide show
  1. package/LICENSE +201 -201
  2. package/argo/package.json +8 -8
  3. package/argo/rules/archgraph.instructions.md +8 -0
  4. package/argo/schema/ImplementationToCodingHandoff.schema.json +251 -251
  5. package/argo/schema/ImplementationToIntentTraceProposal.schema.json +180 -180
  6. package/argo/schema/IntentToImplementationHandoff.schema.json +74 -74
  7. package/argo/schema/SystemArchitecture.schema.json +378 -378
  8. package/argo/schema/archimate3.2.md +7153 -7153
  9. package/argo/scripts/archimate32-rules.js +12301 -12301
  10. package/argo/scripts/generateArchitectureDiffPlantuml.js +466 -466
  11. package/argo/scripts/graph-rag/ARCHITECTURE.md +192 -192
  12. package/argo/scripts/graph-rag/canonicalProjectionAuthority.js +45 -45
  13. package/argo/scripts/graph-rag/embeddingQualificationGate.js +59 -59
  14. package/argo/scripts/graph-rag/externalProductionConfig.js +74 -74
  15. package/argo/scripts/graph-rag/liveEmbeddingProviderClient.js +49 -49
  16. package/argo/scripts/graph-rag/neo4jNativeRetrieval.js +37 -37
  17. package/argo/scripts/graph-rag/semantic-persistence/ARCHITECTURE.md +51 -51
  18. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticCheckpointStore.js +99 -99
  19. package/argo/scripts/graph-rag/semantic-persistence/productionSemanticProjectionStore.js +171 -171
  20. package/argo/scripts/graph-rag/semanticOperatorError.js +38 -38
  21. package/argo/scripts/graph-rag/semanticOperatorJourney.js +459 -459
  22. package/argo/scripts/graph-rag/semanticReadinessAttestationStore.js +398 -398
  23. package/argo/scripts/graph-rag/systemMetadataCommandAdapter.js +269 -269
  24. package/argo/scripts/graph-semantics.js +220 -220
  25. package/argo/scripts/repositoryArgoEnvironment.js +101 -101
  26. package/argo/scripts/runArchitectureTests.js +583 -583
  27. package/argo/scripts/semanticOperatorJourneyCli.js +91 -91
  28. package/argo/scripts/syncSystemArchitectureToNeo4j.js +66 -66
  29. package/argo/scripts/test-executors/_template.js +58 -58
  30. package/argo/scripts/test-executors/default.js +199 -199
  31. package/argo/scripts/validateStageHandoff.js +458 -458
  32. package/argo/scripts/validateSystemArchitecture.js +253 -253
  33. package/argo/scripts/validateTraceProposal.js +181 -181
  34. package/bin/argo-deploy.js +12 -12
  35. package/install-argo.ps1 +27 -8
  36. package/package.json +1 -1
@@ -1,199 +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 };
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 };