metheus-governance-mcp-cli 0.2.20 → 0.2.22

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/cli.mjs +99 -27
  2. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -1913,7 +1913,7 @@ async function runDoctor(flags) {
1913
1913
  );
1914
1914
 
1915
1915
  const syncStatus = String(summary.ctxpack_sync_status || "").trim();
1916
- if (["downloaded", "updated", "current"].includes(syncStatus)) {
1916
+ if (["downloaded", "updated", "current", "home_fallback"].includes(syncStatus)) {
1917
1917
  addDoctorCheck(
1918
1918
  rows,
1919
1919
  "ok",
@@ -2489,20 +2489,15 @@ function syncCtxpackToLocalCache({
2489
2489
  const status = String(ctxpack?.status || "").trim() || "draft";
2490
2490
  const files = normalizeCtxpackFiles(ctxpack?.files);
2491
2491
  const resolvedWorkspaceDir = resolveWorkspaceDir(workspaceDir);
2492
- const cacheDir = path.join(ctxpackCacheRootDir(resolvedWorkspaceDir), projectID);
2492
+ const isHomeFallback = isHomeWorkspaceRoot(resolvedWorkspaceDir) && !allowHomeWorkspaceRoot();
2493
+ const cacheDir = path.join(
2494
+ isHomeFallback ? homeCtxpackCacheRootDir() : ctxpackCacheRootDir(resolvedWorkspaceDir),
2495
+ projectID,
2496
+ );
2493
2497
  const metaPath = path.join(cacheDir, CTXPACK_META_FILENAME);
2494
- const workspaceMetaPath = path.join(resolvedWorkspaceDir, CTXPACK_META_FILENAME);
2495
-
2496
- if (isHomeWorkspaceRoot(resolvedWorkspaceDir) && !allowHomeWorkspaceRoot()) {
2497
- return {
2498
- sync_status: "guarded",
2499
- sync_message:
2500
- "Workspace root resolved to home directory. Guardrail blocked ctxpack local write. Use --workspace-dir <project_path> or --workspace-dir auto.",
2501
- local_path: cacheDir,
2502
- workspace_path: resolvedWorkspaceDir,
2503
- local_file_count: 0,
2504
- };
2505
- }
2498
+ const workspaceMetaPath = isHomeFallback
2499
+ ? metaPath
2500
+ : path.join(resolvedWorkspaceDir, CTXPACK_META_FILENAME);
2506
2501
 
2507
2502
  if (!workspaceSignalTrusted) {
2508
2503
  return {
@@ -2549,8 +2544,10 @@ function syncCtxpackToLocalCache({
2549
2544
  // Best-effort metadata refresh for workspace-root auto-detection.
2550
2545
  }
2551
2546
  return {
2552
- sync_status: "current",
2553
- sync_message: "Local ctxpack cache is up to date.",
2547
+ sync_status: isHomeFallback ? "home_fallback" : "current",
2548
+ sync_message: isHomeFallback
2549
+ ? "Ctxpack cached in home directory. Workspace was not detected; use --workspace-dir for project-local cache."
2550
+ : "Local ctxpack cache is up to date.",
2554
2551
  local_path: cacheDir,
2555
2552
  workspace_path: resolvedWorkspaceDir,
2556
2553
  local_file_count: files.length,
@@ -2571,10 +2568,12 @@ function syncCtxpackToLocalCache({
2571
2568
  fs.writeFileSync(workspaceMetaPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
2572
2569
 
2573
2570
  return {
2574
- sync_status: previousMeta ? "updated" : "downloaded",
2575
- sync_message: previousMeta
2576
- ? "Ctxpack updated to latest server version."
2577
- : "Ctxpack downloaded to local cache.",
2571
+ sync_status: isHomeFallback ? "home_fallback" : (previousMeta ? "updated" : "downloaded"),
2572
+ sync_message: isHomeFallback
2573
+ ? "Ctxpack cached in home directory. Workspace was not detected; use --workspace-dir for project-local cache."
2574
+ : (previousMeta
2575
+ ? "Ctxpack updated to latest server version."
2576
+ : "Ctxpack downloaded to local cache."),
2578
2577
  local_path: cacheDir,
2579
2578
  workspace_path: resolvedWorkspaceDir,
2580
2579
  local_file_count: files.length,
@@ -4126,11 +4125,18 @@ function tryRegister(cliBin, serverName, proxyArgs, options = {}) {
4126
4125
  cliBin === "codex" && workspaceEnv
4127
4126
  ? ["--env", `METHEUS_WORKSPACE_DIR=${workspaceEnv}`]
4128
4127
  : [];
4129
- const attempts = [];
4130
4128
  if (codexEnvArgs.length > 0) {
4131
- attempts.push([...baseAddArgs, ...codexEnvArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs]);
4132
- attempts.push([...baseAddArgs, ...codexEnvArgs, process.execPath, selfPath, "proxy", ...proxyArgs]);
4129
+ const envAttempts = [];
4130
+ envAttempts.push([...baseAddArgs, ...codexEnvArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs]);
4131
+ envAttempts.push([...baseAddArgs, ...codexEnvArgs, process.execPath, selfPath, "proxy", ...proxyArgs]);
4132
+ for (const args of envAttempts) {
4133
+ const run = runCLICommand(cliBin, args, { stdio: "inherit" });
4134
+ if (run.status === 0) return true;
4135
+ }
4136
+ // Do not silently downgrade to no-env registration when fallback env was requested.
4137
+ return false;
4133
4138
  }
4139
+ const attempts = [];
4134
4140
  attempts.push([...baseAddArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs]);
4135
4141
  attempts.push([...baseAddArgs, process.execPath, selfPath, "proxy", ...proxyArgs]);
4136
4142
  for (const args of attempts) {
@@ -4162,6 +4168,44 @@ function isRegistered(cliBin, serverName) {
4162
4168
  return run.status === 0;
4163
4169
  }
4164
4170
 
4171
+ function getRegisteredTransport(cliBin, serverName) {
4172
+ if (cliBin !== "codex") return null;
4173
+ const run = runCLICommand(cliBin, ["mcp", "get", serverName, "--json"], { stdio: "pipe" });
4174
+ if (run.status !== 0) return null;
4175
+ const parsed = tryJsonParse(String(run.stdout || ""));
4176
+ const transport = safeObject(parsed?.transport);
4177
+ if (!transport.type) return null;
4178
+ return transport;
4179
+ }
4180
+
4181
+ function extractWorkspaceDirArg(args) {
4182
+ if (!Array.isArray(args)) return "";
4183
+ for (let i = 0; i < args.length; i += 1) {
4184
+ if (String(args[i] || "").trim() !== "--workspace-dir") continue;
4185
+ return String(args[i + 1] || "").trim();
4186
+ }
4187
+ return "";
4188
+ }
4189
+
4190
+ function withWorkspaceDirArg(args, workspaceDir) {
4191
+ const next = [];
4192
+ let replaced = false;
4193
+ for (let i = 0; i < args.length; i += 1) {
4194
+ const token = String(args[i] || "").trim();
4195
+ if (token !== "--workspace-dir") {
4196
+ next.push(args[i]);
4197
+ continue;
4198
+ }
4199
+ next.push("--workspace-dir", workspaceDir);
4200
+ i += 1;
4201
+ replaced = true;
4202
+ }
4203
+ if (!replaced) {
4204
+ next.push("--workspace-dir", workspaceDir);
4205
+ }
4206
+ return next;
4207
+ }
4208
+
4165
4209
  function resolveSetupContext(flags) {
4166
4210
  const workspaceMeta = loadWorkspaceMeta(process.cwd());
4167
4211
  const projectID = String(flags["project-id"] || workspaceMeta.project_id || "").trim();
@@ -4170,6 +4214,8 @@ function resolveSetupContext(flags) {
4170
4214
  const workspaceDirRaw = String(flags["workspace-dir"] || "").trim();
4171
4215
  const workspaceFallbackDirRaw = String(flags["workspace-fallback-dir"] || "").trim();
4172
4216
  const hasWorkspaceDirFlag = Object.prototype.hasOwnProperty.call(flags, "workspace-dir");
4217
+ const hasWorkspaceFallbackDirFlag = Object.prototype.hasOwnProperty.call(flags, "workspace-fallback-dir");
4218
+ const hasAnySetupOverride = Object.keys(safeObject(flags)).length > 0;
4173
4219
  // Default to auto workspace mode for safer multi-project Codex sessions.
4174
4220
  const workspaceAutoMode = !hasWorkspaceDirFlag || isAutoWorkspaceMode(workspaceDirRaw);
4175
4221
  // Pin only when user explicitly set a non-auto workspace-dir.
@@ -4195,6 +4241,9 @@ function resolveSetupContext(flags) {
4195
4241
  baseURL,
4196
4242
  workspaceDir,
4197
4243
  workspaceFallbackDir,
4244
+ hasWorkspaceDirFlag,
4245
+ hasWorkspaceFallbackDirFlag,
4246
+ hasAnySetupOverride,
4198
4247
  shouldPinWorkspaceDir,
4199
4248
  workspaceAutoMode,
4200
4249
  serverName,
@@ -4211,13 +4260,36 @@ function runSetupInternal(flags, options = {}) {
4211
4260
  for (const cliBin of clients) {
4212
4261
  if (!commandExists(cliBin)) continue;
4213
4262
  const alreadyRegistered = isRegistered(cliBin, context.serverName);
4263
+ if (ensureOnly && alreadyRegistered && !context.hasAnySetupOverride) {
4264
+ results.push({ cliBin, ok: true, action: "kept" });
4265
+ continue;
4266
+ }
4267
+
4268
+ let proxyArgsForRegister = [...context.proxyArgs];
4269
+ let workspaceEnvForRegister = context.shouldPinWorkspaceDir
4270
+ ? context.workspaceDir
4271
+ : context.workspaceFallbackDir;
4272
+
4273
+ if (cliBin === "codex" && !context.hasWorkspaceDirFlag && !context.hasWorkspaceFallbackDirFlag) {
4274
+ const transport = getRegisteredTransport(cliBin, context.serverName);
4275
+ if (transport) {
4276
+ const existingWorkspaceDir = extractWorkspaceDirArg(transport.args);
4277
+ const existingEnv = safeObject(transport.env);
4278
+ const existingWorkspaceEnv = String(existingEnv.METHEUS_WORKSPACE_DIR || "").trim();
4279
+ if (existingWorkspaceDir && !isAutoWorkspaceMode(existingWorkspaceDir)) {
4280
+ proxyArgsForRegister = withWorkspaceDirArg(proxyArgsForRegister, existingWorkspaceDir);
4281
+ workspaceEnvForRegister = "";
4282
+ } else if (!workspaceEnvForRegister && existingWorkspaceEnv) {
4283
+ workspaceEnvForRegister = resolveWorkspaceDir(existingWorkspaceEnv);
4284
+ }
4285
+ }
4286
+ }
4287
+
4214
4288
  if (!ensureOnly || alreadyRegistered) {
4215
4289
  runRemove(cliBin, context.serverName);
4216
4290
  }
4217
- const ok = tryRegister(cliBin, context.serverName, context.proxyArgs, {
4218
- workspaceDir: context.shouldPinWorkspaceDir
4219
- ? context.workspaceDir
4220
- : context.workspaceFallbackDir,
4291
+ const ok = tryRegister(cliBin, context.serverName, proxyArgsForRegister, {
4292
+ workspaceDir: workspaceEnvForRegister,
4221
4293
  });
4222
4294
  const action = ensureOnly
4223
4295
  ? alreadyRegistered
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [