@danielblomma/cortex-mcp 1.2.0 → 1.3.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/bin/cortex.mjs
CHANGED
|
@@ -53,6 +53,7 @@ function printHelp() {
|
|
|
53
53
|
console.log(" cortex bootstrap");
|
|
54
54
|
console.log(" cortex update");
|
|
55
55
|
console.log(" cortex status");
|
|
56
|
+
console.log(" cortex doctor");
|
|
56
57
|
console.log(" cortex ingest [--changed] [--verbose]");
|
|
57
58
|
console.log(" cortex embed [--changed]");
|
|
58
59
|
console.log(" cortex graph-load [--no-reset]");
|
|
@@ -145,6 +146,10 @@ function ensureScaffoldExists() {
|
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
// Files that should never be overwritten if they already exist in the target.
|
|
150
|
+
// These contain user-specific configuration that would be lost on re-init.
|
|
151
|
+
const PRESERVE_FILES = new Set(["config.yaml", "enterprise.yml", "enterprise.yaml", "CLAUDE.md"]);
|
|
152
|
+
|
|
148
153
|
function copyDirectory(sourceDir, targetDir) {
|
|
149
154
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
150
155
|
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
@@ -158,6 +163,11 @@ function copyDirectory(sourceDir, targetDir) {
|
|
|
158
163
|
continue;
|
|
159
164
|
}
|
|
160
165
|
|
|
166
|
+
// Skip user-config files that already exist to avoid overwriting custom settings
|
|
167
|
+
if (PRESERVE_FILES.has(entry.name) && fs.existsSync(targetPath)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
161
171
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
162
172
|
fs.copyFileSync(sourcePath, targetPath);
|
|
163
173
|
const sourceMode = fs.statSync(sourcePath).mode;
|
|
@@ -197,6 +207,13 @@ function installScaffold(targetDir, force) {
|
|
|
197
207
|
copyDirectory(sourcePath, targetPath);
|
|
198
208
|
}
|
|
199
209
|
|
|
210
|
+
// Copy CLAUDE.md (skip if already exists to preserve user edits)
|
|
211
|
+
const claudeMdSource = path.join(SCAFFOLD_ROOT, "CLAUDE.md");
|
|
212
|
+
const claudeMdTarget = path.join(targetDir, "CLAUDE.md");
|
|
213
|
+
if (fs.existsSync(claudeMdSource) && !fs.existsSync(claudeMdTarget)) {
|
|
214
|
+
fs.copyFileSync(claudeMdSource, claudeMdTarget);
|
|
215
|
+
}
|
|
216
|
+
|
|
200
217
|
const docsDir = path.join(targetDir, "docs");
|
|
201
218
|
fs.mkdirSync(docsDir, { recursive: true });
|
|
202
219
|
const docsSource = path.join(SCAFFOLD_ROOT, "docs", "architecture.md");
|
|
@@ -626,7 +643,8 @@ async function run() {
|
|
|
626
643
|
"watch",
|
|
627
644
|
"refresh",
|
|
628
645
|
"memory-compile",
|
|
629
|
-
"memory-lint"
|
|
646
|
+
"memory-lint",
|
|
647
|
+
"doctor"
|
|
630
648
|
]);
|
|
631
649
|
|
|
632
650
|
if (!passthrough.has(command)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danielblomma/cortex-mcp",
|
|
3
3
|
"mcpName": "io.github.DanielBlomma/cortex",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"description": "Local, repo-scoped context platform for coding assistants. Semantic search, graph relationships, and architectural rule context.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Daniel Blomma",
|
|
@@ -18,6 +18,7 @@ Commands:
|
|
|
18
18
|
graph-load [--no-reset] Build RyuGraph DB from indexed context
|
|
19
19
|
dashboard [--interval <sec>] Live TUI showing what Cortex adds to your repo
|
|
20
20
|
status Show latest ingest summary
|
|
21
|
+
doctor Health check — verify config, index, MCP, and enterprise
|
|
21
22
|
memory-compile [--dry-run] [--verbose]
|
|
22
23
|
Compile raw memory notes into structured articles
|
|
23
24
|
memory-lint [--verbose] [--json] Lint compiled memory articles for issues
|
|
@@ -58,6 +59,9 @@ case "$COMMAND" in
|
|
|
58
59
|
status)
|
|
59
60
|
"$SCRIPT_DIR/status.sh"
|
|
60
61
|
;;
|
|
62
|
+
doctor)
|
|
63
|
+
"$SCRIPT_DIR/doctor.sh"
|
|
64
|
+
;;
|
|
61
65
|
memory-compile)
|
|
62
66
|
"$SCRIPT_DIR/memory-compile.sh" "$@"
|
|
63
67
|
;;
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
CONTEXT_DIR="$REPO_ROOT/.context"
|
|
6
|
+
MCP_DIR="$REPO_ROOT/mcp"
|
|
7
|
+
|
|
8
|
+
PASS=0
|
|
9
|
+
FAIL=0
|
|
10
|
+
WARN=0
|
|
11
|
+
|
|
12
|
+
pass() { echo " ✓ $1"; PASS=$((PASS + 1)); }
|
|
13
|
+
fail() { echo " ✗ $1"; FAIL=$((FAIL + 1)); }
|
|
14
|
+
warn() { echo " ! $1"; WARN=$((WARN + 1)); }
|
|
15
|
+
info() { echo " - $1"; }
|
|
16
|
+
|
|
17
|
+
echo ""
|
|
18
|
+
echo "[cortex] Doctor — checking your setup"
|
|
19
|
+
|
|
20
|
+
# ── Config ──────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
echo ""
|
|
23
|
+
echo " Config"
|
|
24
|
+
|
|
25
|
+
if [[ -f "$CONTEXT_DIR/config.yaml" ]]; then
|
|
26
|
+
pass ".context/config.yaml found"
|
|
27
|
+
# Show source_paths
|
|
28
|
+
PATHS=$(node -e '
|
|
29
|
+
const fs = require("node:fs");
|
|
30
|
+
const raw = fs.readFileSync(process.argv[1], "utf8");
|
|
31
|
+
const paths = [];
|
|
32
|
+
let inSection = false;
|
|
33
|
+
for (const line of raw.split("\n")) {
|
|
34
|
+
if (/^source_paths:\s*$/.test(line.trim())) { inSection = true; continue; }
|
|
35
|
+
if (!inSection) continue;
|
|
36
|
+
const m = line.match(/^\s*-\s*(.+?)\s*$/);
|
|
37
|
+
if (m) { paths.push(m[1].replace(/^["\x27]|["\x27]$/g, "")); continue; }
|
|
38
|
+
if (line.trim() !== "" && !/^\s/.test(line)) break;
|
|
39
|
+
}
|
|
40
|
+
console.log(paths.join(", ") || "(none)");
|
|
41
|
+
' "$CONTEXT_DIR/config.yaml" 2>/dev/null || echo "(parse error)")
|
|
42
|
+
info "source_paths: $PATHS"
|
|
43
|
+
else
|
|
44
|
+
fail ".context/config.yaml not found — run: cortex init"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Enterprise config
|
|
48
|
+
ENTERPRISE_CONFIG=""
|
|
49
|
+
if [[ -f "$CONTEXT_DIR/enterprise.yml" ]]; then
|
|
50
|
+
ENTERPRISE_CONFIG="$CONTEXT_DIR/enterprise.yml"
|
|
51
|
+
elif [[ -f "$CONTEXT_DIR/enterprise.yaml" ]]; then
|
|
52
|
+
ENTERPRISE_CONFIG="$CONTEXT_DIR/enterprise.yaml"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [[ -n "$ENTERPRISE_CONFIG" ]]; then
|
|
56
|
+
pass "enterprise config found: $(basename "$ENTERPRISE_CONFIG")"
|
|
57
|
+
else
|
|
58
|
+
info "no enterprise config (community mode)"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# ── Index ───────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
echo ""
|
|
64
|
+
echo " Index"
|
|
65
|
+
|
|
66
|
+
INGEST_MANIFEST="$CONTEXT_DIR/cache/manifest.json"
|
|
67
|
+
if [[ -f "$INGEST_MANIFEST" ]]; then
|
|
68
|
+
INGEST_INFO=$(node -e '
|
|
69
|
+
const fs = require("node:fs");
|
|
70
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
71
|
+
const c = d.counts || {};
|
|
72
|
+
const age = Math.round((Date.now() - new Date(d.generated_at).getTime()) / 60000);
|
|
73
|
+
const ageStr = age < 60 ? age + " min ago" : Math.round(age / 60) + "h ago";
|
|
74
|
+
console.log(`${c.files ?? 0} files, ${c.rules ?? 0} rules (${ageStr})`);
|
|
75
|
+
' "$INGEST_MANIFEST" 2>/dev/null || echo "parse error")
|
|
76
|
+
pass "Ingest: $INGEST_INFO"
|
|
77
|
+
else
|
|
78
|
+
warn "Ingest manifest missing — run: cortex bootstrap"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
GRAPH_MANIFEST="$CONTEXT_DIR/cache/graph-manifest.json"
|
|
82
|
+
if [[ -f "$GRAPH_MANIFEST" ]]; then
|
|
83
|
+
GRAPH_INFO=$(node -e '
|
|
84
|
+
const fs = require("node:fs");
|
|
85
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
86
|
+
const c = d.counts || {};
|
|
87
|
+
const age = Math.round((Date.now() - new Date(d.generated_at).getTime()) / 60000);
|
|
88
|
+
const ageStr = age < 60 ? age + " min ago" : Math.round(age / 60) + "h ago";
|
|
89
|
+
console.log(`${c.files ?? 0} files, ${c.constrains ?? 0} constrains, ${c.calls ?? 0} calls (${ageStr})`);
|
|
90
|
+
' "$GRAPH_MANIFEST" 2>/dev/null || echo "parse error")
|
|
91
|
+
pass "Graph: $GRAPH_INFO"
|
|
92
|
+
else
|
|
93
|
+
warn "Graph manifest missing — run: cortex bootstrap"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
EMBED_MANIFEST="$CONTEXT_DIR/embeddings/manifest.json"
|
|
97
|
+
if [[ -f "$EMBED_MANIFEST" ]]; then
|
|
98
|
+
EMBED_INFO=$(node -e '
|
|
99
|
+
const fs = require("node:fs");
|
|
100
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
101
|
+
const c = d.counts || {};
|
|
102
|
+
console.log(`${c.entities ?? 0} entities, model ${d.model || "unknown"}`);
|
|
103
|
+
' "$EMBED_MANIFEST" 2>/dev/null || echo "parse error")
|
|
104
|
+
pass "Embeddings: $EMBED_INFO"
|
|
105
|
+
else
|
|
106
|
+
warn "Embeddings missing — run: cortex bootstrap"
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Freshness
|
|
110
|
+
if [[ -f "$INGEST_MANIFEST" ]] && command -v git &>/dev/null && git -C "$REPO_ROOT" rev-parse --git-dir &>/dev/null; then
|
|
111
|
+
FRESHNESS=$(node -e '
|
|
112
|
+
const fs = require("node:fs");
|
|
113
|
+
const { execSync } = require("node:child_process");
|
|
114
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
115
|
+
const sp = Array.isArray(d.source_paths) ? d.source_paths : [];
|
|
116
|
+
const files = Number(d.counts?.files ?? 0);
|
|
117
|
+
let changed = 0;
|
|
118
|
+
try {
|
|
119
|
+
const out = execSync("git status --porcelain", { cwd: process.argv[2], encoding: "utf8", timeout: 3000 });
|
|
120
|
+
for (const line of out.split("\n")) {
|
|
121
|
+
if (!line || line.length < 4) continue;
|
|
122
|
+
const p = line.slice(3).trim().split(" -> ").pop();
|
|
123
|
+
if (p.startsWith(".context/")) continue;
|
|
124
|
+
if (sp.length === 0 || sp.some(s => p === s || p.startsWith(s + "/"))) changed++;
|
|
125
|
+
}
|
|
126
|
+
} catch {}
|
|
127
|
+
const base = Math.max(files, changed, 1);
|
|
128
|
+
const pct = Math.round(Math.max(0, (base - changed) / base) * 100);
|
|
129
|
+
console.log(pct);
|
|
130
|
+
' "$INGEST_MANIFEST" "$REPO_ROOT" 2>/dev/null || echo "-1")
|
|
131
|
+
if [[ "$FRESHNESS" != "-1" ]]; then
|
|
132
|
+
if [[ "$FRESHNESS" -ge 90 ]]; then
|
|
133
|
+
pass "Freshness: ${FRESHNESS}%"
|
|
134
|
+
elif [[ "$FRESHNESS" -ge 50 ]]; then
|
|
135
|
+
warn "Freshness: ${FRESHNESS}% — run: cortex update"
|
|
136
|
+
else
|
|
137
|
+
fail "Freshness: ${FRESHNESS}% — run: cortex update"
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# ── MCP Server ──────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
echo ""
|
|
145
|
+
echo " MCP Server"
|
|
146
|
+
|
|
147
|
+
if [[ -f "$MCP_DIR/dist/server.js" ]]; then
|
|
148
|
+
pass "mcp/dist/server.js exists"
|
|
149
|
+
else
|
|
150
|
+
fail "mcp/dist/server.js missing — run: cd mcp && npm run build"
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
if [[ -d "$MCP_DIR/node_modules" ]]; then
|
|
154
|
+
pass "mcp/node_modules present"
|
|
155
|
+
else
|
|
156
|
+
fail "mcp/node_modules missing — run: cd mcp && npm install"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Quick MCP import check
|
|
160
|
+
if [[ -f "$MCP_DIR/dist/server.js" ]] && [[ -d "$MCP_DIR/node_modules" ]]; then
|
|
161
|
+
MCP_CHECK=$(cd "$REPO_ROOT" && timeout 10 node -e '
|
|
162
|
+
const start = Date.now();
|
|
163
|
+
try {
|
|
164
|
+
require("./mcp/dist/graph.js");
|
|
165
|
+
console.log("ok " + (Date.now() - start));
|
|
166
|
+
} catch(e) {
|
|
167
|
+
console.log("fail " + e.message);
|
|
168
|
+
}
|
|
169
|
+
' 2>/dev/null || echo "fail timeout")
|
|
170
|
+
if [[ "$MCP_CHECK" == ok* ]]; then
|
|
171
|
+
MS="${MCP_CHECK#ok }"
|
|
172
|
+
pass "Graph module loads (${MS}ms)"
|
|
173
|
+
else
|
|
174
|
+
warn "Graph module failed to load: ${MCP_CHECK#fail }"
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# ── Enterprise ──────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
if [[ -n "$ENTERPRISE_CONFIG" ]]; then
|
|
181
|
+
echo ""
|
|
182
|
+
echo " Enterprise"
|
|
183
|
+
|
|
184
|
+
# Plugin installed?
|
|
185
|
+
ENTERPRISE_PKG="$MCP_DIR/node_modules/@danielblomma/cortex-enterprise/package.json"
|
|
186
|
+
if [[ -f "$ENTERPRISE_PKG" ]]; then
|
|
187
|
+
ENT_VERSION=$(node -e 'console.log(JSON.parse(require("fs").readFileSync(process.argv[1],"utf8")).version)' "$ENTERPRISE_PKG" 2>/dev/null || echo "unknown")
|
|
188
|
+
pass "Plugin installed: v${ENT_VERSION}"
|
|
189
|
+
else
|
|
190
|
+
fail "Plugin not installed — run: cortex bootstrap"
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# Parse enterprise config for checks
|
|
194
|
+
TELEMETRY_ENDPOINT=$(node -e '
|
|
195
|
+
const fs = require("node:fs");
|
|
196
|
+
const raw = fs.readFileSync(process.argv[1], "utf8");
|
|
197
|
+
let section = "", fields = {};
|
|
198
|
+
for (const line of raw.split("\n")) {
|
|
199
|
+
const t = line.trimEnd();
|
|
200
|
+
if (!t || t.startsWith("#")) continue;
|
|
201
|
+
const sm = t.match(/^(\w+):\s*$/);
|
|
202
|
+
if (sm) { section = sm[1]; continue; }
|
|
203
|
+
const kv = t.match(/^\s+(\w+):\s*(.+?)\s*$/);
|
|
204
|
+
if (kv && section) fields[section + "." + kv[1]] = kv[2].replace(/^["\x27]|["\x27]$/g, "");
|
|
205
|
+
}
|
|
206
|
+
console.log(fields["telemetry.endpoint"] || "");
|
|
207
|
+
' "$ENTERPRISE_CONFIG" 2>/dev/null || echo "")
|
|
208
|
+
|
|
209
|
+
POLICY_ENDPOINT=$(node -e '
|
|
210
|
+
const fs = require("node:fs");
|
|
211
|
+
const raw = fs.readFileSync(process.argv[1], "utf8");
|
|
212
|
+
let section = "", fields = {};
|
|
213
|
+
for (const line of raw.split("\n")) {
|
|
214
|
+
const t = line.trimEnd();
|
|
215
|
+
if (!t || t.startsWith("#")) continue;
|
|
216
|
+
const sm = t.match(/^(\w+):\s*$/);
|
|
217
|
+
if (sm) { section = sm[1]; continue; }
|
|
218
|
+
const kv = t.match(/^\s+(\w+):\s*(.+?)\s*$/);
|
|
219
|
+
if (kv && section) fields[section + "." + kv[1]] = kv[2].replace(/^["\x27]|["\x27]$/g, "");
|
|
220
|
+
}
|
|
221
|
+
console.log(fields["policy.endpoint"] || "");
|
|
222
|
+
' "$ENTERPRISE_CONFIG" 2>/dev/null || echo "")
|
|
223
|
+
|
|
224
|
+
# Telemetry
|
|
225
|
+
if [[ -n "$TELEMETRY_ENDPOINT" ]]; then
|
|
226
|
+
pass "Telemetry: endpoint configured"
|
|
227
|
+
HTTP_CODE=$(curl -so /dev/null -w '%{http_code}' --max-time 5 -X POST \
|
|
228
|
+
-H "Content-Type: application/json" \
|
|
229
|
+
-d '{}' \
|
|
230
|
+
"$TELEMETRY_ENDPOINT" 2>/dev/null | tail -c 3 || echo "000")
|
|
231
|
+
if [[ "$HTTP_CODE" == "000" ]]; then
|
|
232
|
+
fail "Telemetry: endpoint not reachable (timeout/DNS)"
|
|
233
|
+
elif [[ "$HTTP_CODE" =~ ^[23] ]]; then
|
|
234
|
+
pass "Telemetry: endpoint reachable (HTTP ${HTTP_CODE})"
|
|
235
|
+
elif [[ "$HTTP_CODE" == "401" ]]; then
|
|
236
|
+
pass "Telemetry: endpoint reachable (auth required — expected)"
|
|
237
|
+
else
|
|
238
|
+
warn "Telemetry: endpoint returned HTTP ${HTTP_CODE}"
|
|
239
|
+
fi
|
|
240
|
+
else
|
|
241
|
+
warn "Telemetry: no endpoint configured"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# Policy
|
|
245
|
+
POLICY_COUNT=0
|
|
246
|
+
if [[ -f "$CONTEXT_DIR/rules.yaml" ]]; then
|
|
247
|
+
LOCAL_RULES=$(grep -c "^ - id:" "$CONTEXT_DIR/rules.yaml" 2>/dev/null || echo "0")
|
|
248
|
+
POLICY_COUNT=$((POLICY_COUNT + LOCAL_RULES))
|
|
249
|
+
fi
|
|
250
|
+
if [[ -f "$CONTEXT_DIR/policies/org-rules.yaml" ]]; then
|
|
251
|
+
ORG_RULES=$(grep -c "^ - id:" "$CONTEXT_DIR/policies/org-rules.yaml" 2>/dev/null || echo "0")
|
|
252
|
+
POLICY_COUNT=$((POLICY_COUNT + ORG_RULES))
|
|
253
|
+
fi
|
|
254
|
+
if [[ "$POLICY_COUNT" -gt 0 ]]; then
|
|
255
|
+
pass "Policies: ${POLICY_COUNT} loaded"
|
|
256
|
+
else
|
|
257
|
+
info "Policies: none loaded"
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
if [[ -n "$POLICY_ENDPOINT" ]]; then
|
|
261
|
+
POLICY_HTTP=$(curl -so /dev/null -w '%{http_code}' --max-time 5 "$POLICY_ENDPOINT" 2>/dev/null | tail -c 3 || echo "000")
|
|
262
|
+
if [[ "$POLICY_HTTP" == "000" ]]; then
|
|
263
|
+
fail "Policy: endpoint not reachable (timeout/DNS)"
|
|
264
|
+
elif [[ "$POLICY_HTTP" =~ ^[23] ]] || [[ "$POLICY_HTTP" == "401" ]]; then
|
|
265
|
+
pass "Policy: endpoint reachable (HTTP ${POLICY_HTTP})"
|
|
266
|
+
else
|
|
267
|
+
warn "Policy: endpoint returned HTTP ${POLICY_HTTP}"
|
|
268
|
+
fi
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Audit
|
|
272
|
+
LATEST_AUDIT=$(ls -t "$CONTEXT_DIR/audit/"*.jsonl 2>/dev/null | head -1 || echo "")
|
|
273
|
+
if [[ -n "$LATEST_AUDIT" ]]; then
|
|
274
|
+
AUDIT_AGE=$(node -e '
|
|
275
|
+
const fs = require("node:fs");
|
|
276
|
+
const stat = fs.statSync(process.argv[1]);
|
|
277
|
+
const mins = Math.round((Date.now() - stat.mtimeMs) / 60000);
|
|
278
|
+
if (mins < 60) console.log(mins + " min ago");
|
|
279
|
+
else console.log(Math.round(mins / 60) + "h ago");
|
|
280
|
+
' "$LATEST_AUDIT" 2>/dev/null || echo "unknown")
|
|
281
|
+
pass "Audit: last entry ${AUDIT_AGE}"
|
|
282
|
+
else
|
|
283
|
+
info "Audit: no entries yet"
|
|
284
|
+
fi
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
# ── Summary ─────────────────────────────────────────────
|
|
288
|
+
|
|
289
|
+
echo ""
|
|
290
|
+
TOTAL=$((PASS + FAIL + WARN))
|
|
291
|
+
if [[ "$FAIL" -eq 0 ]]; then
|
|
292
|
+
echo "[cortex] ${PASS}/${TOTAL} checks passed"
|
|
293
|
+
else
|
|
294
|
+
echo "[cortex] ${PASS}/${TOTAL} checks passed, ${FAIL} failed, ${WARN} warnings"
|
|
295
|
+
fi
|
|
296
|
+
echo ""
|
|
297
|
+
|
|
298
|
+
exit "$FAIL"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared enterprise plugin detection and installation.
|
|
3
|
+
# Sourced by both scripts/bootstrap.sh and scaffold/scripts/bootstrap.sh.
|
|
4
|
+
#
|
|
5
|
+
# Expects: REPO_ROOT, MCP_DIR, step(), info() to be defined by the caller.
|
|
6
|
+
|
|
7
|
+
step "Checking for enterprise plugin"
|
|
8
|
+
ENTERPRISE_CONFIG="$REPO_ROOT/.context/enterprise.yml"
|
|
9
|
+
if [[ ! -f "$ENTERPRISE_CONFIG" ]]; then
|
|
10
|
+
ENTERPRISE_CONFIG="$REPO_ROOT/.context/enterprise.yaml"
|
|
11
|
+
fi
|
|
12
|
+
if [[ -f "$ENTERPRISE_CONFIG" ]]; then
|
|
13
|
+
info "detected enterprise config; installing @danielblomma/cortex-enterprise"
|
|
14
|
+
if NPM_CONFIG_CACHE="$MCP_DIR/.npm-cache" npm --prefix "$MCP_DIR" install --no-fund --no-update-notifier --loglevel=warn "@danielblomma/cortex-enterprise@latest"; then
|
|
15
|
+
info "enterprise plugin installed"
|
|
16
|
+
else
|
|
17
|
+
info "warning: failed to install enterprise plugin; continuing in community mode"
|
|
18
|
+
fi
|
|
19
|
+
else
|
|
20
|
+
info "no enterprise config found; community mode"
|
|
21
|
+
fi
|