@danielblomma/cortex-mcp 1.7.1 → 2.0.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.
Files changed (79) hide show
  1. package/bin/cortex.mjs +679 -32
  2. package/bin/style.mjs +349 -0
  3. package/package.json +4 -3
  4. package/scaffold/mcp/package-lock.json +834 -671
  5. package/scaffold/mcp/package.json +1 -1
  6. package/scaffold/mcp/src/cli/enterprise-setup.ts +124 -0
  7. package/scaffold/mcp/src/cli/govern.ts +987 -0
  8. package/scaffold/mcp/src/cli/run.ts +306 -0
  9. package/scaffold/mcp/src/cli/telemetry-test.ts +158 -0
  10. package/scaffold/mcp/src/cli/ungoverned-detector.ts +168 -0
  11. package/scaffold/mcp/src/core/audit/query.ts +81 -0
  12. package/scaffold/mcp/src/core/audit/writer.ts +68 -0
  13. package/scaffold/mcp/src/core/config.ts +329 -0
  14. package/scaffold/mcp/src/core/index.ts +34 -0
  15. package/scaffold/mcp/src/core/license.ts +202 -0
  16. package/scaffold/mcp/src/core/policy/enforce.ts +98 -0
  17. package/scaffold/mcp/src/core/policy/injection.ts +229 -0
  18. package/scaffold/mcp/src/core/policy/store.ts +197 -0
  19. package/scaffold/mcp/src/core/rbac/check.ts +40 -0
  20. package/scaffold/mcp/src/core/telemetry/collector.ts +234 -0
  21. package/scaffold/mcp/src/core/validators/builtins.ts +711 -0
  22. package/scaffold/mcp/src/core/validators/config.ts +47 -0
  23. package/scaffold/mcp/src/core/validators/engine.ts +199 -0
  24. package/scaffold/mcp/src/core/validators/evaluators/code_comments.ts +294 -0
  25. package/scaffold/mcp/src/core/validators/evaluators/regex.ts +144 -0
  26. package/scaffold/mcp/src/daemon/client.ts +155 -0
  27. package/scaffold/mcp/src/daemon/egress-proxy.ts +331 -0
  28. package/scaffold/mcp/src/daemon/heartbeat-pusher.ts +147 -0
  29. package/scaffold/mcp/src/daemon/heartbeat-tracker.ts +223 -0
  30. package/scaffold/mcp/src/daemon/host-events-pusher.ts +285 -0
  31. package/scaffold/mcp/src/daemon/main.ts +300 -0
  32. package/scaffold/mcp/src/daemon/paths.ts +41 -0
  33. package/scaffold/mcp/src/daemon/protocol.ts +101 -0
  34. package/scaffold/mcp/src/daemon/server.ts +227 -0
  35. package/scaffold/mcp/src/daemon/sync-checker.ts +213 -0
  36. package/scaffold/mcp/src/daemon/ungoverned-scanner.ts +149 -0
  37. package/scaffold/mcp/src/embed.ts +1 -1
  38. package/scaffold/mcp/src/embeddings.ts +1 -1
  39. package/scaffold/mcp/src/enterprise/audit/push.ts +84 -0
  40. package/scaffold/mcp/src/enterprise/index.ts +415 -0
  41. package/scaffold/mcp/src/enterprise/model/deploy.ts +33 -0
  42. package/scaffold/mcp/src/enterprise/policy/sync.ts +146 -0
  43. package/scaffold/mcp/src/enterprise/privacy/boundary.ts +212 -0
  44. package/scaffold/mcp/src/enterprise/reviews/push.ts +79 -0
  45. package/scaffold/mcp/src/enterprise/telemetry/sync.ts +72 -0
  46. package/scaffold/mcp/src/enterprise/tools/enterprise.ts +1031 -0
  47. package/scaffold/mcp/src/enterprise/tools/walk.ts +79 -0
  48. package/scaffold/mcp/src/enterprise/violations/push.ts +102 -0
  49. package/scaffold/mcp/src/enterprise/workflow/push.ts +60 -0
  50. package/scaffold/mcp/src/enterprise/workflow/state.ts +535 -0
  51. package/scaffold/mcp/src/hooks/pre-compact.ts +54 -0
  52. package/scaffold/mcp/src/hooks/pre-tool-use.ts +96 -0
  53. package/scaffold/mcp/src/hooks/session-end.ts +73 -0
  54. package/scaffold/mcp/src/hooks/session-start.ts +78 -0
  55. package/scaffold/mcp/src/hooks/shared.ts +134 -0
  56. package/scaffold/mcp/src/hooks/stop.ts +60 -0
  57. package/scaffold/mcp/src/hooks/user-prompt-submit.ts +64 -0
  58. package/scaffold/mcp/src/plugin.ts +150 -0
  59. package/scaffold/mcp/src/server.ts +218 -7
  60. package/scaffold/mcp/tests/copilot-shim.test.mjs +146 -0
  61. package/scaffold/mcp/tests/daemon-client.test.mjs +32 -0
  62. package/scaffold/mcp/tests/egress-proxy.test.mjs +239 -0
  63. package/scaffold/mcp/tests/enterprise-config.test.mjs +154 -0
  64. package/scaffold/mcp/tests/govern-install.test.mjs +320 -0
  65. package/scaffold/mcp/tests/govern-repair.test.mjs +157 -0
  66. package/scaffold/mcp/tests/govern-status.test.mjs +538 -0
  67. package/scaffold/mcp/tests/govern.test.mjs +74 -0
  68. package/scaffold/mcp/tests/heartbeat-pusher.test.mjs +154 -0
  69. package/scaffold/mcp/tests/heartbeat-tracker.test.mjs +237 -0
  70. package/scaffold/mcp/tests/host-events-pusher.test.mjs +347 -0
  71. package/scaffold/mcp/tests/policy-check.test.mjs +220 -0
  72. package/scaffold/mcp/tests/repo-name.test.mjs +134 -0
  73. package/scaffold/mcp/tests/run.test.mjs +109 -0
  74. package/scaffold/mcp/tests/sync-checker.test.mjs +188 -0
  75. package/scaffold/mcp/tests/ungoverned-detector.test.mjs +191 -0
  76. package/scaffold/mcp/tests/ungoverned-scanner.test.mjs +198 -0
  77. package/scaffold/scripts/bootstrap.sh +0 -11
  78. package/scaffold/scripts/doctor.sh +24 -4
  79. package/types.js +5 -0
@@ -0,0 +1,79 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join, relative, sep } from "node:path";
3
+
4
+ // Directories skipped while walking the project for a scope=all review.
5
+ // Common build/vendor conventions across JS/Python/Go/Rust/C#/Java
6
+ // ecosystems; keep permissive enough that individual validators still do
7
+ // their own per-language filtering.
8
+ const EXCLUDED_DIRS = new Set([
9
+ "node_modules",
10
+ ".git",
11
+ "dist",
12
+ "build",
13
+ ".next",
14
+ "target",
15
+ "bin",
16
+ "obj",
17
+ ".venv",
18
+ "venv",
19
+ "__pycache__",
20
+ ".nuxt",
21
+ "vendor",
22
+ ".terraform",
23
+ "coverage",
24
+ ".cache",
25
+ ".turbo",
26
+ ]);
27
+
28
+ const TEXT_EXT_RE =
29
+ /\.(?:ts|tsx|js|jsx|mjs|cjs|json|ya?ml|toml|ini|env|config|xml|properties|tf|tfvars|sh|ps1|py|cs|vb|java|go|rs|rb|php|sql|md|txt|html?|css|scss|less)$/i;
30
+
31
+ // Extensionless text files the secrets validator cares about: dotenv
32
+ // variants and .NET appsettings.*
33
+ const PATH_EXTRA_RE = /(?:^|\/)\.env(?:\.|$)|(?:^|\/)appsettings(?:\.|$)/i;
34
+
35
+ const DEFAULT_MAX_FILES = 10_000;
36
+
37
+ export type WalkOptions = {
38
+ maxFiles?: number;
39
+ };
40
+
41
+ // Recursively list project-relative text file paths under `root`. Used as
42
+ // the file set for scope=all reviews and as a fallback when scope=changed
43
+ // cannot resolve a git diff (non-git working copy, git missing, etc.).
44
+ export function walkProjectFiles(root: string, options: WalkOptions = {}): string[] {
45
+ const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES;
46
+ const results: string[] = [];
47
+
48
+ function walk(dir: string): void {
49
+ if (results.length >= maxFiles) return;
50
+ let entries: string[];
51
+ try {
52
+ entries = readdirSync(dir);
53
+ } catch {
54
+ return;
55
+ }
56
+ for (const name of entries) {
57
+ if (results.length >= maxFiles) return;
58
+ if (EXCLUDED_DIRS.has(name)) continue;
59
+ const abs = join(dir, name);
60
+ let st;
61
+ try {
62
+ st = statSync(abs);
63
+ } catch {
64
+ continue;
65
+ }
66
+ if (st.isDirectory()) {
67
+ walk(abs);
68
+ } else if (st.isFile()) {
69
+ const rel = relative(root, abs).split(sep).join("/");
70
+ if (TEXT_EXT_RE.test(rel) || PATH_EXTRA_RE.test(rel)) {
71
+ results.push(rel);
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ walk(root);
78
+ return results;
79
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Push policy violations to the Cortex Cloud API.
3
+ *
4
+ * Uses the same endpoint/api_key as policy sync since
5
+ * violations require the "policy" scope.
6
+ */
7
+ type ViolationItem = {
8
+ rule_id: string;
9
+ severity: "error" | "warning" | "info";
10
+ message: string;
11
+ file_path?: string;
12
+ metadata?: string;
13
+ occurred_at: string;
14
+ };
15
+
16
+ export type ViolationPushContext = {
17
+ repo?: string;
18
+ instance_id?: string;
19
+ session_id?: string;
20
+ };
21
+
22
+ export type ViolationPushResult = {
23
+ success: boolean;
24
+ count: number;
25
+ error?: string;
26
+ };
27
+
28
+ const pending: ViolationItem[] = [];
29
+ let activeContext: ViolationPushContext = {};
30
+
31
+ export function setViolationPushContext(context: ViolationPushContext): void {
32
+ activeContext = { ...context };
33
+ }
34
+
35
+ /**
36
+ * Queue a violation for the next push.
37
+ */
38
+ export function queueViolation(item: ViolationItem): void {
39
+ pending.push(item);
40
+ }
41
+
42
+ /**
43
+ * Push all queued violations to cortex-web.
44
+ * Fire-and-forget — errors are logged but do not throw.
45
+ */
46
+ export async function pushViolations(
47
+ baseUrl: string,
48
+ apiKey: string,
49
+ ): Promise<ViolationPushResult> {
50
+ if (pending.length === 0) {
51
+ return { success: true, count: 0 };
52
+ }
53
+
54
+ if (!baseUrl || !apiKey) {
55
+ return { success: false, count: 0, error: "endpoint or api_key not configured" };
56
+ }
57
+
58
+ const violationsUrl = `${baseUrl.replace(/\/$/, "")}/api/v1/violations/push`;
59
+
60
+ const batch = pending.splice(0, 100); // max 100 per push
61
+
62
+ try {
63
+ const response = await fetch(violationsUrl, {
64
+ method: "POST",
65
+ headers: {
66
+ "Authorization": `Bearer ${apiKey}`,
67
+ "Content-Type": "application/json",
68
+ "Accept": "application/json",
69
+ },
70
+ body: JSON.stringify({
71
+ repo: activeContext.repo,
72
+ instance_id: activeContext.instance_id,
73
+ session_id: activeContext.session_id,
74
+ violations: batch,
75
+ }),
76
+ signal: AbortSignal.timeout(10_000),
77
+ });
78
+
79
+ if (!response.ok) {
80
+ // Put them back so they can be retried
81
+ pending.unshift(...batch);
82
+ return { success: false, count: 0, error: `HTTP ${response.status}` };
83
+ }
84
+
85
+ return { success: true, count: batch.length };
86
+ } catch (err) {
87
+ // Put them back for retry
88
+ pending.unshift(...batch);
89
+ return {
90
+ success: false,
91
+ count: 0,
92
+ error: err instanceof Error ? err.message : "unknown error",
93
+ };
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Return the current queue length (for diagnostics).
99
+ */
100
+ export function pendingCount(): number {
101
+ return pending.length;
102
+ }
@@ -0,0 +1,60 @@
1
+ import type { WorkflowState } from "./state.js";
2
+
3
+ export type WorkflowPushContext = {
4
+ repo?: string;
5
+ instance_id?: string;
6
+ session_id?: string;
7
+ };
8
+
9
+ export type WorkflowPushResult = {
10
+ success: boolean;
11
+ status?: number;
12
+ error?: string;
13
+ };
14
+
15
+ let activeContext: WorkflowPushContext = {};
16
+
17
+ export function setWorkflowPushContext(context: WorkflowPushContext): void {
18
+ activeContext = { ...context };
19
+ }
20
+
21
+ export async function pushWorkflowSnapshot(
22
+ baseUrl: string,
23
+ apiKey: string,
24
+ workflow: WorkflowState
25
+ ): Promise<WorkflowPushResult> {
26
+ if (!baseUrl || !apiKey) {
27
+ return { success: false, error: "endpoint or api_key not configured" };
28
+ }
29
+
30
+ const workflowUrl = `${baseUrl.replace(/\/$/, "")}/api/v1/workflow/push`;
31
+
32
+ try {
33
+ const response = await fetch(workflowUrl, {
34
+ method: "POST",
35
+ headers: {
36
+ "Authorization": `Bearer ${apiKey}`,
37
+ "Content-Type": "application/json",
38
+ "Accept": "application/json",
39
+ },
40
+ body: JSON.stringify({
41
+ repo: activeContext.repo,
42
+ instance_id: activeContext.instance_id,
43
+ session_id: activeContext.session_id,
44
+ workflow,
45
+ }),
46
+ signal: AbortSignal.timeout(10_000),
47
+ });
48
+
49
+ if (!response.ok) {
50
+ return { success: false, status: response.status, error: `HTTP ${response.status}` };
51
+ }
52
+
53
+ return { success: true, status: response.status };
54
+ } catch (err) {
55
+ return {
56
+ success: false,
57
+ error: err instanceof Error ? err.message : "unknown error",
58
+ };
59
+ }
60
+ }