@cortex-context/cli 0.0.12 → 0.0.14
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/dist/index.js +455 -24
- package/dist/index.js.map +1 -1
- package/dist/templates/local/docker-compose.local.yml +10 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5617,7 +5617,7 @@ var require_dist = __commonJS({
|
|
|
5617
5617
|
});
|
|
5618
5618
|
};
|
|
5619
5619
|
}
|
|
5620
|
-
var
|
|
5620
|
+
var prompts7 = require_prompts();
|
|
5621
5621
|
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
|
|
5622
5622
|
var noop = () => {
|
|
5623
5623
|
};
|
|
@@ -5668,7 +5668,7 @@ var require_dist = __commonJS({
|
|
|
5668
5668
|
var _question2 = question;
|
|
5669
5669
|
name = _question2.name;
|
|
5670
5670
|
type = _question2.type;
|
|
5671
|
-
if (
|
|
5671
|
+
if (prompts7[type] === void 0) {
|
|
5672
5672
|
throw new Error(`prompt type (${type}) is not defined`);
|
|
5673
5673
|
}
|
|
5674
5674
|
if (override2[question.name] !== void 0) {
|
|
@@ -5679,7 +5679,7 @@ var require_dist = __commonJS({
|
|
|
5679
5679
|
}
|
|
5680
5680
|
}
|
|
5681
5681
|
try {
|
|
5682
|
-
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield
|
|
5682
|
+
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts7[type](question);
|
|
5683
5683
|
answers[name] = answer = yield getFormattedAnswer(question, answer, true);
|
|
5684
5684
|
quit = yield onSubmit(question, answer, answers);
|
|
5685
5685
|
} catch (err) {
|
|
@@ -5711,7 +5711,7 @@ var require_dist = __commonJS({
|
|
|
5711
5711
|
}
|
|
5712
5712
|
module2.exports = Object.assign(prompt, {
|
|
5713
5713
|
prompt,
|
|
5714
|
-
prompts:
|
|
5714
|
+
prompts: prompts7,
|
|
5715
5715
|
inject,
|
|
5716
5716
|
override
|
|
5717
5717
|
});
|
|
@@ -7798,7 +7798,7 @@ var require_prompts2 = __commonJS({
|
|
|
7798
7798
|
var require_lib = __commonJS({
|
|
7799
7799
|
"node_modules/prompts/lib/index.js"(exports2, module2) {
|
|
7800
7800
|
"use strict";
|
|
7801
|
-
var
|
|
7801
|
+
var prompts7 = require_prompts2();
|
|
7802
7802
|
var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
|
|
7803
7803
|
var noop = () => {
|
|
7804
7804
|
};
|
|
@@ -7830,7 +7830,7 @@ var require_lib = __commonJS({
|
|
|
7830
7830
|
throw new Error("prompt message is required");
|
|
7831
7831
|
}
|
|
7832
7832
|
({ name, type } = question);
|
|
7833
|
-
if (
|
|
7833
|
+
if (prompts7[type] === void 0) {
|
|
7834
7834
|
throw new Error(`prompt type (${type}) is not defined`);
|
|
7835
7835
|
}
|
|
7836
7836
|
if (override2[question.name] !== void 0) {
|
|
@@ -7841,7 +7841,7 @@ var require_lib = __commonJS({
|
|
|
7841
7841
|
}
|
|
7842
7842
|
}
|
|
7843
7843
|
try {
|
|
7844
|
-
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await
|
|
7844
|
+
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts7[type](question);
|
|
7845
7845
|
answers[name] = answer = await getFormattedAnswer(question, answer, true);
|
|
7846
7846
|
quit = await onSubmit(question, answer, answers);
|
|
7847
7847
|
} catch (err) {
|
|
@@ -7864,7 +7864,7 @@ var require_lib = __commonJS({
|
|
|
7864
7864
|
function override(answers) {
|
|
7865
7865
|
prompt._override = Object.assign({}, answers);
|
|
7866
7866
|
}
|
|
7867
|
-
module2.exports = Object.assign(prompt, { prompt, prompts:
|
|
7867
|
+
module2.exports = Object.assign(prompt, { prompt, prompts: prompts7, inject, override });
|
|
7868
7868
|
}
|
|
7869
7869
|
});
|
|
7870
7870
|
|
|
@@ -18008,16 +18008,33 @@ function writeMcpConfig(mcpPath, config2) {
|
|
|
18008
18008
|
(0, import_fs3.mkdirSync)((0, import_path3.dirname)(mcpPath), { recursive: true });
|
|
18009
18009
|
(0, import_fs3.writeFileSync)(mcpPath, JSON.stringify(config2, null, 2) + "\n");
|
|
18010
18010
|
}
|
|
18011
|
-
function injectCortexMcpServer(mcpPath, cortexUrl, cortexToken) {
|
|
18011
|
+
function injectCortexMcpServer(mcpPath, cortexUrl, cortexToken, target) {
|
|
18012
18012
|
const config2 = readMcpConfig(mcpPath);
|
|
18013
18013
|
const existed = "cortex" in config2.servers;
|
|
18014
|
+
let cortexTokenEnv;
|
|
18015
|
+
if (cortexToken) {
|
|
18016
|
+
if (target === "vscode" || target === "claude") {
|
|
18017
|
+
if (!config2.inputs) config2.inputs = [];
|
|
18018
|
+
if (!config2.inputs.some((i) => i.id === "cortex_token")) {
|
|
18019
|
+
config2.inputs.push({
|
|
18020
|
+
id: "cortex_token",
|
|
18021
|
+
type: "promptString",
|
|
18022
|
+
description: "Cortex API Token (set during cortex-context server setup)",
|
|
18023
|
+
password: true
|
|
18024
|
+
});
|
|
18025
|
+
}
|
|
18026
|
+
cortexTokenEnv = "${input:cortex_token}";
|
|
18027
|
+
} else {
|
|
18028
|
+
cortexTokenEnv = "${env:CORTEX_API_TOKEN}";
|
|
18029
|
+
}
|
|
18030
|
+
}
|
|
18014
18031
|
config2.servers["cortex"] = {
|
|
18015
18032
|
type: "stdio",
|
|
18016
18033
|
command: "npx",
|
|
18017
18034
|
args: ["-y", "@cortex-context/cli", "mcp-serve"],
|
|
18018
18035
|
env: {
|
|
18019
18036
|
CORTEX_URL: cortexUrl,
|
|
18020
|
-
...
|
|
18037
|
+
...cortexTokenEnv ? { CORTEX_API_TOKEN: cortexTokenEnv } : {}
|
|
18021
18038
|
}
|
|
18022
18039
|
};
|
|
18023
18040
|
writeMcpConfig(mcpPath, config2);
|
|
@@ -18133,7 +18150,7 @@ function configureClaudeDesktop(cortexUrl, cortexToken) {
|
|
|
18133
18150
|
args: ["-y", "@cortex-context/cli", "mcp-serve"],
|
|
18134
18151
|
env: {
|
|
18135
18152
|
CORTEX_URL: cortexUrl,
|
|
18136
|
-
...cortexToken ? { CORTEX_API_TOKEN:
|
|
18153
|
+
...cortexToken ? { CORTEX_API_TOKEN: "${env:CORTEX_API_TOKEN}" } : {}
|
|
18137
18154
|
}
|
|
18138
18155
|
};
|
|
18139
18156
|
(0, import_fs3.writeFileSync)(configPath, JSON.stringify(config2, null, 2) + "\n");
|
|
@@ -18295,6 +18312,10 @@ async function deployLocalStack(workspacePath, opts = {}) {
|
|
|
18295
18312
|
if (!(0, import_fs5.existsSync)(destPath)) {
|
|
18296
18313
|
(0, import_fs5.cpSync)(templatePath, destPath);
|
|
18297
18314
|
}
|
|
18315
|
+
const envPath = (0, import_path5.join)(workspacePath, ".env");
|
|
18316
|
+
const envContent = `CORTEX_API_TOKEN=${opts.token ?? ""}
|
|
18317
|
+
`;
|
|
18318
|
+
(0, import_fs5.writeFileSync)(envPath, envContent, { encoding: "utf-8" });
|
|
18298
18319
|
const imageTag = opts.embeddings ? "latest-embeddings" : "latest";
|
|
18299
18320
|
const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
|
|
18300
18321
|
try {
|
|
@@ -18321,6 +18342,66 @@ ${stderr.trim()}` : ""}`
|
|
|
18321
18342
|
};
|
|
18322
18343
|
}
|
|
18323
18344
|
}
|
|
18345
|
+
async function upgradeLocalStack(workspacePath, opts = {}) {
|
|
18346
|
+
const composePath = (0, import_path5.join)(workspacePath, "docker-compose.local.yml");
|
|
18347
|
+
if (!(0, import_fs5.existsSync)(composePath)) {
|
|
18348
|
+
return {
|
|
18349
|
+
upgraded: false,
|
|
18350
|
+
error: `docker-compose.local.yml not found in ${workspacePath}. Run: cortex-context server`
|
|
18351
|
+
};
|
|
18352
|
+
}
|
|
18353
|
+
const imageTag = opts.embeddings ? "latest-embeddings" : "latest";
|
|
18354
|
+
const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
|
|
18355
|
+
const composeCmd = `docker compose --project-name cortex-local -f "${composePath}"`;
|
|
18356
|
+
try {
|
|
18357
|
+
(0, import_child_process.execSync)(`${composeCmd} pull cortex-api`, {
|
|
18358
|
+
cwd: workspacePath,
|
|
18359
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
18360
|
+
env: { ...process.env, CORTEX_IMAGE: cortexImage }
|
|
18361
|
+
});
|
|
18362
|
+
} catch (err) {
|
|
18363
|
+
const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() ?? "" : "";
|
|
18364
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
18365
|
+
return {
|
|
18366
|
+
upgraded: false,
|
|
18367
|
+
error: `docker compose pull failed: ${msg}${stderr ? `
|
|
18368
|
+
${stderr.trim()}` : ""}`
|
|
18369
|
+
};
|
|
18370
|
+
}
|
|
18371
|
+
try {
|
|
18372
|
+
(0, import_child_process.execSync)(`${composeCmd} up -d --force-recreate cortex-api`, {
|
|
18373
|
+
cwd: workspacePath,
|
|
18374
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
18375
|
+
env: { ...process.env, CORTEX_IMAGE: cortexImage }
|
|
18376
|
+
});
|
|
18377
|
+
} catch (err) {
|
|
18378
|
+
const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() ?? "" : "";
|
|
18379
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
18380
|
+
return {
|
|
18381
|
+
upgraded: false,
|
|
18382
|
+
error: `docker compose up failed: ${msg}${stderr ? `
|
|
18383
|
+
${stderr.trim()}` : ""}`
|
|
18384
|
+
};
|
|
18385
|
+
}
|
|
18386
|
+
return { upgraded: true };
|
|
18387
|
+
}
|
|
18388
|
+
function restartCortexApi(workspacePath) {
|
|
18389
|
+
const composePath = (0, import_path5.join)(workspacePath, "docker-compose.local.yml");
|
|
18390
|
+
if (!(0, import_fs5.existsSync)(composePath))
|
|
18391
|
+
return { restarted: false, error: "docker-compose.local.yml not found" };
|
|
18392
|
+
try {
|
|
18393
|
+
(0, import_child_process.execSync)(
|
|
18394
|
+
`docker compose --project-name cortex-local -f "${composePath}" restart cortex-api`,
|
|
18395
|
+
{ cwd: workspacePath, stdio: "ignore" }
|
|
18396
|
+
);
|
|
18397
|
+
return { restarted: true };
|
|
18398
|
+
} catch (err) {
|
|
18399
|
+
return {
|
|
18400
|
+
restarted: false,
|
|
18401
|
+
error: err instanceof Error ? err.message : String(err)
|
|
18402
|
+
};
|
|
18403
|
+
}
|
|
18404
|
+
}
|
|
18324
18405
|
function isDockerAvailable() {
|
|
18325
18406
|
try {
|
|
18326
18407
|
(0, import_child_process.execSync)("docker --version", { stdio: "ignore" });
|
|
@@ -18711,7 +18792,8 @@ async function initCommand(options) {
|
|
|
18711
18792
|
const mcpStatus = injectCortexMcpServer(
|
|
18712
18793
|
detected.mcpPath,
|
|
18713
18794
|
cortexUrl,
|
|
18714
|
-
cortexToken
|
|
18795
|
+
cortexToken,
|
|
18796
|
+
detected.target
|
|
18715
18797
|
);
|
|
18716
18798
|
if (mcpStatus.added) {
|
|
18717
18799
|
console.log(source_default.green(` \u2713 ${label} \u2014 Cortex server added`));
|
|
@@ -28113,6 +28195,7 @@ async function serveCommand() {
|
|
|
28113
28195
|
var import_os4 = require("os");
|
|
28114
28196
|
var import_fs12 = require("fs");
|
|
28115
28197
|
var import_path13 = require("path");
|
|
28198
|
+
var import_crypto = require("crypto");
|
|
28116
28199
|
var import_prompts3 = __toESM(require_prompts3());
|
|
28117
28200
|
var CORTEX_URL2 = "http://localhost:8082";
|
|
28118
28201
|
var NEO4J_URL = "http://localhost:7474";
|
|
@@ -28233,7 +28316,73 @@ async function serverCommand(options) {
|
|
|
28233
28316
|
process.exit(0);
|
|
28234
28317
|
}
|
|
28235
28318
|
console.log("");
|
|
28236
|
-
console.log(source_default.bold(" Step 3:
|
|
28319
|
+
console.log(source_default.bold(" Step 3: API Token"));
|
|
28320
|
+
console.log(
|
|
28321
|
+
source_default.dim(" Optionally secure write endpoints with a Bearer token.")
|
|
28322
|
+
);
|
|
28323
|
+
console.log(
|
|
28324
|
+
source_default.dim(" Leave open (no token) for purely local/private use.")
|
|
28325
|
+
);
|
|
28326
|
+
console.log("");
|
|
28327
|
+
const generatedToken = (0, import_crypto.randomBytes)(24).toString("hex");
|
|
28328
|
+
const { tokenChoice } = await (0, import_prompts3.default)(
|
|
28329
|
+
{
|
|
28330
|
+
type: "select",
|
|
28331
|
+
name: "tokenChoice",
|
|
28332
|
+
message: "API token:",
|
|
28333
|
+
choices: [
|
|
28334
|
+
{
|
|
28335
|
+
title: "Generate random token " + source_default.dim("(recommended)"),
|
|
28336
|
+
value: "generate"
|
|
28337
|
+
},
|
|
28338
|
+
{ title: "Enter my own token", value: "custom" },
|
|
28339
|
+
{
|
|
28340
|
+
title: "No token " + source_default.dim("(open access \u2014 local only)"),
|
|
28341
|
+
value: "none"
|
|
28342
|
+
}
|
|
28343
|
+
],
|
|
28344
|
+
initial: 0
|
|
28345
|
+
},
|
|
28346
|
+
{
|
|
28347
|
+
onCancel: () => {
|
|
28348
|
+
console.log(source_default.yellow("\n Aborted."));
|
|
28349
|
+
process.exit(0);
|
|
28350
|
+
}
|
|
28351
|
+
}
|
|
28352
|
+
);
|
|
28353
|
+
let serverToken = "";
|
|
28354
|
+
if (!tokenChoice || tokenChoice === "none") {
|
|
28355
|
+
console.log(
|
|
28356
|
+
source_default.dim(" \u2139 No token \u2014 API is open (suitable for local use only)")
|
|
28357
|
+
);
|
|
28358
|
+
} else if (tokenChoice === "generate") {
|
|
28359
|
+
serverToken = generatedToken;
|
|
28360
|
+
console.log(source_default.green(" \u2713 Random token generated"));
|
|
28361
|
+
} else {
|
|
28362
|
+
const { customToken } = await (0, import_prompts3.default)(
|
|
28363
|
+
{
|
|
28364
|
+
type: "password",
|
|
28365
|
+
name: "customToken",
|
|
28366
|
+
message: "Enter your token:",
|
|
28367
|
+
validate: (v) => v.trim().length >= 8 || "Token must be at least 8 characters"
|
|
28368
|
+
},
|
|
28369
|
+
{
|
|
28370
|
+
onCancel: () => {
|
|
28371
|
+
console.log(source_default.yellow("\n Aborted."));
|
|
28372
|
+
process.exit(0);
|
|
28373
|
+
}
|
|
28374
|
+
}
|
|
28375
|
+
);
|
|
28376
|
+
serverToken = customToken?.trim() ?? "";
|
|
28377
|
+
if (!serverToken) {
|
|
28378
|
+
console.log(source_default.dim(" \u2139 Empty \u2014 API is open"));
|
|
28379
|
+
} else {
|
|
28380
|
+
console.log(source_default.green(" \u2713 Token saved"));
|
|
28381
|
+
}
|
|
28382
|
+
}
|
|
28383
|
+
writeConfig({ url: CORTEX_URL2, token: serverToken });
|
|
28384
|
+
console.log("");
|
|
28385
|
+
console.log(source_default.bold(" Step 4: Starting Cortex stack"));
|
|
28237
28386
|
const sysctlFix = tryFixLxcSysctl();
|
|
28238
28387
|
if (sysctlFix.applied) {
|
|
28239
28388
|
console.log(
|
|
@@ -28257,7 +28406,8 @@ async function serverCommand(options) {
|
|
|
28257
28406
|
console.log(source_default.dim(" $ docker compose up -d"));
|
|
28258
28407
|
console.log("");
|
|
28259
28408
|
const startResult = await deployLocalStack(workDir, {
|
|
28260
|
-
embeddings: options.embeddings ?? false
|
|
28409
|
+
embeddings: options.embeddings ?? false,
|
|
28410
|
+
token: serverToken
|
|
28261
28411
|
});
|
|
28262
28412
|
console.log("");
|
|
28263
28413
|
if (!startResult.started) {
|
|
@@ -28306,7 +28456,7 @@ async function serverCommand(options) {
|
|
|
28306
28456
|
}
|
|
28307
28457
|
console.log(source_default.green(" \u2713 Containers started"));
|
|
28308
28458
|
console.log("");
|
|
28309
|
-
console.log(source_default.bold(" Step
|
|
28459
|
+
console.log(source_default.bold(" Step 5: Waiting for Cortex API..."));
|
|
28310
28460
|
const healthSpinner = ora(
|
|
28311
28461
|
" Polling http://localhost:8082/health (up to 2 min)..."
|
|
28312
28462
|
).start();
|
|
@@ -28332,9 +28482,22 @@ async function serverCommand(options) {
|
|
|
28332
28482
|
console.log(source_default.cyan(` Neo4j UI \u2192 ${NEO4J_URL}`));
|
|
28333
28483
|
console.log(source_default.dim(" Neo4j login \u2192 neo4j / cortex-local"));
|
|
28334
28484
|
console.log("");
|
|
28335
|
-
|
|
28336
|
-
|
|
28337
|
-
|
|
28485
|
+
if (serverToken) {
|
|
28486
|
+
console.log(source_default.bold(" \u{1F511} API Token (save this!):"));
|
|
28487
|
+
console.log(source_default.bold.yellow(` ${serverToken}`));
|
|
28488
|
+
console.log("");
|
|
28489
|
+
console.log(source_default.bold(" Next steps:"));
|
|
28490
|
+
console.log(source_default.dim(" 1. Initialize your workspace:"));
|
|
28491
|
+
console.log(
|
|
28492
|
+
source_default.cyan(
|
|
28493
|
+
` cortex-context init --url ${CORTEX_URL2} --token ${serverToken}`
|
|
28494
|
+
)
|
|
28495
|
+
);
|
|
28496
|
+
} else {
|
|
28497
|
+
console.log(source_default.bold(" Next steps:"));
|
|
28498
|
+
console.log(source_default.dim(" 1. Initialize your workspace:"));
|
|
28499
|
+
console.log(source_default.cyan(` cortex-context init --url ${CORTEX_URL2}`));
|
|
28500
|
+
}
|
|
28338
28501
|
console.log(source_default.dim(" 2. Check connectivity:"));
|
|
28339
28502
|
console.log(source_default.cyan(" cortex-context doctor"));
|
|
28340
28503
|
console.log("");
|
|
@@ -28488,8 +28651,8 @@ async function uninstallCommand(options) {
|
|
|
28488
28651
|
if (!options.keepHook && hasHook) {
|
|
28489
28652
|
const hookPath = (0, import_path14.join)(workspacePath, ".git", "hooks", "post-commit");
|
|
28490
28653
|
try {
|
|
28491
|
-
const { readFileSync:
|
|
28492
|
-
const hookContent =
|
|
28654
|
+
const { readFileSync: readFileSync9 } = await import("fs");
|
|
28655
|
+
const hookContent = readFileSync9(hookPath, "utf-8");
|
|
28493
28656
|
if (hookContent.includes("cortex-context")) {
|
|
28494
28657
|
(0, import_fs13.unlinkSync)(hookPath);
|
|
28495
28658
|
console.log(source_default.green(" \u2713 .git/hooks/post-commit \u2014 removed"));
|
|
@@ -28556,7 +28719,11 @@ async function resetCommand(options) {
|
|
|
28556
28719
|
console.log("");
|
|
28557
28720
|
console.log(source_default.bold(" \u25C6 Cortex Context \u2014 Reset Graph"));
|
|
28558
28721
|
console.log("");
|
|
28559
|
-
console.log(
|
|
28722
|
+
console.log(
|
|
28723
|
+
source_default.yellow(
|
|
28724
|
+
" \u26A0 This will delete ALL nodes and relationships from the graph."
|
|
28725
|
+
)
|
|
28726
|
+
);
|
|
28560
28727
|
console.log(source_default.dim(` Server: ${url}`));
|
|
28561
28728
|
console.log("");
|
|
28562
28729
|
const confirmed = options.yes || await (0, import_prompts5.default)({
|
|
@@ -28584,7 +28751,9 @@ async function resetCommand(options) {
|
|
|
28584
28751
|
} catch (err) {
|
|
28585
28752
|
process.stdout.write("\n");
|
|
28586
28753
|
console.error(
|
|
28587
|
-
source_default.red(
|
|
28754
|
+
source_default.red(
|
|
28755
|
+
` \u2717 Network error: ${err instanceof Error ? err.message : String(err)}`
|
|
28756
|
+
)
|
|
28588
28757
|
);
|
|
28589
28758
|
process.exit(1);
|
|
28590
28759
|
}
|
|
@@ -28603,11 +28772,258 @@ async function resetCommand(options) {
|
|
|
28603
28772
|
console.log(source_default.dim(" Run `cortex-context sync` to re-ingest the graph."));
|
|
28604
28773
|
}
|
|
28605
28774
|
|
|
28606
|
-
// src/
|
|
28775
|
+
// src/commands/token.ts
|
|
28776
|
+
var import_crypto2 = require("crypto");
|
|
28607
28777
|
var import_fs14 = require("fs");
|
|
28608
28778
|
var import_path15 = require("path");
|
|
28779
|
+
var import_os5 = require("os");
|
|
28780
|
+
var import_prompts6 = __toESM(require_prompts3());
|
|
28781
|
+
var CORTEX_DIR = (0, import_path15.join)((0, import_os5.homedir)(), ".cortex-context");
|
|
28782
|
+
var ENV_FILE = (0, import_path15.join)(CORTEX_DIR, ".env");
|
|
28783
|
+
async function applyTokenRestart() {
|
|
28784
|
+
if (!isDockerAvailable()) return;
|
|
28785
|
+
console.log(
|
|
28786
|
+
source_default.dim(" Restarting cortex-api container to apply new token...")
|
|
28787
|
+
);
|
|
28788
|
+
const result = restartCortexApi(CORTEX_DIR);
|
|
28789
|
+
if (!result.restarted) {
|
|
28790
|
+
console.log(
|
|
28791
|
+
source_default.yellow(
|
|
28792
|
+
` \u26A0 Could not restart container: ${result.error ?? "unknown error"}`
|
|
28793
|
+
)
|
|
28794
|
+
);
|
|
28795
|
+
console.log(
|
|
28796
|
+
source_default.dim(
|
|
28797
|
+
" docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
|
|
28798
|
+
)
|
|
28799
|
+
);
|
|
28800
|
+
return;
|
|
28801
|
+
}
|
|
28802
|
+
const config2 = readConfig();
|
|
28803
|
+
const url = config2.url ?? "http://localhost:8082";
|
|
28804
|
+
console.log(source_default.dim(` Waiting for Cortex API at ${url}...`));
|
|
28805
|
+
const { healthy } = await waitForCortexHealth(url, 6e4);
|
|
28806
|
+
if (healthy) {
|
|
28807
|
+
console.log(source_default.green(" \u2713 Container restarted and healthy"));
|
|
28808
|
+
} else {
|
|
28809
|
+
console.log(
|
|
28810
|
+
source_default.yellow(
|
|
28811
|
+
" \u26A0 Container restarted but did not become healthy within 60s"
|
|
28812
|
+
)
|
|
28813
|
+
);
|
|
28814
|
+
}
|
|
28815
|
+
}
|
|
28816
|
+
function readEnvToken() {
|
|
28817
|
+
if (!(0, import_fs14.existsSync)(ENV_FILE)) return "";
|
|
28818
|
+
const content = (0, import_fs14.readFileSync)(ENV_FILE, "utf-8");
|
|
28819
|
+
const match = content.match(/^CORTEX_API_TOKEN=(.*)$/m);
|
|
28820
|
+
return match?.[1]?.trim() ?? "";
|
|
28821
|
+
}
|
|
28822
|
+
function writeEnvToken(token) {
|
|
28823
|
+
(0, import_fs14.mkdirSync)(CORTEX_DIR, { recursive: true });
|
|
28824
|
+
if (!(0, import_fs14.existsSync)(ENV_FILE)) {
|
|
28825
|
+
(0, import_fs14.writeFileSync)(ENV_FILE, `CORTEX_API_TOKEN=${token}
|
|
28826
|
+
`, "utf-8");
|
|
28827
|
+
return;
|
|
28828
|
+
}
|
|
28829
|
+
const content = (0, import_fs14.readFileSync)(ENV_FILE, "utf-8");
|
|
28830
|
+
const updated = content.includes("CORTEX_API_TOKEN=") ? content.replace(/^CORTEX_API_TOKEN=.*$/m, `CORTEX_API_TOKEN=${token}`) : content + `CORTEX_API_TOKEN=${token}
|
|
28831
|
+
`;
|
|
28832
|
+
(0, import_fs14.writeFileSync)(ENV_FILE, updated, "utf-8");
|
|
28833
|
+
}
|
|
28834
|
+
async function tokenCommand(options) {
|
|
28835
|
+
console.log("");
|
|
28836
|
+
console.log(source_default.bold(" \u25C6 Cortex Context \u2014 API Token"));
|
|
28837
|
+
console.log("");
|
|
28838
|
+
if (options.set !== void 0) {
|
|
28839
|
+
const newToken = options.set.trim();
|
|
28840
|
+
if (!newToken) {
|
|
28841
|
+
console.log(
|
|
28842
|
+
source_default.yellow(
|
|
28843
|
+
" Clearing token \u2014 API will accept all requests (open access)."
|
|
28844
|
+
)
|
|
28845
|
+
);
|
|
28846
|
+
}
|
|
28847
|
+
writeConfig({ token: newToken });
|
|
28848
|
+
writeEnvToken(newToken);
|
|
28849
|
+
console.log(
|
|
28850
|
+
source_default.green(newToken ? " \u2713 Token updated" : " \u2713 Token cleared")
|
|
28851
|
+
);
|
|
28852
|
+
console.log("");
|
|
28853
|
+
await applyTokenRestart();
|
|
28854
|
+
console.log("");
|
|
28855
|
+
return;
|
|
28856
|
+
}
|
|
28857
|
+
if (options.rotate) {
|
|
28858
|
+
const { confirm } = await (0, import_prompts6.default)(
|
|
28859
|
+
{
|
|
28860
|
+
type: "confirm",
|
|
28861
|
+
name: "confirm",
|
|
28862
|
+
message: "Generate a new random token? (requires container restart to apply)",
|
|
28863
|
+
initial: true
|
|
28864
|
+
},
|
|
28865
|
+
{
|
|
28866
|
+
onCancel: () => {
|
|
28867
|
+
console.log(source_default.yellow("\n Aborted."));
|
|
28868
|
+
process.exit(0);
|
|
28869
|
+
}
|
|
28870
|
+
}
|
|
28871
|
+
);
|
|
28872
|
+
if (!confirm) {
|
|
28873
|
+
console.log(source_default.dim(" Aborted."));
|
|
28874
|
+
console.log("");
|
|
28875
|
+
return;
|
|
28876
|
+
}
|
|
28877
|
+
const newToken = (0, import_crypto2.randomBytes)(24).toString("hex");
|
|
28878
|
+
writeConfig({ token: newToken });
|
|
28879
|
+
writeEnvToken(newToken);
|
|
28880
|
+
console.log(source_default.green(" \u2713 New token generated and saved"));
|
|
28881
|
+
console.log("");
|
|
28882
|
+
console.log(source_default.bold(" \u{1F511} New Token:"));
|
|
28883
|
+
console.log(source_default.bold.yellow(` ${newToken}`));
|
|
28884
|
+
console.log("");
|
|
28885
|
+
const config3 = readConfig();
|
|
28886
|
+
console.log(
|
|
28887
|
+
source_default.dim(" Re-initialize your workspace to update MCP config:")
|
|
28888
|
+
);
|
|
28889
|
+
console.log(
|
|
28890
|
+
source_default.cyan(
|
|
28891
|
+
` cortex-context init --url ${config3.url ?? "http://localhost:8082"} --token ${newToken}`
|
|
28892
|
+
)
|
|
28893
|
+
);
|
|
28894
|
+
console.log("");
|
|
28895
|
+
await applyTokenRestart();
|
|
28896
|
+
console.log("");
|
|
28897
|
+
return;
|
|
28898
|
+
}
|
|
28899
|
+
const config2 = readConfig();
|
|
28900
|
+
const currentToken = config2.token ?? readEnvToken();
|
|
28901
|
+
if (!currentToken) {
|
|
28902
|
+
console.log(
|
|
28903
|
+
source_default.yellow(" \u26A0 No token configured \u2014 API is in open access mode")
|
|
28904
|
+
);
|
|
28905
|
+
console.log(source_default.dim(" Generate one: cortex-context token --rotate"));
|
|
28906
|
+
console.log(
|
|
28907
|
+
source_default.dim(" Set one: cortex-context token --set <value>")
|
|
28908
|
+
);
|
|
28909
|
+
} else if (options.show) {
|
|
28910
|
+
console.log(source_default.bold(` Token: ${source_default.yellow(currentToken)}`));
|
|
28911
|
+
} else {
|
|
28912
|
+
const masked = currentToken.length > 8 ? currentToken.slice(0, 4) + "\u2022".repeat(currentToken.length - 8) + currentToken.slice(-4) : "\u2022".repeat(currentToken.length);
|
|
28913
|
+
console.log(source_default.dim(` Token: ${masked}`));
|
|
28914
|
+
console.log(source_default.dim(" Use --show to reveal the full token"));
|
|
28915
|
+
}
|
|
28916
|
+
console.log("");
|
|
28917
|
+
}
|
|
28918
|
+
|
|
28919
|
+
// src/commands/upgrade.ts
|
|
28920
|
+
var import_path16 = require("path");
|
|
28921
|
+
var import_os6 = require("os");
|
|
28922
|
+
var import_fs15 = require("fs");
|
|
28923
|
+
async function upgradeCommand(options) {
|
|
28924
|
+
console.log("");
|
|
28925
|
+
console.log(source_default.bold.cyan(" \u25C6 Cortex Context \u2014 Upgrade"));
|
|
28926
|
+
console.log(
|
|
28927
|
+
source_default.dim(
|
|
28928
|
+
" Pulls the latest backend image and recreates the cortex-api container."
|
|
28929
|
+
)
|
|
28930
|
+
);
|
|
28931
|
+
console.log("");
|
|
28932
|
+
if (!isDockerAvailable()) {
|
|
28933
|
+
console.error(source_default.red(" \u2717 Docker is not available on $PATH."));
|
|
28934
|
+
console.log(
|
|
28935
|
+
source_default.dim(" Install Docker or ensure it is running, then retry.")
|
|
28936
|
+
);
|
|
28937
|
+
process.exit(1);
|
|
28938
|
+
}
|
|
28939
|
+
const workDir = options.dir ?? (0, import_path16.join)((0, import_os6.homedir)(), ".cortex-context");
|
|
28940
|
+
const composePath = (0, import_path16.join)(workDir, "docker-compose.local.yml");
|
|
28941
|
+
if (!(0, import_fs15.existsSync)(composePath)) {
|
|
28942
|
+
console.error(
|
|
28943
|
+
source_default.red(` \u2717 docker-compose.local.yml not found in ${workDir}`)
|
|
28944
|
+
);
|
|
28945
|
+
console.log(
|
|
28946
|
+
source_default.dim(" The local Cortex stack has not been set up yet. Run:")
|
|
28947
|
+
);
|
|
28948
|
+
console.log(source_default.cyan(" cortex-context server"));
|
|
28949
|
+
console.log("");
|
|
28950
|
+
process.exit(1);
|
|
28951
|
+
}
|
|
28952
|
+
const imageTag = options.embeddings ? "latest-embeddings" : "latest";
|
|
28953
|
+
const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
|
|
28954
|
+
console.log(source_default.dim(` Target image: ${cortexImage}`));
|
|
28955
|
+
console.log(source_default.dim(` Compose dir: ${workDir}`));
|
|
28956
|
+
console.log("");
|
|
28957
|
+
console.log(source_default.bold(" Step 1 \u2014 Pulling latest image..."));
|
|
28958
|
+
if (options.pullOnly) {
|
|
28959
|
+
const { execSync: execSync3 } = await import("child_process");
|
|
28960
|
+
try {
|
|
28961
|
+
execSync3(
|
|
28962
|
+
`docker compose --project-name cortex-local -f "${composePath}" pull cortex-api`,
|
|
28963
|
+
{
|
|
28964
|
+
cwd: workDir,
|
|
28965
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
28966
|
+
env: { ...process.env, CORTEX_IMAGE: cortexImage }
|
|
28967
|
+
}
|
|
28968
|
+
);
|
|
28969
|
+
console.log("");
|
|
28970
|
+
console.log(
|
|
28971
|
+
source_default.green(" \u2713 Image pulled successfully (--pull-only mode)")
|
|
28972
|
+
);
|
|
28973
|
+
console.log(
|
|
28974
|
+
source_default.dim(
|
|
28975
|
+
" Run without --pull-only to recreate the container with the new image."
|
|
28976
|
+
)
|
|
28977
|
+
);
|
|
28978
|
+
console.log("");
|
|
28979
|
+
} catch (err) {
|
|
28980
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28981
|
+
console.error(source_default.red(` \u2717 Pull failed: ${msg}`));
|
|
28982
|
+
process.exit(1);
|
|
28983
|
+
}
|
|
28984
|
+
return;
|
|
28985
|
+
}
|
|
28986
|
+
const result = await upgradeLocalStack(workDir, {
|
|
28987
|
+
embeddings: options.embeddings
|
|
28988
|
+
});
|
|
28989
|
+
if (!result.upgraded) {
|
|
28990
|
+
console.error(source_default.red(` \u2717 Upgrade failed: ${result.error}`));
|
|
28991
|
+
process.exit(1);
|
|
28992
|
+
}
|
|
28993
|
+
console.log("");
|
|
28994
|
+
console.log(source_default.bold(" Step 2 \u2014 Waiting for Cortex API to be healthy..."));
|
|
28995
|
+
const config2 = readConfig();
|
|
28996
|
+
const cortexUrl = config2.url ?? "http://localhost:8082";
|
|
28997
|
+
const { healthy } = await waitForCortexHealth(cortexUrl, 12e4);
|
|
28998
|
+
console.log("");
|
|
28999
|
+
if (healthy) {
|
|
29000
|
+
console.log(source_default.green(" \u2713 Cortex API is healthy"));
|
|
29001
|
+
console.log("");
|
|
29002
|
+
console.log(source_default.bold(" \u25C6 Upgrade complete!"));
|
|
29003
|
+
console.log(source_default.dim(` API running at ${cortexUrl}`));
|
|
29004
|
+
console.log("");
|
|
29005
|
+
} else {
|
|
29006
|
+
console.log(
|
|
29007
|
+
source_default.yellow(
|
|
29008
|
+
" \u26A0 Container is up but did not become healthy within 120s"
|
|
29009
|
+
)
|
|
29010
|
+
);
|
|
29011
|
+
console.log(source_default.dim(" Check container logs:"));
|
|
29012
|
+
console.log(
|
|
29013
|
+
source_default.cyan(
|
|
29014
|
+
` docker compose -f ${workDir}/docker-compose.local.yml logs cortex-api`
|
|
29015
|
+
)
|
|
29016
|
+
);
|
|
29017
|
+
console.log("");
|
|
29018
|
+
process.exit(1);
|
|
29019
|
+
}
|
|
29020
|
+
}
|
|
29021
|
+
|
|
29022
|
+
// src/cli.ts
|
|
29023
|
+
var import_fs16 = require("fs");
|
|
29024
|
+
var import_path17 = require("path");
|
|
28609
29025
|
var pkg = JSON.parse(
|
|
28610
|
-
(0,
|
|
29026
|
+
(0, import_fs16.readFileSync)((0, import_path17.join)(__dirname, "..", "package.json"), "utf-8")
|
|
28611
29027
|
);
|
|
28612
29028
|
function createCli() {
|
|
28613
29029
|
const program3 = new Command();
|
|
@@ -28655,6 +29071,21 @@ function createCli() {
|
|
|
28655
29071
|
program3.command("reset").description(
|
|
28656
29072
|
"Wipe all nodes and relationships from the Cortex Knowledge Graph (irreversible)"
|
|
28657
29073
|
).option("-y, --yes", "Skip confirmation prompt").action(resetCommand);
|
|
29074
|
+
program3.command("token").description(
|
|
29075
|
+
"Show or manage the Cortex API token for the local stack (~/.cortex-context/.env)"
|
|
29076
|
+
).option("--show", "Reveal the full token (default shows masked)").option("--rotate", "Generate a new random token and save it").option(
|
|
29077
|
+
"--set <value>",
|
|
29078
|
+
"Set a specific token value (empty string clears auth)"
|
|
29079
|
+
).action(tokenCommand);
|
|
29080
|
+
program3.command("upgrade").description(
|
|
29081
|
+
"Pull the latest Cortex backend image and restart the local stack"
|
|
29082
|
+
).option(
|
|
29083
|
+
"--dir <path>",
|
|
29084
|
+
"Directory with docker-compose.local.yml (defaults to ~/.cortex-context)"
|
|
29085
|
+
).option("--embeddings", "Use the embeddings-enabled image variant").option(
|
|
29086
|
+
"--pull-only",
|
|
29087
|
+
"Pull the latest image without recreating the container"
|
|
29088
|
+
).action(upgradeCommand);
|
|
28658
29089
|
return program3;
|
|
28659
29090
|
}
|
|
28660
29091
|
|