@cortex-context/cli 0.0.13 → 0.0.15

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 CHANGED
@@ -18309,12 +18309,26 @@ async function deployLocalStack(workspacePath, opts = {}) {
18309
18309
  if (!(0, import_fs5.existsSync)(templatePath)) {
18310
18310
  return { started: false, error: `Template not found: ${templatePath}` };
18311
18311
  }
18312
- if (!(0, import_fs5.existsSync)(destPath)) {
18313
- (0, import_fs5.cpSync)(templatePath, destPath);
18314
- }
18312
+ (0, import_fs5.cpSync)(templatePath, destPath);
18313
+ const specsSample = (0, import_path5.join)(workspacePath, "specs-sample");
18314
+ const reposSample = (0, import_path5.join)(workspacePath, "repos-sample");
18315
+ (0, import_fs5.mkdirSync)(specsSample, { recursive: true });
18316
+ (0, import_fs5.mkdirSync)(reposSample, { recursive: true });
18315
18317
  const envPath = (0, import_path5.join)(workspacePath, ".env");
18316
- const envContent = `CORTEX_API_TOKEN=${opts.token ?? ""}
18317
- `;
18318
+ let existingEnv = "";
18319
+ if ((0, import_fs5.existsSync)(envPath)) {
18320
+ existingEnv = (0, import_fs5.readFileSync)(envPath, "utf-8");
18321
+ }
18322
+ const setEnvVar = (content, key, value) => {
18323
+ const re = new RegExp(`^${key}=.*$`, "m");
18324
+ const line = `${key}=${value}`;
18325
+ return re.test(content) ? content.replace(re, line) : content + (content.endsWith("\n") || !content ? "" : "\n") + line + "\n";
18326
+ };
18327
+ let envContent = existingEnv;
18328
+ envContent = setEnvVar(envContent, "CORTEX_API_TOKEN", opts.token ?? "");
18329
+ envContent = setEnvVar(envContent, "SPECS_DIR_HOST", opts.specsDir ?? "./specs-sample");
18330
+ envContent = setEnvVar(envContent, "REPOS_DIR_HOST", opts.reposDir ?? "./repos-sample");
18331
+ if (!envContent.endsWith("\n")) envContent += "\n";
18318
18332
  (0, import_fs5.writeFileSync)(envPath, envContent, { encoding: "utf-8" });
18319
18333
  const imageTag = opts.embeddings ? "latest-embeddings" : "latest";
18320
18334
  const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
@@ -18342,6 +18356,66 @@ ${stderr.trim()}` : ""}`
18342
18356
  };
18343
18357
  }
18344
18358
  }
18359
+ async function upgradeLocalStack(workspacePath, opts = {}) {
18360
+ const composePath = (0, import_path5.join)(workspacePath, "docker-compose.local.yml");
18361
+ if (!(0, import_fs5.existsSync)(composePath)) {
18362
+ return {
18363
+ upgraded: false,
18364
+ error: `docker-compose.local.yml not found in ${workspacePath}. Run: cortex-context server`
18365
+ };
18366
+ }
18367
+ const imageTag = opts.embeddings ? "latest-embeddings" : "latest";
18368
+ const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
18369
+ const composeCmd = `docker compose --project-name cortex-local -f "${composePath}"`;
18370
+ try {
18371
+ (0, import_child_process.execSync)(`${composeCmd} pull cortex-api`, {
18372
+ cwd: workspacePath,
18373
+ stdio: ["inherit", "inherit", "pipe"],
18374
+ env: { ...process.env, CORTEX_IMAGE: cortexImage }
18375
+ });
18376
+ } catch (err) {
18377
+ const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() ?? "" : "";
18378
+ const msg = err instanceof Error ? err.message : String(err);
18379
+ return {
18380
+ upgraded: false,
18381
+ error: `docker compose pull failed: ${msg}${stderr ? `
18382
+ ${stderr.trim()}` : ""}`
18383
+ };
18384
+ }
18385
+ try {
18386
+ (0, import_child_process.execSync)(`${composeCmd} up -d --no-deps --force-recreate cortex-api`, {
18387
+ cwd: workspacePath,
18388
+ stdio: ["inherit", "inherit", "pipe"],
18389
+ env: { ...process.env, CORTEX_IMAGE: cortexImage }
18390
+ });
18391
+ } catch (err) {
18392
+ const stderr = err instanceof Error && "stderr" in err ? err.stderr?.toString() ?? "" : "";
18393
+ const msg = err instanceof Error ? err.message : String(err);
18394
+ return {
18395
+ upgraded: false,
18396
+ error: `docker compose up failed: ${msg}${stderr ? `
18397
+ ${stderr.trim()}` : ""}`
18398
+ };
18399
+ }
18400
+ return { upgraded: true };
18401
+ }
18402
+ function restartCortexApi(workspacePath) {
18403
+ const composePath = (0, import_path5.join)(workspacePath, "docker-compose.local.yml");
18404
+ if (!(0, import_fs5.existsSync)(composePath))
18405
+ return { restarted: false, error: "docker-compose.local.yml not found" };
18406
+ try {
18407
+ (0, import_child_process.execSync)(
18408
+ `docker compose --project-name cortex-local -f "${composePath}" restart cortex-api`,
18409
+ { cwd: workspacePath, stdio: "ignore" }
18410
+ );
18411
+ return { restarted: true };
18412
+ } catch (err) {
18413
+ return {
18414
+ restarted: false,
18415
+ error: err instanceof Error ? err.message : String(err)
18416
+ };
18417
+ }
18418
+ }
18345
18419
  function isDockerAvailable() {
18346
18420
  try {
18347
18421
  (0, import_child_process.execSync)("docker --version", { stdio: "ignore" });
@@ -18619,7 +18693,7 @@ async function initCommand(options) {
18619
18693
  const spinner2 = ora(
18620
18694
  " Starting Cortex stack with Docker Compose..."
18621
18695
  ).start();
18622
- const dockerResult = await deployLocalStack(workspacePath);
18696
+ const dockerResult = await deployLocalStack(workspacePath, { token: cortexToken });
18623
18697
  if (!dockerResult.started) {
18624
18698
  spinner2.fail(
18625
18699
  source_default.red(` \u2717 Docker deploy failed: ${dockerResult.error}`)
@@ -28720,6 +28794,39 @@ var import_os5 = require("os");
28720
28794
  var import_prompts6 = __toESM(require_prompts3());
28721
28795
  var CORTEX_DIR = (0, import_path15.join)((0, import_os5.homedir)(), ".cortex-context");
28722
28796
  var ENV_FILE = (0, import_path15.join)(CORTEX_DIR, ".env");
28797
+ async function applyTokenRestart() {
28798
+ if (!isDockerAvailable()) return;
28799
+ console.log(
28800
+ source_default.dim(" Restarting cortex-api container to apply new token...")
28801
+ );
28802
+ const result = restartCortexApi(CORTEX_DIR);
28803
+ if (!result.restarted) {
28804
+ console.log(
28805
+ source_default.yellow(
28806
+ ` \u26A0 Could not restart container: ${result.error ?? "unknown error"}`
28807
+ )
28808
+ );
28809
+ console.log(
28810
+ source_default.dim(
28811
+ " docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
28812
+ )
28813
+ );
28814
+ return;
28815
+ }
28816
+ const config2 = readConfig();
28817
+ const url = config2.url ?? "http://localhost:8082";
28818
+ console.log(source_default.dim(` Waiting for Cortex API at ${url}...`));
28819
+ const { healthy } = await waitForCortexHealth(url, 6e4);
28820
+ if (healthy) {
28821
+ console.log(source_default.green(" \u2713 Container restarted and healthy"));
28822
+ } else {
28823
+ console.log(
28824
+ source_default.yellow(
28825
+ " \u26A0 Container restarted but did not become healthy within 60s"
28826
+ )
28827
+ );
28828
+ }
28829
+ }
28723
28830
  function readEnvToken() {
28724
28831
  if (!(0, import_fs14.existsSync)(ENV_FILE)) return "";
28725
28832
  const content = (0, import_fs14.readFileSync)(ENV_FILE, "utf-8");
@@ -28756,15 +28863,8 @@ async function tokenCommand(options) {
28756
28863
  console.log(
28757
28864
  source_default.green(newToken ? " \u2713 Token updated" : " \u2713 Token cleared")
28758
28865
  );
28759
- if (newToken) {
28760
- console.log("");
28761
- console.log(source_default.dim(" Restart the Cortex container to apply:"));
28762
- console.log(
28763
- source_default.cyan(
28764
- " docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
28765
- )
28766
- );
28767
- }
28866
+ console.log("");
28867
+ await applyTokenRestart();
28768
28868
  console.log("");
28769
28869
  return;
28770
28870
  }
@@ -28805,12 +28905,8 @@ async function tokenCommand(options) {
28805
28905
  ` cortex-context init --url ${config3.url ?? "http://localhost:8082"} --token ${newToken}`
28806
28906
  )
28807
28907
  );
28808
- console.log(source_default.dim(" Restart the Cortex container:"));
28809
- console.log(
28810
- source_default.cyan(
28811
- " docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
28812
- )
28813
- );
28908
+ console.log("");
28909
+ await applyTokenRestart();
28814
28910
  console.log("");
28815
28911
  return;
28816
28912
  }
@@ -28834,11 +28930,114 @@ async function tokenCommand(options) {
28834
28930
  console.log("");
28835
28931
  }
28836
28932
 
28837
- // src/cli.ts
28838
- var import_fs15 = require("fs");
28933
+ // src/commands/upgrade.ts
28839
28934
  var import_path16 = require("path");
28935
+ var import_os6 = require("os");
28936
+ var import_fs15 = require("fs");
28937
+ async function upgradeCommand(options) {
28938
+ console.log("");
28939
+ console.log(source_default.bold.cyan(" \u25C6 Cortex Context \u2014 Upgrade"));
28940
+ console.log(
28941
+ source_default.dim(
28942
+ " Pulls the latest backend image and recreates the cortex-api container."
28943
+ )
28944
+ );
28945
+ console.log("");
28946
+ if (!isDockerAvailable()) {
28947
+ console.error(source_default.red(" \u2717 Docker is not available on $PATH."));
28948
+ console.log(
28949
+ source_default.dim(" Install Docker or ensure it is running, then retry.")
28950
+ );
28951
+ process.exit(1);
28952
+ }
28953
+ const workDir = options.dir ?? (0, import_path16.join)((0, import_os6.homedir)(), ".cortex-context");
28954
+ const composePath = (0, import_path16.join)(workDir, "docker-compose.local.yml");
28955
+ if (!(0, import_fs15.existsSync)(composePath)) {
28956
+ console.error(
28957
+ source_default.red(` \u2717 docker-compose.local.yml not found in ${workDir}`)
28958
+ );
28959
+ console.log(
28960
+ source_default.dim(" The local Cortex stack has not been set up yet. Run:")
28961
+ );
28962
+ console.log(source_default.cyan(" cortex-context server"));
28963
+ console.log("");
28964
+ process.exit(1);
28965
+ }
28966
+ const imageTag = options.embeddings ? "latest-embeddings" : "latest";
28967
+ const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
28968
+ console.log(source_default.dim(` Target image: ${cortexImage}`));
28969
+ console.log(source_default.dim(` Compose dir: ${workDir}`));
28970
+ console.log("");
28971
+ console.log(source_default.bold(" Step 1 \u2014 Pulling latest image..."));
28972
+ if (options.pullOnly) {
28973
+ const { execSync: execSync3 } = await import("child_process");
28974
+ try {
28975
+ execSync3(
28976
+ `docker compose --project-name cortex-local -f "${composePath}" pull cortex-api`,
28977
+ {
28978
+ cwd: workDir,
28979
+ stdio: ["inherit", "inherit", "pipe"],
28980
+ env: { ...process.env, CORTEX_IMAGE: cortexImage }
28981
+ }
28982
+ );
28983
+ console.log("");
28984
+ console.log(
28985
+ source_default.green(" \u2713 Image pulled successfully (--pull-only mode)")
28986
+ );
28987
+ console.log(
28988
+ source_default.dim(
28989
+ " Run without --pull-only to recreate the container with the new image."
28990
+ )
28991
+ );
28992
+ console.log("");
28993
+ } catch (err) {
28994
+ const msg = err instanceof Error ? err.message : String(err);
28995
+ console.error(source_default.red(` \u2717 Pull failed: ${msg}`));
28996
+ process.exit(1);
28997
+ }
28998
+ return;
28999
+ }
29000
+ const result = await upgradeLocalStack(workDir, {
29001
+ embeddings: options.embeddings
29002
+ });
29003
+ if (!result.upgraded) {
29004
+ console.error(source_default.red(` \u2717 Upgrade failed: ${result.error}`));
29005
+ process.exit(1);
29006
+ }
29007
+ console.log("");
29008
+ console.log(source_default.bold(" Step 2 \u2014 Waiting for Cortex API to be healthy..."));
29009
+ const config2 = readConfig();
29010
+ const cortexUrl = config2.url ?? "http://localhost:8082";
29011
+ const { healthy } = await waitForCortexHealth(cortexUrl, 12e4);
29012
+ console.log("");
29013
+ if (healthy) {
29014
+ console.log(source_default.green(" \u2713 Cortex API is healthy"));
29015
+ console.log("");
29016
+ console.log(source_default.bold(" \u25C6 Upgrade complete!"));
29017
+ console.log(source_default.dim(` API running at ${cortexUrl}`));
29018
+ console.log("");
29019
+ } else {
29020
+ console.log(
29021
+ source_default.yellow(
29022
+ " \u26A0 Container is up but did not become healthy within 120s"
29023
+ )
29024
+ );
29025
+ console.log(source_default.dim(" Check container logs:"));
29026
+ console.log(
29027
+ source_default.cyan(
29028
+ ` docker compose -f ${workDir}/docker-compose.local.yml logs cortex-api`
29029
+ )
29030
+ );
29031
+ console.log("");
29032
+ process.exit(1);
29033
+ }
29034
+ }
29035
+
29036
+ // src/cli.ts
29037
+ var import_fs16 = require("fs");
29038
+ var import_path17 = require("path");
28840
29039
  var pkg = JSON.parse(
28841
- (0, import_fs15.readFileSync)((0, import_path16.join)(__dirname, "..", "package.json"), "utf-8")
29040
+ (0, import_fs16.readFileSync)((0, import_path17.join)(__dirname, "..", "package.json"), "utf-8")
28842
29041
  );
28843
29042
  function createCli() {
28844
29043
  const program3 = new Command();
@@ -28892,6 +29091,15 @@ function createCli() {
28892
29091
  "--set <value>",
28893
29092
  "Set a specific token value (empty string clears auth)"
28894
29093
  ).action(tokenCommand);
29094
+ program3.command("upgrade").description(
29095
+ "Pull the latest Cortex backend image and restart the local stack"
29096
+ ).option(
29097
+ "--dir <path>",
29098
+ "Directory with docker-compose.local.yml (defaults to ~/.cortex-context)"
29099
+ ).option("--embeddings", "Use the embeddings-enabled image variant").option(
29100
+ "--pull-only",
29101
+ "Pull the latest image without recreating the container"
29102
+ ).action(upgradeCommand);
28895
29103
  return program3;
28896
29104
  }
28897
29105