metheus-governance-mcp-cli 0.2.16 → 0.2.18

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 (3) hide show
  1. package/README.md +13 -2
  2. package/cli.mjs +130 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -37,6 +37,8 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
37
37
  ```
38
38
 
39
39
  `project-id` can be omitted if your current folder (or parent) has `.metheus_ctxpack_sync.json`.
40
+ `setup` defaults to `--workspace-dir auto` (dynamic workspace detection).
41
+ Use an explicit path only when you intentionally want a fixed workspace.
40
42
 
41
43
  Recommended for Codex/Claude multi-workspace sessions:
42
44
 
@@ -44,6 +46,15 @@ Recommended for Codex/Claude multi-workspace sessions:
44
46
  metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctxpack_key>" --base-url https://metheus.gesiaplatform.com --workspace-dir auto
45
47
  ```
46
48
 
49
+ When a client does not send workspace metadata (for example some Codex sessions),
50
+ set a stable fallback root once:
51
+
52
+ ```bash
53
+ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctxpack_key>" --base-url https://metheus.gesiaplatform.com --workspace-dir auto --workspace-fallback-dir C:\code_test
54
+ ```
55
+
56
+ This registers `METHEUS_WORKSPACE_DIR` for Codex MCP so ctxpack sync still resolves safely.
57
+
47
58
  Guardrail note:
48
59
  - By default, CLI blocks reading/writing ctxpack sync metadata when workspace root resolves to the home directory.
49
60
  - Override only when intentional: `METHEUS_ALLOW_HOME_WORKSPACE=1`.
@@ -93,8 +104,8 @@ These tools accept `project_id` and return:
93
104
  - missing local cache -> download
94
105
  - same version -> keep current
95
106
  - newer server version -> update local cache
96
- - workspace path -> pinned to setup/proxy working directory by default
97
- - use `--workspace-dir auto` to follow active client workspace/root dynamically
107
+ - workspace path -> auto-detected from client metadata/env by default
108
+ - use `--workspace-fallback-dir <path>` when client metadata is unavailable
98
109
 
99
110
  Ctxpack merge safety flow:
100
111
  - call `ctxpack.merge.brief` first
package/cli.mjs CHANGED
@@ -38,7 +38,7 @@ function printUsage() {
38
38
  "Usage:",
39
39
  ` ${cmd} [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--flow <auto|device|callback|manual>]`,
40
40
  ` ${cmd} init [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--flow <auto|device|callback|manual>]`,
41
- ` ${cmd} setup [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--name <server_name>]`,
41
+ ` ${cmd} setup [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--workspace-fallback-dir <path>] [--name <server_name>]`,
42
42
  ` ${cmd} doctor [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--timeout-seconds <n>]`,
43
43
  ` ${cmd} proxy [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--include-drafts <true|false>] [--auto-pull-on-conflict <true|false>] [--timeout-seconds <n>]`,
44
44
  ` ${cmd} ctxpack pull [--project-id <uuid>] [--base-url <url>] [--workspace-dir <path|auto>] [--paths <csv>] [--timeout-seconds <n>]`,
@@ -365,7 +365,7 @@ function extractWorkspaceCandidateFromFolders(rawFolders) {
365
365
  return "";
366
366
  }
367
367
 
368
- function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
368
+ function extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs) {
369
369
  const params = safeObject(requestObj?.params);
370
370
  const meta = safeObject(params._meta);
371
371
  const workspaceFromFolders = firstNonEmptyString([
@@ -381,13 +381,23 @@ function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
381
381
  args.workspaceDir,
382
382
  params.workspace_dir,
383
383
  params.workspaceDir,
384
+ meta.workspace_dir,
385
+ meta.workspaceDir,
386
+ ]);
387
+ return sanitizeWorkspaceCandidate(rawCandidate);
388
+ }
389
+
390
+ function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
391
+ const strongCandidate = extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs);
392
+ if (strongCandidate) return strongCandidate;
393
+ const params = safeObject(requestObj?.params);
394
+ const meta = safeObject(params._meta);
395
+ const rawCandidate = firstNonEmptyString([
384
396
  params.cwd,
385
397
  params.root_path,
386
398
  params.rootPath,
387
399
  params.root_uri,
388
400
  params.rootUri,
389
- meta.workspace_dir,
390
- meta.workspaceDir,
391
401
  meta.cwd,
392
402
  meta.root_path,
393
403
  meta.rootPath,
@@ -397,13 +407,22 @@ function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
397
407
  return sanitizeWorkspaceCandidate(rawCandidate);
398
408
  }
399
409
 
400
- function extractWorkspaceCandidateFromEnv() {
410
+ function extractStrongWorkspaceCandidateFromEnv() {
401
411
  const rawCandidate = firstNonEmptyString([
402
412
  process.env.METHEUS_WORKSPACE_DIR,
413
+ process.env.METHEUS_WORKSPACE_URI,
414
+ process.env.CODEX_WORKSPACE_DIR,
415
+ process.env.CODEX_WORKSPACE_URI,
403
416
  process.env.CLAUDE_WORKSPACE_DIR,
404
417
  process.env.CLAUDE_WORKSPACE_URI,
405
418
  process.env.CLAUDE_PROJECT_DIR,
406
- process.env.CODEX_WORKSPACE_DIR,
419
+ ]);
420
+ return sanitizeWorkspaceCandidate(rawCandidate);
421
+ }
422
+
423
+ function extractWorkspaceCandidateFromEnv() {
424
+ const rawCandidate = firstNonEmptyString([
425
+ extractStrongWorkspaceCandidateFromEnv(),
407
426
  process.env.WORKSPACE_DIR,
408
427
  process.env.WORKSPACE_FOLDER,
409
428
  process.env.VSCODE_WORKSPACE_FOLDER,
@@ -2436,7 +2455,13 @@ function hasAllCtxpackFiles(baseDir, files) {
2436
2455
  return true;
2437
2456
  }
2438
2457
 
2439
- function syncCtxpackToLocalCache({ siteBaseURL, projectID, ctxpack, workspaceDir }) {
2458
+ function syncCtxpackToLocalCache({
2459
+ siteBaseURL,
2460
+ projectID,
2461
+ ctxpack,
2462
+ workspaceDir,
2463
+ workspaceSignalTrusted = true,
2464
+ }) {
2440
2465
  const ctxpackID = String(ctxpack?.ctxpack_id || "").trim();
2441
2466
  const version = String(ctxpack?.version || "").trim();
2442
2467
  const versionID = String(ctxpack?.version_id || ctxpack?.current_version_id || "").trim();
@@ -2458,6 +2483,17 @@ function syncCtxpackToLocalCache({ siteBaseURL, projectID, ctxpack, workspaceDir
2458
2483
  };
2459
2484
  }
2460
2485
 
2486
+ if (!workspaceSignalTrusted) {
2487
+ return {
2488
+ sync_status: "guarded",
2489
+ sync_message:
2490
+ "Workspace signal is missing in auto mode. Guardrail blocked ctxpack local write to avoid wrong folder sync.",
2491
+ local_path: cacheDir,
2492
+ workspace_path: resolvedWorkspaceDir,
2493
+ local_file_count: 0,
2494
+ };
2495
+ }
2496
+
2461
2497
  if (!ctxpackID || !version || files.length === 0) {
2462
2498
  return {
2463
2499
  sync_status: "not_available",
@@ -2542,6 +2578,7 @@ async function loadProjectSummaryForTool({
2542
2578
  syncCtxpackLocal,
2543
2579
  workspaceDir,
2544
2580
  ctxpackPaths,
2581
+ workspaceSignalTrusted = true,
2545
2582
  }) {
2546
2583
  const encodedProjectID = encodeURIComponent(projectID);
2547
2584
  let projectRaw = null;
@@ -2607,6 +2644,7 @@ async function loadProjectSummaryForTool({
2607
2644
  projectID,
2608
2645
  ctxpack,
2609
2646
  workspaceDir,
2647
+ workspaceSignalTrusted,
2610
2648
  });
2611
2649
  ctxpackSyncStatus = syncResult.sync_status || "error";
2612
2650
  ctxpackSyncMessage = String(syncResult.sync_message || "").trim();
@@ -3267,6 +3305,7 @@ async function maybeAutoSyncCtxpackForCall({
3267
3305
  args,
3268
3306
  token,
3269
3307
  workspaceDir,
3308
+ workspaceSignalTrusted = true,
3270
3309
  }) {
3271
3310
  if (!isJsonRpcMethod(requestObj, "tools/call")) return null;
3272
3311
  if (!token) return null;
@@ -3298,6 +3337,7 @@ async function maybeAutoSyncCtxpackForCall({
3298
3337
  includeCtxpack: true,
3299
3338
  syncCtxpackLocal: true,
3300
3339
  workspaceDir: workspacePath,
3340
+ workspaceSignalTrusted,
3301
3341
  });
3302
3342
  } catch {
3303
3343
  return null;
@@ -3329,7 +3369,7 @@ function appendAutoCtxpackSyncHint(responseObj, summary) {
3329
3369
  return responseObj;
3330
3370
  }
3331
3371
 
3332
- async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
3372
+ async function appendWorkitemListHints(responseObj, args, toolArgs, token, workspaceSignalTrusted = true) {
3333
3373
  const result = safeObject(responseObj.result);
3334
3374
  const content = ensureArray(result.content);
3335
3375
  if (!content.length) return responseObj;
@@ -3388,6 +3428,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
3388
3428
  includeCtxpack: isEmptyBody,
3389
3429
  syncCtxpackLocal: isEmptyBody,
3390
3430
  workspaceDir: args.workspaceDir,
3431
+ workspaceSignalTrusted,
3391
3432
  });
3392
3433
  if (String(summary.access || "") === "granted") {
3393
3434
  nextLines.push("Project context:");
@@ -3425,7 +3466,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
3425
3466
  return responseObj;
3426
3467
  }
3427
3468
 
3428
- function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj) {
3469
+ function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj, workspaceSignalTrusted = true) {
3429
3470
  const result = safeObject(responseObj.result);
3430
3471
  const content = ensureArray(result.content);
3431
3472
  if (!content.length) return responseObj;
@@ -3459,6 +3500,7 @@ function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj) {
3459
3500
  projectID,
3460
3501
  ctxpack: body,
3461
3502
  workspaceDir,
3503
+ workspaceSignalTrusted,
3462
3504
  });
3463
3505
  const baseVersionID = firstNonEmptyString([body.base_version_id, body.version_id, body.current_version_id]);
3464
3506
  const currentVersionID = firstNonEmptyString([body.current_version_id, body.version_id, body.base_version_id]);
@@ -3616,7 +3658,15 @@ async function injectCtxpackPreflightToken(requestObj, toolName, toolArgs, args,
3616
3658
  }
3617
3659
  }
3618
3660
 
3619
- async function appendCtxpackConflictHintToErrorResponse(responseObj, args, toolName, toolArgs, token, workspaceDir) {
3661
+ async function appendCtxpackConflictHintToErrorResponse(
3662
+ responseObj,
3663
+ args,
3664
+ toolName,
3665
+ toolArgs,
3666
+ token,
3667
+ workspaceDir,
3668
+ workspaceSignalTrusted = true,
3669
+ ) {
3620
3670
  const out = safeObject(responseObj);
3621
3671
  const errObj = safeObject(out.error);
3622
3672
  const message = String(errObj.message || "").trim();
@@ -3648,6 +3698,7 @@ async function appendCtxpackConflictHintToErrorResponse(responseObj, args, toolN
3648
3698
  projectID: projectIDHint,
3649
3699
  ctxpack: safeObject(ctxpackRaw),
3650
3700
  workspaceDir,
3701
+ workspaceSignalTrusted,
3651
3702
  });
3652
3703
  autoPullHint = ` auto-pull: ${String(syncResult.sync_status || "error")}${
3653
3704
  syncResult.local_path ? ` (${String(syncResult.local_path)})` : ""
@@ -3684,6 +3735,7 @@ async function runProxy(flags) {
3684
3735
  let lastRefreshAttemptAtMs = 0;
3685
3736
  let lastRefreshError = "";
3686
3737
  let sessionWorkspaceDir = "";
3738
+ let sessionWorkspaceTrusted = false;
3687
3739
 
3688
3740
  const rl = readline.createInterface({
3689
3741
  input: process.stdin,
@@ -3741,15 +3793,36 @@ async function runProxy(flags) {
3741
3793
  }
3742
3794
 
3743
3795
  const { name: toolName, args: toolArgs } = extractToolCall(requestObj);
3796
+ let requestWorkspaceCandidate = "";
3797
+ let strongRequestWorkspaceCandidate = "";
3798
+ let strongEnvWorkspaceCandidate = "";
3744
3799
  if (!args.explicitPinnedWorkspace) {
3745
- const requestWorkspaceCandidate = extractWorkspaceCandidateFromRequest(requestObj, toolArgs);
3746
- const envWorkspaceCandidate = extractWorkspaceCandidateFromEnv();
3800
+ strongRequestWorkspaceCandidate = extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs);
3801
+ requestWorkspaceCandidate = firstNonEmptyString([
3802
+ strongRequestWorkspaceCandidate,
3803
+ extractWorkspaceCandidateFromRequest(requestObj, toolArgs),
3804
+ ]);
3805
+ strongEnvWorkspaceCandidate = extractStrongWorkspaceCandidateFromEnv();
3806
+ const envWorkspaceCandidate = firstNonEmptyString([
3807
+ strongEnvWorkspaceCandidate,
3808
+ extractWorkspaceCandidateFromEnv(),
3809
+ ]);
3747
3810
  if (requestWorkspaceCandidate) {
3748
3811
  sessionWorkspaceDir = requestWorkspaceCandidate;
3812
+ if (strongRequestWorkspaceCandidate) {
3813
+ sessionWorkspaceTrusted = true;
3814
+ }
3749
3815
  } else if (envWorkspaceCandidate) {
3750
3816
  sessionWorkspaceDir = envWorkspaceCandidate;
3817
+ if (strongEnvWorkspaceCandidate) {
3818
+ sessionWorkspaceTrusted = true;
3819
+ }
3751
3820
  }
3752
3821
  }
3822
+ const workspaceSignalTrusted =
3823
+ args.explicitPinnedWorkspace ||
3824
+ sessionWorkspaceTrusted ||
3825
+ Boolean(strongRequestWorkspaceCandidate || strongEnvWorkspaceCandidate);
3753
3826
  const requestWorkspaceDir = args.explicitPinnedWorkspace
3754
3827
  ? resolveWorkspaceDir(args.workspaceDir || process.cwd())
3755
3828
  : resolveWorkspaceDirForRequest(
@@ -3766,6 +3839,7 @@ async function runProxy(flags) {
3766
3839
  args,
3767
3840
  token,
3768
3841
  workspaceDir: requestWorkspaceDir,
3842
+ workspaceSignalTrusted,
3769
3843
  });
3770
3844
  }
3771
3845
  if (isJsonRpcMethod(requestObj, "tools/call") && LOCAL_PROJECT_TOOL_NAMES.includes(toolName)) {
@@ -3809,6 +3883,7 @@ async function runProxy(flags) {
3809
3883
  includeCtxpack,
3810
3884
  syncCtxpackLocal,
3811
3885
  workspaceDir: requestWorkspaceDir,
3886
+ workspaceSignalTrusted,
3812
3887
  });
3813
3888
  const text = buildProjectSummaryText(summary);
3814
3889
  process.stdout.write(
@@ -3962,6 +4037,7 @@ async function runProxy(flags) {
3962
4037
  toolArgs,
3963
4038
  token,
3964
4039
  requestWorkspaceDir,
4040
+ workspaceSignalTrusted,
3965
4041
  );
3966
4042
  process.stdout.write(`${JSON.stringify(patched)}\n`);
3967
4043
  return;
@@ -3971,9 +4047,15 @@ async function runProxy(flags) {
3971
4047
  } else if (isJsonRpcMethod(requestObj, "initialize")) {
3972
4048
  patched = appendProjectHintToInitialize(patched, args);
3973
4049
  } else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "workitem.list") {
3974
- patched = await appendWorkitemListHints(patched, args, toolArgs, token);
4050
+ patched = await appendWorkitemListHints(patched, args, toolArgs, token, workspaceSignalTrusted);
3975
4051
  } else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "ctxpack.ensure") {
3976
- patched = appendCtxpackEnsureSyncHints(patched, args, toolArgs, requestObj);
4052
+ patched = appendCtxpackEnsureSyncHints(
4053
+ patched,
4054
+ args,
4055
+ toolArgs,
4056
+ requestObj,
4057
+ workspaceSignalTrusted,
4058
+ );
3977
4059
  }
3978
4060
  if (autoSyncSummary) {
3979
4061
  patched = appendAutoCtxpackSyncHint(patched, autoSyncSummary);
@@ -4017,16 +4099,24 @@ function commandExists(bin) {
4017
4099
  return check.status === 0;
4018
4100
  }
4019
4101
 
4020
- function tryRegister(cliBin, serverName, proxyArgs) {
4102
+ function tryRegister(cliBin, serverName, proxyArgs, options = {}) {
4021
4103
  const selfPath = fileURLToPath(import.meta.url);
4022
4104
  const baseAddArgs =
4023
4105
  cliBin === "claude"
4024
4106
  ? ["mcp", "add", "--scope", "user", serverName]
4025
4107
  : ["mcp", "add", serverName];
4026
- const attempts = [
4027
- [...baseAddArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs],
4028
- [...baseAddArgs, process.execPath, selfPath, "proxy", ...proxyArgs],
4029
- ];
4108
+ const workspaceEnv = String(options.workspaceDir || "").trim();
4109
+ const codexEnvArgs =
4110
+ cliBin === "codex" && workspaceEnv
4111
+ ? ["--env", `METHEUS_WORKSPACE_DIR=${workspaceEnv}`]
4112
+ : [];
4113
+ const attempts = [];
4114
+ if (codexEnvArgs.length > 0) {
4115
+ attempts.push([...baseAddArgs, ...codexEnvArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs]);
4116
+ attempts.push([...baseAddArgs, ...codexEnvArgs, process.execPath, selfPath, "proxy", ...proxyArgs]);
4117
+ }
4118
+ attempts.push([...baseAddArgs, "--", process.execPath, selfPath, "proxy", ...proxyArgs]);
4119
+ attempts.push([...baseAddArgs, process.execPath, selfPath, "proxy", ...proxyArgs]);
4030
4120
  for (const args of attempts) {
4031
4121
  const run = runCLICommand(cliBin, args, { stdio: "inherit" });
4032
4122
  if (run.status === 0) return true;
@@ -4062,18 +4152,23 @@ function resolveSetupContext(flags) {
4062
4152
  const ctxpackKey = String(flags["ctxpack-key"] || buildCtxpackKeyFromMeta(workspaceMeta) || "").trim();
4063
4153
  const baseURL = String(flags["base-url"] || DEFAULT_SITE_URL).trim().replace(/\/+$/, "");
4064
4154
  const workspaceDirRaw = String(flags["workspace-dir"] || "").trim();
4065
- const hasWorkspaceDirFlag = workspaceDirRaw.length > 0;
4066
- const workspaceAutoMode = hasWorkspaceDirFlag && isAutoWorkspaceMode(workspaceDirRaw);
4067
- // Default: pin to current working directory.
4068
- // Use --workspace-dir auto for dynamic runtime workspace detection.
4069
- const shouldPinWorkspaceDir = !workspaceAutoMode;
4155
+ const workspaceFallbackDirRaw = String(flags["workspace-fallback-dir"] || "").trim();
4156
+ const hasWorkspaceDirFlag = Object.prototype.hasOwnProperty.call(flags, "workspace-dir");
4157
+ // Default to auto workspace mode for safer multi-project Codex sessions.
4158
+ const workspaceAutoMode = !hasWorkspaceDirFlag || isAutoWorkspaceMode(workspaceDirRaw);
4159
+ // Pin only when user explicitly set a non-auto workspace-dir.
4160
+ const shouldPinWorkspaceDir = hasWorkspaceDirFlag && !workspaceAutoMode;
4161
+ const workspaceFallbackDir = workspaceFallbackDirRaw
4162
+ ? resolveWorkspaceDir(workspaceFallbackDirRaw)
4163
+ : "";
4070
4164
  const workspaceDir = resolveWorkspaceDir(
4071
4165
  shouldPinWorkspaceDir ? workspaceDirRaw || process.cwd() : process.cwd(),
4072
4166
  );
4073
4167
  const serverName = String(flags.name || DEFAULT_SERVER_NAME).trim() || DEFAULT_SERVER_NAME;
4074
4168
  const proxyArgs = ["--base-url", `${baseURL}/governance/mcp`];
4075
- // Pin workspace by default to avoid spreading ctxpack cache across mixed client roots.
4076
- if (shouldPinWorkspaceDir) {
4169
+ if (workspaceAutoMode) {
4170
+ proxyArgs.push("--workspace-dir", "auto");
4171
+ } else if (shouldPinWorkspaceDir) {
4077
4172
  proxyArgs.push("--workspace-dir", workspaceDir);
4078
4173
  }
4079
4174
  if (projectID) proxyArgs.push("--project-id", projectID);
@@ -4083,6 +4178,7 @@ function resolveSetupContext(flags) {
4083
4178
  ctxpackKey,
4084
4179
  baseURL,
4085
4180
  workspaceDir,
4181
+ workspaceFallbackDir,
4086
4182
  shouldPinWorkspaceDir,
4087
4183
  workspaceAutoMode,
4088
4184
  serverName,
@@ -4102,7 +4198,11 @@ function runSetupInternal(flags, options = {}) {
4102
4198
  if (!ensureOnly || alreadyRegistered) {
4103
4199
  runRemove(cliBin, context.serverName);
4104
4200
  }
4105
- const ok = tryRegister(cliBin, context.serverName, context.proxyArgs);
4201
+ const ok = tryRegister(cliBin, context.serverName, context.proxyArgs, {
4202
+ workspaceDir: context.shouldPinWorkspaceDir
4203
+ ? context.workspaceDir
4204
+ : context.workspaceFallbackDir,
4205
+ });
4106
4206
  const action = ensureOnly
4107
4207
  ? alreadyRegistered
4108
4208
  ? "updated"
@@ -4117,6 +4217,9 @@ function runSetupInternal(flags, options = {}) {
4117
4217
  process.stdout.write(`Server: ${context.serverName}\n`);
4118
4218
  process.stdout.write(`Gateway: ${context.baseURL}/governance/mcp\n`);
4119
4219
  process.stdout.write(`Workspace: ${context.shouldPinWorkspaceDir ? context.workspaceDir : "auto (client current folder)"}\n`);
4220
+ if (!context.shouldPinWorkspaceDir && context.workspaceFallbackDir) {
4221
+ process.stdout.write(`Fallback: ${context.workspaceFallbackDir} (METHEUS_WORKSPACE_DIR)\n`);
4222
+ }
4120
4223
  process.stdout.write(`Project: ${context.projectID || "auto-detect from .metheus_ctxpack_sync.json"}\n`);
4121
4224
  if (context.ctxpackKey) {
4122
4225
  process.stdout.write(`Ctxpack: ${context.ctxpackKey}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [