@alaarab/cortex 1.13.6 → 1.15.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/README.md +16 -15
- package/mcp/dist/cli-config.js +20 -16
- package/mcp/dist/cli-extract.js +15 -10
- package/mcp/dist/cli-govern.js +37 -32
- package/mcp/dist/cli-hooks-citations.js +1 -1
- package/mcp/dist/cli-hooks-retrieval.js +42 -9
- package/mcp/dist/cli-hooks-session.js +46 -41
- package/mcp/dist/cli-hooks.js +26 -21
- package/mcp/dist/cli.js +172 -24
- package/mcp/dist/data-access.js +7 -43
- package/mcp/dist/index.js +23 -15
- package/mcp/dist/link-skills.js +0 -6
- package/mcp/dist/link.js +14 -1
- package/mcp/dist/mcp-finding.js +2 -2
- package/mcp/dist/mcp-search.js +4 -4
- package/mcp/dist/shared-index.js +45 -26
- package/mcp/dist/shared.js +6 -0
- package/mcp/dist/utils.js +49 -5
- package/package.json +11 -11
- package/starter/README.md +2 -2
|
@@ -11,7 +11,12 @@ import { runDoctor } from "./link.js";
|
|
|
11
11
|
import { getHooksEnabledPreference } from "./init.js";
|
|
12
12
|
import { buildIndex, queryRows, } from "./shared-index.js";
|
|
13
13
|
import { filterBacklogByPriority } from "./cli-hooks-retrieval.js";
|
|
14
|
-
|
|
14
|
+
let _cortexPath;
|
|
15
|
+
function getCortexPath() {
|
|
16
|
+
if (!_cortexPath)
|
|
17
|
+
_cortexPath = ensureCortexPath();
|
|
18
|
+
return _cortexPath;
|
|
19
|
+
}
|
|
15
20
|
const profile = process.env.CORTEX_PROFILE || "";
|
|
16
21
|
export function getGitContext(cwd) {
|
|
17
22
|
if (!cwd)
|
|
@@ -239,21 +244,21 @@ async function runBestEffortGit(args, cwd) {
|
|
|
239
244
|
// ── Hook handlers ────────────────────────────────────────────────────────────
|
|
240
245
|
export async function handleHookSessionStart() {
|
|
241
246
|
const startedAt = new Date().toISOString();
|
|
242
|
-
if (!getHooksEnabledPreference(
|
|
243
|
-
updateRuntimeHealth(
|
|
244
|
-
appendAuditLog(
|
|
247
|
+
if (!getHooksEnabledPreference(getCortexPath())) {
|
|
248
|
+
updateRuntimeHealth(getCortexPath(), { lastSessionStartAt: startedAt });
|
|
249
|
+
appendAuditLog(getCortexPath(), "hook_session_start", "status=disabled");
|
|
245
250
|
return;
|
|
246
251
|
}
|
|
247
|
-
const pull = await runBestEffortGit(["pull", "--rebase", "--quiet"],
|
|
248
|
-
const doctor = await runDoctor(
|
|
249
|
-
const maintenanceScheduled = scheduleBackgroundMaintenance(
|
|
252
|
+
const pull = await runBestEffortGit(["pull", "--rebase", "--quiet"], getCortexPath());
|
|
253
|
+
const doctor = await runDoctor(getCortexPath(), false);
|
|
254
|
+
const maintenanceScheduled = scheduleBackgroundMaintenance(getCortexPath());
|
|
250
255
|
try {
|
|
251
256
|
const { trackSession } = await import("./telemetry.js");
|
|
252
|
-
trackSession(
|
|
257
|
+
trackSession(getCortexPath());
|
|
253
258
|
}
|
|
254
259
|
catch { /* best-effort */ }
|
|
255
|
-
updateRuntimeHealth(
|
|
256
|
-
appendAuditLog(
|
|
260
|
+
updateRuntimeHealth(getCortexPath(), { lastSessionStartAt: startedAt });
|
|
261
|
+
appendAuditLog(getCortexPath(), "hook_session_start", `pull=${pull.ok ? "ok" : "fail"} doctor=${doctor.ok ? "ok" : "issues"} maintenance=${maintenanceScheduled ? "scheduled" : "skipped"}`);
|
|
257
262
|
}
|
|
258
263
|
// ── Q21: Conversation memory capture ─────────────────────────────────────────
|
|
259
264
|
const INSIGHT_KEYWORDS = [
|
|
@@ -291,35 +296,35 @@ export function extractConversationInsights(text) {
|
|
|
291
296
|
}
|
|
292
297
|
export async function handleHookStop() {
|
|
293
298
|
const now = new Date().toISOString();
|
|
294
|
-
if (!getHooksEnabledPreference(
|
|
295
|
-
updateRuntimeHealth(
|
|
299
|
+
if (!getHooksEnabledPreference(getCortexPath())) {
|
|
300
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
296
301
|
lastStopAt: now,
|
|
297
302
|
lastAutoSave: { at: now, status: "clean", detail: "hooks disabled by preference" },
|
|
298
303
|
});
|
|
299
|
-
appendAuditLog(
|
|
304
|
+
appendAuditLog(getCortexPath(), "hook_stop", "status=disabled");
|
|
300
305
|
return;
|
|
301
306
|
}
|
|
302
|
-
const status = await runBestEffortGit(["status", "--porcelain"],
|
|
307
|
+
const status = await runBestEffortGit(["status", "--porcelain"], getCortexPath());
|
|
303
308
|
if (!status.ok) {
|
|
304
|
-
updateRuntimeHealth(
|
|
309
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
305
310
|
lastStopAt: now,
|
|
306
311
|
lastAutoSave: { at: now, status: "error", detail: status.error || "git status failed" },
|
|
307
312
|
});
|
|
308
|
-
appendAuditLog(
|
|
313
|
+
appendAuditLog(getCortexPath(), "hook_stop", `status=error detail=${JSON.stringify(status.error || "git status failed")}`);
|
|
309
314
|
return;
|
|
310
315
|
}
|
|
311
316
|
if (!status.output) {
|
|
312
|
-
updateRuntimeHealth(
|
|
317
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
313
318
|
lastStopAt: now,
|
|
314
319
|
lastAutoSave: { at: now, status: "clean", detail: "no changes" },
|
|
315
320
|
});
|
|
316
|
-
appendAuditLog(
|
|
321
|
+
appendAuditLog(getCortexPath(), "hook_stop", "status=clean");
|
|
317
322
|
return;
|
|
318
323
|
}
|
|
319
|
-
const add = await runBestEffortGit(["add", "-A"],
|
|
320
|
-
const commit = add.ok ? await runBestEffortGit(["commit", "-m", "auto-save cortex"],
|
|
324
|
+
const add = await runBestEffortGit(["add", "-A"], getCortexPath());
|
|
325
|
+
const commit = add.ok ? await runBestEffortGit(["commit", "-m", "auto-save cortex"], getCortexPath()) : { ok: false, error: add.error };
|
|
321
326
|
if (!add.ok || !commit.ok) {
|
|
322
|
-
updateRuntimeHealth(
|
|
327
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
323
328
|
lastStopAt: now,
|
|
324
329
|
lastAutoSave: {
|
|
325
330
|
at: now,
|
|
@@ -327,36 +332,36 @@ export async function handleHookStop() {
|
|
|
327
332
|
detail: add.error || commit.error || "git add/commit failed",
|
|
328
333
|
},
|
|
329
334
|
});
|
|
330
|
-
appendAuditLog(
|
|
335
|
+
appendAuditLog(getCortexPath(), "hook_stop", `status=error detail=${JSON.stringify(add.error || commit.error || "git add/commit failed")}`);
|
|
331
336
|
return;
|
|
332
337
|
}
|
|
333
|
-
const remotes = await runBestEffortGit(["remote"],
|
|
338
|
+
const remotes = await runBestEffortGit(["remote"], getCortexPath());
|
|
334
339
|
if (!remotes.ok || !remotes.output) {
|
|
335
|
-
updateRuntimeHealth(
|
|
340
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
336
341
|
lastStopAt: now,
|
|
337
342
|
lastAutoSave: { at: now, status: "saved-local", detail: "commit created; no remote configured" },
|
|
338
343
|
});
|
|
339
|
-
appendAuditLog(
|
|
344
|
+
appendAuditLog(getCortexPath(), "hook_stop", "status=saved-local");
|
|
340
345
|
return;
|
|
341
346
|
}
|
|
342
|
-
const push = await runBestEffortGit(["push"],
|
|
347
|
+
const push = await runBestEffortGit(["push"], getCortexPath());
|
|
343
348
|
if (push.ok) {
|
|
344
|
-
updateRuntimeHealth(
|
|
349
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
345
350
|
lastStopAt: now,
|
|
346
351
|
lastAutoSave: { at: now, status: "saved-pushed", detail: "commit pushed" },
|
|
347
352
|
});
|
|
348
|
-
appendAuditLog(
|
|
353
|
+
appendAuditLog(getCortexPath(), "hook_stop", "status=saved-pushed");
|
|
349
354
|
// Q21: Auto-capture conversation insights (gated behind CORTEX_FEATURE_AUTO_CAPTURE=1)
|
|
350
355
|
if (isFeatureEnabled("CORTEX_FEATURE_AUTO_CAPTURE", false)) {
|
|
351
356
|
try {
|
|
352
357
|
const captureInput = process.env.CORTEX_CONVERSATION_CONTEXT || "";
|
|
353
358
|
if (captureInput) {
|
|
354
359
|
const cwd = process.cwd();
|
|
355
|
-
const activeProject = detectProject(
|
|
360
|
+
const activeProject = detectProject(getCortexPath(), cwd, profile);
|
|
356
361
|
if (activeProject) {
|
|
357
362
|
const insights = extractConversationInsights(captureInput);
|
|
358
363
|
for (const insight of insights) {
|
|
359
|
-
addFindingToFile(
|
|
364
|
+
addFindingToFile(getCortexPath(), activeProject, `[pattern] ${insight}`);
|
|
360
365
|
debugLog(`auto-capture: saved insight for ${activeProject}: ${insight.slice(0, 60)}`);
|
|
361
366
|
}
|
|
362
367
|
}
|
|
@@ -368,7 +373,7 @@ export async function handleHookStop() {
|
|
|
368
373
|
}
|
|
369
374
|
// Auto governance scheduling: run governance weekly if overdue
|
|
370
375
|
try {
|
|
371
|
-
const lastGovPath = runtimeFile(
|
|
376
|
+
const lastGovPath = runtimeFile(getCortexPath(), "last-governance.txt");
|
|
372
377
|
const lastRun = fs.existsSync(lastGovPath) ? parseInt(fs.readFileSync(lastGovPath, "utf8"), 10) : 0;
|
|
373
378
|
const daysSince = (Date.now() - lastRun) / 86_400_000;
|
|
374
379
|
if (daysSince >= 7) {
|
|
@@ -386,14 +391,14 @@ export async function handleHookStop() {
|
|
|
386
391
|
}
|
|
387
392
|
return;
|
|
388
393
|
}
|
|
389
|
-
updateRuntimeHealth(
|
|
394
|
+
updateRuntimeHealth(getCortexPath(), {
|
|
390
395
|
lastStopAt: now,
|
|
391
396
|
lastAutoSave: { at: now, status: "saved-local", detail: push.error || "push failed" },
|
|
392
397
|
});
|
|
393
|
-
appendAuditLog(
|
|
398
|
+
appendAuditLog(getCortexPath(), "hook_stop", `status=saved-local detail=${JSON.stringify(push.error || "push failed")}`);
|
|
394
399
|
}
|
|
395
400
|
export async function handleHookContext() {
|
|
396
|
-
if (!getHooksEnabledPreference(
|
|
401
|
+
if (!getHooksEnabledPreference(getCortexPath())) {
|
|
397
402
|
process.exit(0);
|
|
398
403
|
}
|
|
399
404
|
let cwd = process.cwd();
|
|
@@ -406,8 +411,8 @@ export async function handleHookContext() {
|
|
|
406
411
|
catch (err) {
|
|
407
412
|
debugLog(`hook-context: no stdin or invalid JSON, using cwd: ${err instanceof Error ? err.message : String(err)}`);
|
|
408
413
|
}
|
|
409
|
-
const project = detectProject(
|
|
410
|
-
const db = await buildIndex(
|
|
414
|
+
const project = detectProject(getCortexPath(), cwd, profile);
|
|
415
|
+
const db = await buildIndex(getCortexPath(), profile);
|
|
411
416
|
const contextLabel = project ? `\u25c6 cortex \u00b7 ${project} \u00b7 context` : `\u25c6 cortex \u00b7 context`;
|
|
412
417
|
const parts = [contextLabel, "<cortex-context>"];
|
|
413
418
|
if (project) {
|
|
@@ -456,7 +461,7 @@ export async function handleHookContext() {
|
|
|
456
461
|
// ── PostToolUse hook ─────────────────────────────────────────────────────────
|
|
457
462
|
const INTERESTING_TOOLS = new Set(["Read", "Write", "Edit", "Bash", "Glob", "Grep"]);
|
|
458
463
|
export async function handleHookTool() {
|
|
459
|
-
if (!getHooksEnabledPreference(
|
|
464
|
+
if (!getHooksEnabledPreference(getCortexPath())) {
|
|
460
465
|
process.exit(0);
|
|
461
466
|
}
|
|
462
467
|
const start = Date.now();
|
|
@@ -513,7 +518,7 @@ export async function handleHookTool() {
|
|
|
513
518
|
entry.error = responseStr.slice(0, 300);
|
|
514
519
|
}
|
|
515
520
|
try {
|
|
516
|
-
const logFile = runtimeFile(
|
|
521
|
+
const logFile = runtimeFile(getCortexPath(), "tool-log.jsonl");
|
|
517
522
|
fs.mkdirSync(path.dirname(logFile), { recursive: true });
|
|
518
523
|
fs.appendFileSync(logFile, JSON.stringify(entry) + "\n");
|
|
519
524
|
}
|
|
@@ -521,17 +526,17 @@ export async function handleHookTool() {
|
|
|
521
526
|
// best effort
|
|
522
527
|
}
|
|
523
528
|
const cwd = (data.cwd ?? input.cwd ?? undefined);
|
|
524
|
-
const activeProject = cwd ? detectProject(
|
|
529
|
+
const activeProject = cwd ? detectProject(getCortexPath(), cwd, profile) : null;
|
|
525
530
|
if (activeProject) {
|
|
526
531
|
try {
|
|
527
532
|
const candidates = extractToolFindings(toolName, input, responseStr);
|
|
528
533
|
for (const { text, confidence } of candidates) {
|
|
529
534
|
if (confidence >= 0.85) {
|
|
530
|
-
addFindingToFile(
|
|
535
|
+
addFindingToFile(getCortexPath(), activeProject, text);
|
|
531
536
|
debugLog(`hook-tool: auto-added learning (conf=${confidence}): ${text.slice(0, 60)}`);
|
|
532
537
|
}
|
|
533
538
|
else {
|
|
534
|
-
appendReviewQueue(
|
|
539
|
+
appendReviewQueue(getCortexPath(), activeProject, "Review", [text]);
|
|
535
540
|
debugLog(`hook-tool: queued candidate (conf=${confidence}): ${text.slice(0, 60)}`);
|
|
536
541
|
}
|
|
537
542
|
}
|
package/mcp/dist/cli-hooks.js
CHANGED
|
@@ -30,12 +30,17 @@ import { searchDocuments, applyTrustFilter, rankResults, selectSnippets, detectT
|
|
|
30
30
|
import { buildHookOutput } from "./cli-hooks-output.js";
|
|
31
31
|
import { getGitContext, trackSessionMetrics, scheduleBackgroundMaintenance, } from "./cli-hooks-session.js";
|
|
32
32
|
import { approximateTokens } from "./cli-hooks-retrieval.js";
|
|
33
|
-
|
|
33
|
+
let _cortexPath;
|
|
34
|
+
function getCortexPath() {
|
|
35
|
+
if (!_cortexPath)
|
|
36
|
+
_cortexPath = ensureCortexPath();
|
|
37
|
+
return _cortexPath;
|
|
38
|
+
}
|
|
34
39
|
const profile = process.env.CORTEX_PROFILE || "";
|
|
35
40
|
async function readStdin() {
|
|
36
41
|
return new Promise((resolve, reject) => {
|
|
37
42
|
const chunks = [];
|
|
38
|
-
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
43
|
+
process.stdin.on("data", (chunk) => chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
|
|
39
44
|
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
40
45
|
process.stdin.on("error", reject);
|
|
41
46
|
});
|
|
@@ -67,24 +72,24 @@ export async function handleHookPrompt() {
|
|
|
67
72
|
if (!input)
|
|
68
73
|
process.exit(0);
|
|
69
74
|
const { prompt, cwd, sessionId } = input;
|
|
70
|
-
if (!getHooksEnabledPreference(
|
|
71
|
-
appendAuditLog(
|
|
75
|
+
if (!getHooksEnabledPreference(getCortexPath())) {
|
|
76
|
+
appendAuditLog(getCortexPath(), "hook_prompt", "status=disabled");
|
|
72
77
|
process.exit(0);
|
|
73
78
|
}
|
|
74
|
-
updateRuntimeHealth(
|
|
79
|
+
updateRuntimeHealth(getCortexPath(), { lastPromptAt: new Date().toISOString() });
|
|
75
80
|
const keywords = extractKeywords(prompt);
|
|
76
81
|
if (!keywords)
|
|
77
82
|
process.exit(0);
|
|
78
83
|
debugLog(`hook-prompt keywords: "${keywords}"`);
|
|
79
84
|
const tIndex0 = Date.now();
|
|
80
|
-
const db = await buildIndex(
|
|
85
|
+
const db = await buildIndex(getCortexPath(), profile);
|
|
81
86
|
stage.indexMs = Date.now() - tIndex0;
|
|
82
87
|
const gitCtx = getGitContext(cwd);
|
|
83
88
|
const intent = detectTaskIntent(prompt);
|
|
84
|
-
const detectedProject = cwd ? detectProject(
|
|
89
|
+
const detectedProject = cwd ? detectProject(getCortexPath(), cwd, profile) : null;
|
|
85
90
|
if (detectedProject)
|
|
86
91
|
debugLog(`Detected project: ${detectedProject}`);
|
|
87
|
-
const safeQuery = buildRobustFtsQuery(keywords);
|
|
92
|
+
const safeQuery = buildRobustFtsQuery(keywords, detectedProject);
|
|
88
93
|
if (!safeQuery)
|
|
89
94
|
process.exit(0);
|
|
90
95
|
try {
|
|
@@ -94,14 +99,14 @@ export async function handleHookPrompt() {
|
|
|
94
99
|
if (!rows || !rows.length)
|
|
95
100
|
process.exit(0);
|
|
96
101
|
const tTrust0 = Date.now();
|
|
97
|
-
const policy = getRetentionPolicy(
|
|
102
|
+
const policy = getRetentionPolicy(getCortexPath());
|
|
98
103
|
const memoryTtlDays = Number.parseInt(process.env.CORTEX_MEMORY_TTL_DAYS || String(policy.ttlDays), 10);
|
|
99
|
-
rows = applyTrustFilter(rows,
|
|
104
|
+
rows = applyTrustFilter(rows, getCortexPath(), Number.isNaN(memoryTtlDays) ? policy.ttlDays : memoryTtlDays, policy.minInjectConfidence, policy.decay);
|
|
100
105
|
stage.trustMs = Date.now() - tTrust0;
|
|
101
106
|
if (!rows.length)
|
|
102
107
|
process.exit(0);
|
|
103
108
|
if (isFeatureEnabled("CORTEX_FEATURE_AUTO_EXTRACT", true) && sessionId && detectedProject && cwd) {
|
|
104
|
-
const marker = sessionMarker(
|
|
109
|
+
const marker = sessionMarker(getCortexPath(), `extracted-${sessionId}-${detectedProject}`);
|
|
105
110
|
if (!fs.existsSync(marker)) {
|
|
106
111
|
try {
|
|
107
112
|
await handleExtractMemories(detectedProject, cwd, true);
|
|
@@ -113,7 +118,7 @@ export async function handleHookPrompt() {
|
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
const tRank0 = Date.now();
|
|
116
|
-
rows = rankResults(rows, intent, gitCtx, detectedProject,
|
|
121
|
+
rows = rankResults(rows, intent, gitCtx, detectedProject, getCortexPath(), db, cwd, keywords);
|
|
117
122
|
stage.rankMs = Date.now() - tRank0;
|
|
118
123
|
if (!rows.length)
|
|
119
124
|
process.exit(0);
|
|
@@ -155,7 +160,7 @@ export async function handleHookPrompt() {
|
|
|
155
160
|
budgetUsedTokens = runningTokens;
|
|
156
161
|
debugLog(`injection-budget: trimmed ${selected.length} -> ${kept.length} snippets to fit ${maxInjectTokens} token budget`);
|
|
157
162
|
}
|
|
158
|
-
const parts = buildHookOutput(budgetSelected, budgetUsedTokens, intent, gitCtx, detectedProject, stage, safeTokenBudget,
|
|
163
|
+
const parts = buildHookOutput(budgetSelected, budgetUsedTokens, intent, gitCtx, detectedProject, stage, safeTokenBudget, getCortexPath(), sessionId);
|
|
159
164
|
// Add budget info to trace
|
|
160
165
|
if (parts.length > 0) {
|
|
161
166
|
const traceIdx = parts.findIndex(p => p.includes("trace:"));
|
|
@@ -165,17 +170,17 @@ export async function handleHookPrompt() {
|
|
|
165
170
|
}
|
|
166
171
|
const changedCount = gitCtx?.changedFiles.size ?? 0;
|
|
167
172
|
if (sessionId) {
|
|
168
|
-
trackSessionMetrics(
|
|
173
|
+
trackSessionMetrics(getCortexPath(), sessionId, selected, changedCount);
|
|
169
174
|
}
|
|
170
|
-
flushEntryScores(
|
|
171
|
-
scheduleBackgroundMaintenance(
|
|
172
|
-
const noticeFile = sessionId ? sessionMarker(
|
|
175
|
+
flushEntryScores(getCortexPath());
|
|
176
|
+
scheduleBackgroundMaintenance(getCortexPath());
|
|
177
|
+
const noticeFile = sessionId ? sessionMarker(getCortexPath(), `noticed-${sessionId}`) : null;
|
|
173
178
|
const alreadyNoticed = noticeFile ? fs.existsSync(noticeFile) : false;
|
|
174
179
|
if (!alreadyNoticed) {
|
|
175
180
|
// Clean up stale session markers (>24h old) from .sessions/ dir
|
|
176
181
|
try {
|
|
177
182
|
const cutoff = Date.now() - 86400000;
|
|
178
|
-
const sessDir = sessionsDir(
|
|
183
|
+
const sessDir = sessionsDir(getCortexPath());
|
|
179
184
|
if (fs.existsSync(sessDir)) {
|
|
180
185
|
for (const f of fs.readdirSync(sessDir)) {
|
|
181
186
|
if (!f.startsWith("noticed-") && !f.startsWith("extracted-"))
|
|
@@ -186,10 +191,10 @@ export async function handleHookPrompt() {
|
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
// Also clean legacy markers from root
|
|
189
|
-
for (const f of fs.readdirSync(
|
|
194
|
+
for (const f of fs.readdirSync(getCortexPath())) {
|
|
190
195
|
if (!f.startsWith(".noticed-") && !f.startsWith(".extracted-"))
|
|
191
196
|
continue;
|
|
192
|
-
const fp = `${
|
|
197
|
+
const fp = `${getCortexPath()}/${f}`;
|
|
193
198
|
try {
|
|
194
199
|
fs.unlinkSync(fp);
|
|
195
200
|
}
|
|
@@ -199,7 +204,7 @@ export async function handleHookPrompt() {
|
|
|
199
204
|
catch (err) {
|
|
200
205
|
debugLog(`stale notice cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
201
206
|
}
|
|
202
|
-
const needed = checkConsolidationNeeded(
|
|
207
|
+
const needed = checkConsolidationNeeded(getCortexPath(), profile);
|
|
203
208
|
if (needed.length > 0) {
|
|
204
209
|
const notices = needed.map((n) => {
|
|
205
210
|
const since = n.lastConsolidated ? ` since ${n.lastConsolidated}` : "";
|