@jentrix/cli 0.5.6 → 0.5.8

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 (2) hide show
  1. package/dist/main.js +135 -61
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -6418,7 +6418,7 @@ var require_compile = __commonJS({
6418
6418
  const schOrFunc = root.refs[ref];
6419
6419
  if (schOrFunc)
6420
6420
  return schOrFunc;
6421
- let _sch = resolve4.call(this, root, ref);
6421
+ let _sch = resolve5.call(this, root, ref);
6422
6422
  if (_sch === void 0) {
6423
6423
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
6424
6424
  const { schemaId } = this.opts;
@@ -6445,7 +6445,7 @@ var require_compile = __commonJS({
6445
6445
  function sameSchemaEnv(s1, s2) {
6446
6446
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
6447
6447
  }
6448
- function resolve4(root, ref) {
6448
+ function resolve5(root, ref) {
6449
6449
  let sch;
6450
6450
  while (typeof (sch = this.refs[ref]) == "string")
6451
6451
  ref = sch;
@@ -7076,7 +7076,7 @@ var require_fast_uri = __commonJS({
7076
7076
  }
7077
7077
  return uri;
7078
7078
  }
7079
- function resolve4(baseURI, relativeURI, options) {
7079
+ function resolve5(baseURI, relativeURI, options) {
7080
7080
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
7081
7081
  const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
7082
7082
  schemelessOptions.skipEscape = true;
@@ -7334,7 +7334,7 @@ var require_fast_uri = __commonJS({
7334
7334
  var fastUri = {
7335
7335
  SCHEMES,
7336
7336
  normalize,
7337
- resolve: resolve4,
7337
+ resolve: resolve5,
7338
7338
  resolveComponent,
7339
7339
  equal,
7340
7340
  serialize,
@@ -10337,7 +10337,7 @@ import {
10337
10337
  statSync as statSync3
10338
10338
  } from "node:fs";
10339
10339
  import { homedir } from "node:os";
10340
- import { basename as basename2, dirname as dirname4, join as join6 } from "node:path";
10340
+ import { basename as basename2, delimiter as delimiter2, dirname as dirname4, join as join6, resolve as resolve4 } from "node:path";
10341
10341
  import { fileURLToPath } from "node:url";
10342
10342
 
10343
10343
  // node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
@@ -17873,7 +17873,7 @@ var Protocol = class {
17873
17873
  return;
17874
17874
  }
17875
17875
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
17876
- await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
17876
+ await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
17877
17877
  options?.signal?.throwIfAborted();
17878
17878
  }
17879
17879
  } catch (error2) {
@@ -17890,7 +17890,7 @@ var Protocol = class {
17890
17890
  */
17891
17891
  request(request, resultSchema, options) {
17892
17892
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
17893
- return new Promise((resolve4, reject) => {
17893
+ return new Promise((resolve5, reject) => {
17894
17894
  const earlyReject = (error2) => {
17895
17895
  reject(error2);
17896
17896
  };
@@ -17968,7 +17968,7 @@ var Protocol = class {
17968
17968
  if (!parseResult.success) {
17969
17969
  reject(parseResult.error);
17970
17970
  } else {
17971
- resolve4(parseResult.data);
17971
+ resolve5(parseResult.data);
17972
17972
  }
17973
17973
  } catch (error2) {
17974
17974
  reject(error2);
@@ -18229,12 +18229,12 @@ var Protocol = class {
18229
18229
  }
18230
18230
  } catch {
18231
18231
  }
18232
- return new Promise((resolve4, reject) => {
18232
+ return new Promise((resolve5, reject) => {
18233
18233
  if (signal.aborted) {
18234
18234
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
18235
18235
  return;
18236
18236
  }
18237
- const timeoutId = setTimeout(resolve4, interval);
18237
+ const timeoutId = setTimeout(resolve5, interval);
18238
18238
  signal.addEventListener("abort", () => {
18239
18239
  clearTimeout(timeoutId);
18240
18240
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -20962,7 +20962,7 @@ function refreshAccessToken(input) {
20962
20962
 
20963
20963
  // src/client.ts
20964
20964
  var CLI_NAME = "stacks-cli";
20965
- var CLI_VERSION = "0.5.6";
20965
+ var CLI_VERSION = "0.5.8";
20966
20966
  var DEAD_TOKEN_MESSAGE = "authentication failed (HTTP 401): the token is dead or expired \u2014 mint a new PAT at /account/tokens on your Jentrix server and update STACKS_TOKEN (or --token / the config file).";
20967
20967
  var RELOGIN_MESSAGE = "OAuth session expired and could not be refreshed \u2014 run `jentrix login` to sign in again.";
20968
20968
  function originOf2(url2) {
@@ -21117,6 +21117,17 @@ function execTarget(file, args, platform2 = process.platform, comSpec = process.
21117
21117
  options: { windowsVerbatimArguments: true }
21118
21118
  };
21119
21119
  }
21120
+ function browserTarget(url2, platform2 = process.platform, comSpec = process.env.ComSpec) {
21121
+ if (platform2 === "darwin") return { file: "open", args: [url2], options: {} };
21122
+ if (platform2 !== "win32") {
21123
+ return { file: "xdg-open", args: [url2], options: {} };
21124
+ }
21125
+ return {
21126
+ file: comSpec || "cmd.exe",
21127
+ args: ["/d", "/s", "/c", `"start "" ${quoteForCmd(url2)}"`],
21128
+ options: { windowsVerbatimArguments: true }
21129
+ };
21130
+ }
21120
21131
 
21121
21132
  // src/loopback.ts
21122
21133
  import { createServer } from "node:http";
@@ -21130,7 +21141,7 @@ function escapeHtml(s) {
21130
21141
  );
21131
21142
  }
21132
21143
  function tryBindPort(port, timeoutMs = CALLBACK_TIMEOUT_MS) {
21133
- return new Promise((resolve4) => {
21144
+ return new Promise((resolve5) => {
21134
21145
  let settleCode = null;
21135
21146
  let rejectCode = null;
21136
21147
  let timer = null;
@@ -21155,9 +21166,9 @@ function tryBindPort(port, timeoutMs = CALLBACK_TIMEOUT_MS) {
21155
21166
  rejectCode?.(new Error("callback had no authorization code"));
21156
21167
  else settleCode?.({ code, state: url2.searchParams.get("state") });
21157
21168
  });
21158
- server.once("error", () => resolve4(null));
21169
+ server.once("error", () => resolve5(null));
21159
21170
  server.listen(port, LOOPBACK_HOST, () => {
21160
- resolve4({
21171
+ resolve5({
21161
21172
  port,
21162
21173
  waitForCode: () => new Promise((res, rej) => {
21163
21174
  settleCode = res;
@@ -21184,17 +21195,19 @@ async function bindLoopback(ports, timeoutMs = CALLBACK_TIMEOUT_MS) {
21184
21195
  return null;
21185
21196
  }
21186
21197
  function openBrowser(url2) {
21187
- return new Promise((resolve4) => {
21188
- const os = platform();
21189
- const cmd = os === "darwin" ? "open" : os === "win32" ? "cmd" : "xdg-open";
21190
- const args = os === "win32" ? ["/c", "start", "", url2] : [url2];
21198
+ return new Promise((resolve5) => {
21199
+ const { file, args, options } = browserTarget(url2, platform());
21191
21200
  try {
21192
- const child = spawn(cmd, args, { stdio: "ignore", detached: true });
21193
- child.on("error", () => resolve4());
21201
+ const child = spawn(file, args, {
21202
+ stdio: "ignore",
21203
+ detached: true,
21204
+ ...options
21205
+ });
21206
+ child.on("error", () => resolve5());
21194
21207
  child.unref();
21195
21208
  } catch {
21196
21209
  }
21197
- resolve4();
21210
+ resolve5();
21198
21211
  });
21199
21212
  }
21200
21213
 
@@ -21747,13 +21760,13 @@ function normalizeRemoteRepo(url2) {
21747
21760
  if (trimmed.length < 2) return null;
21748
21761
  return `${trimmed[0]}/${trimmed[1]}`.toLowerCase();
21749
21762
  }
21750
- var defaultGitRunner = (args, cwd) => new Promise((resolve4) => {
21763
+ var defaultGitRunner = (args, cwd) => new Promise((resolve5) => {
21751
21764
  execFile(
21752
21765
  "git",
21753
21766
  args,
21754
21767
  { cwd, timeout: 1e4, maxBuffer: 4 * 1024 * 1024, windowsHide: true },
21755
21768
  (error2, stdout) => {
21756
- resolve4({
21769
+ resolve5({
21757
21770
  code: error2 === null ? 0 : typeof error2.code === "number" ? Number(error2.code) : 1,
21758
21771
  stdout: String(stdout)
21759
21772
  });
@@ -27905,9 +27918,12 @@ function say(deps2, text = "") {
27905
27918
  }
27906
27919
  async function installToolchain(deps2) {
27907
27920
  const npm = await deps2.resolveNpm();
27908
- const existing = await deps2.resolveJentrix();
27909
- if (existing) {
27910
- say(deps2, `jentrix ${CLI_VERSION} is already installed (${existing}).`);
27921
+ let global = await deps2.globalInstall();
27922
+ if (global.cliDir) {
27923
+ say(
27924
+ deps2,
27925
+ `jentrix ${CLI_VERSION} is already installed (${global.cliDir}).`
27926
+ );
27911
27927
  say(deps2, " Upgrade it any time with: npm update -g @jentrix/cli");
27912
27928
  } else {
27913
27929
  if (!npm) {
@@ -27934,15 +27950,16 @@ async function installToolchain(deps2) {
27934
27950
  );
27935
27951
  return EXIT_CODES.INTERNAL;
27936
27952
  }
27937
- if (!await deps2.resolveJentrix()) {
27953
+ global = await deps2.globalInstall();
27954
+ if (!global.cliDir) {
27938
27955
  deps2.writeErr(
27939
- "TOOLCHAIN_NOT_ON_PATH: the packages installed but `jentrix` is not resolvable \u2014 add npm's global bin directory (`npm prefix -g`) to PATH, then retry."
27956
+ "TOOLCHAIN_INSTALL_FAILED: npm reported success but @jentrix/cli is not under `npm root -g` \u2014 check npm's global prefix, then retry."
27940
27957
  );
27941
27958
  return EXIT_CODES.INTERNAL;
27942
27959
  }
27943
27960
  say(deps2, "Installed the CLI and the session runner.");
27944
27961
  }
27945
- if (!await deps2.resolveRunner()) {
27962
+ if (!global.runnerDir) {
27946
27963
  if (!npm) {
27947
27964
  deps2.writeErr(
27948
27965
  `RUNNER_NOT_INSTALLED: connected sessions need the runner and npm was not found to install it \u2014 npm install -g ${RUNNER_SPEC2}, then retry.`
@@ -27956,41 +27973,56 @@ async function installToolchain(deps2) {
27956
27973
  void 0,
27957
27974
  NPM_INSTALL_TIMEOUT_MS2
27958
27975
  );
27959
- if (runner.code !== 0 || !await deps2.resolveRunner()) {
27976
+ global = await deps2.globalInstall();
27977
+ if (runner.code !== 0 || !global.runnerDir) {
27960
27978
  deps2.writeErr(
27961
- `RUNNER_NOT_INSTALLED: \`npm install -g ${RUNNER_SPEC2}\` did not leave a resolvable runner \u2014 install it by hand, then retry.`
27979
+ `RUNNER_NOT_INSTALLED: \`npm install -g ${RUNNER_SPEC2}\` did not leave the runner under \`npm root -g\` \u2014 install it by hand, then retry.`
27962
27980
  );
27963
27981
  return EXIT_CODES.INTERNAL;
27964
27982
  }
27965
27983
  }
27966
- return EXIT_CODES.OK;
27967
- }
27968
- async function installRuntimes(deps2) {
27969
- if (await deps2.resolveClaude()) {
27970
- await deps2.installPlugin("claude");
27971
- } else {
27972
- say(deps2, "note: the `claude` CLI is not installed \u2014 skipped its plugin.");
27984
+ if (global.binDir && !global.binDirOnPath) {
27985
+ say(deps2, "");
27986
+ say(deps2, "note: npm's global bin directory is NOT on your PATH \u2014");
27987
+ say(deps2, ` ${global.binDir}`);
27973
27988
  say(
27974
27989
  deps2,
27975
- " Install Claude Code (https://claude.com/claude-code), then run: jentrix plugin install"
27990
+ " The toolchain is installed, but `jentrix` will not be found in a new"
27976
27991
  );
27977
- }
27978
- if (await deps2.resolveCodex()) {
27979
- if (await deps2.installPlugin("codex") !== EXIT_CODES.OK) {
27980
- say(
27981
- deps2,
27982
- "note: `jentrix plugin install codex` did not complete \u2014 retry it after `jentrix login`."
27983
- );
27984
- }
27985
- } else {
27986
27992
  say(
27987
27993
  deps2,
27988
- "note: the `codex` CLI is not installed \u2014 skipped its plugin and MCP server."
27994
+ " terminal until you add that directory to PATH and reopen your shell."
27989
27995
  );
27990
- say(
27991
- deps2,
27996
+ }
27997
+ return EXIT_CODES.OK;
27998
+ }
27999
+ var RUNTIMES = [
28000
+ {
28001
+ provider: "claude",
28002
+ resolve: (deps2) => deps2.resolveClaude(),
28003
+ absent: [
28004
+ "note: the `claude` CLI is not installed \u2014 skipped its plugin.",
28005
+ " Install Claude Code (https://claude.com/claude-code), then run: jentrix plugin install"
28006
+ ]
28007
+ },
28008
+ {
28009
+ provider: "codex",
28010
+ resolve: (deps2) => deps2.resolveCodex(),
28011
+ absent: [
28012
+ "note: the `codex` CLI is not installed \u2014 skipped its plugin and MCP server.",
27992
28013
  " Install Codex (https://developers.openai.com/codex/cli), then re-run this command."
27993
- );
28014
+ ]
28015
+ }
28016
+ ];
28017
+ async function installRuntimes(deps2, pending) {
28018
+ for (const runtime of RUNTIMES) {
28019
+ if (!await runtime.resolve(deps2)) {
28020
+ for (const line of runtime.absent) say(deps2, line);
28021
+ continue;
28022
+ }
28023
+ if (await deps2.installPlugin(runtime.provider) !== EXIT_CODES.OK) {
28024
+ pending.failedPlugins.push(runtime.provider);
28025
+ }
27994
28026
  }
27995
28027
  }
27996
28028
  async function registerCodexMcp(deps2, codex, pending) {
@@ -28118,7 +28150,8 @@ async function runSetupCommand(flags, deps2) {
28118
28150
  }
28119
28151
  const toolchain = await installToolchain(deps2);
28120
28152
  if (toolchain !== EXIT_CODES.OK) return toolchain;
28121
- await installRuntimes(deps2);
28153
+ const pending = { failedPlugins: [] };
28154
+ await installRuntimes(deps2, pending);
28122
28155
  if (!deps2.hasCredential()) {
28123
28156
  if (deps2.isInteractive) {
28124
28157
  say(deps2, "");
@@ -28136,13 +28169,25 @@ async function runSetupCommand(flags, deps2) {
28136
28169
  );
28137
28170
  }
28138
28171
  }
28139
- const pending = {};
28140
28172
  const codex = await deps2.resolveCodex();
28141
28173
  if (codex) await registerCodexMcp(deps2, codex, pending);
28142
28174
  if (flags.git !== false && deps2.isInteractive && deps2.cwd() !== deps2.homeDir()) {
28143
28175
  await bootstrapRepository(deps2);
28144
28176
  }
28145
28177
  say(deps2, "");
28178
+ if (pending.failedPlugins.length) {
28179
+ for (const provider of pending.failedPlugins) {
28180
+ say(
28181
+ deps2,
28182
+ `note: the ${provider} plugin did NOT install \u2014 its commands will be missing.`
28183
+ );
28184
+ say(
28185
+ deps2,
28186
+ ` Run \`jentrix plugin install ${provider}\` on its own to see why.`
28187
+ );
28188
+ }
28189
+ say(deps2, "");
28190
+ }
28146
28191
  say(deps2, "Done. Verify with: jentrix whoami");
28147
28192
  if (pending.codexLoginUrl) {
28148
28193
  say(deps2, "");
@@ -28185,7 +28230,7 @@ async function runSetupCommand(flags, deps2) {
28185
28230
  deps2,
28186
28231
  "(Bind a folder to a different server any time with: jentrix login --local)"
28187
28232
  );
28188
- return EXIT_CODES.OK;
28233
+ return pending.failedPlugins.length ? EXIT_CODES.INTERNAL : EXIT_CODES.OK;
28189
28234
  }
28190
28235
  function registerSetupCommand(program3, deps2, onExit2) {
28191
28236
  return program3.command("setup").description(
@@ -28539,12 +28584,12 @@ function surfaceFileMtime() {
28539
28584
  }
28540
28585
  }
28541
28586
  function readStdin() {
28542
- return new Promise((resolve4, reject) => {
28587
+ return new Promise((resolve5, reject) => {
28543
28588
  const chunks = [];
28544
28589
  process.stdin.on("data", (chunk) => chunks.push(chunk));
28545
28590
  process.stdin.on(
28546
28591
  "end",
28547
- () => resolve4(Buffer.concat(chunks).toString("utf8"))
28592
+ () => resolve5(Buffer.concat(chunks).toString("utf8"))
28548
28593
  );
28549
28594
  process.stdin.on("error", reject);
28550
28595
  });
@@ -28555,14 +28600,14 @@ function configFile() {
28555
28600
  return readConfigFile(CONFIG_PATH);
28556
28601
  }
28557
28602
  function readLine(prompt) {
28558
- return new Promise((resolve4) => {
28603
+ return new Promise((resolve5) => {
28559
28604
  const rl = createInterface({
28560
28605
  input: process.stdin,
28561
28606
  output: process.stdout
28562
28607
  });
28563
28608
  rl.question(prompt, (answer) => {
28564
28609
  rl.close();
28565
- resolve4(answer);
28610
+ resolve5(answer);
28566
28611
  });
28567
28612
  });
28568
28613
  }
@@ -28620,7 +28665,7 @@ var deps = {
28620
28665
  `),
28621
28666
  writeErr: (text) => process.stderr.write(`${text}
28622
28667
  `),
28623
- sleep: (ms) => new Promise((resolve4) => setTimeout(resolve4, ms)),
28668
+ sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms)),
28624
28669
  now: () => Date.now()
28625
28670
  };
28626
28671
  var loginDeps = {
@@ -28810,7 +28855,36 @@ registerSetupCommand(
28810
28855
  program2,
28811
28856
  {
28812
28857
  ...pluginDeps,
28813
- resolveJentrix: () => resolveExecutableOnPath(platformExecutableNames("jentrix"), process.env),
28858
+ // npm's global prefix, read from npm itself — never a PATH probe. Under
28859
+ // `npx @jentrix/cli setup` the _npx cache is prepended to PATH and holds a
28860
+ // `jentrix` shim, so a PATH answer is always yes and always meaningless.
28861
+ globalInstall: async () => {
28862
+ const npm = await resolveExecutableOnPath(
28863
+ platformExecutableNames("npm"),
28864
+ process.env
28865
+ );
28866
+ const ask = async (args) => {
28867
+ if (!npm) return null;
28868
+ const out = (await invokeRunnerProcess(npm, args)).stdout.trim();
28869
+ return out || null;
28870
+ };
28871
+ const root = await ask(["root", "-g"]);
28872
+ const prefix = await ask(["prefix", "-g"]);
28873
+ const binDir = prefix ? process.platform === "win32" ? prefix : join6(prefix, "bin") : null;
28874
+ const dir = (name) => {
28875
+ if (!root) return null;
28876
+ const candidate = join6(root, "@jentrix", name);
28877
+ return existsSync6(join6(candidate, "package.json")) ? candidate : null;
28878
+ };
28879
+ return {
28880
+ cliDir: dir("cli"),
28881
+ runnerDir: dir("runner"),
28882
+ binDir,
28883
+ binDirOnPath: Boolean(
28884
+ binDir && (process.env.PATH ?? "").split(delimiter2).some((entry) => entry && resolve4(entry) === resolve4(binDir))
28885
+ )
28886
+ };
28887
+ },
28814
28888
  resolveGit: () => resolveExecutableOnPath(platformExecutableNames("git"), process.env),
28815
28889
  // Register the plugin from whichever copy of the package PERSISTS. Under
28816
28890
  // `npx @jentrix/cli setup` the running module lives in npm's _npx cache,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jentrix/cli",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Command-line client for the Jentrix MCP surface (jentrix tool <name>, generated noun-verb commands).",
5
5
  "keywords": [
6
6
  "jentrix",