metheus-governance-mcp-cli 0.2.17 → 0.2.19
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/README.md +13 -2
- package/cli.mjs +138 -29
- 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 ->
|
|
97
|
-
- use `--workspace-dir
|
|
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
|
|
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,28 @@ 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
|
+
return firstNonEmptyString([
|
|
392
|
+
extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs),
|
|
393
|
+
extractWeakWorkspaceCandidateFromRequest(requestObj),
|
|
394
|
+
]);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function extractWeakWorkspaceCandidateFromRequest(requestObj) {
|
|
398
|
+
const params = safeObject(requestObj?.params);
|
|
399
|
+
const meta = safeObject(params._meta);
|
|
400
|
+
const rawCandidate = firstNonEmptyString([
|
|
384
401
|
params.cwd,
|
|
385
402
|
params.root_path,
|
|
386
403
|
params.rootPath,
|
|
387
404
|
params.root_uri,
|
|
388
405
|
params.rootUri,
|
|
389
|
-
meta.workspace_dir,
|
|
390
|
-
meta.workspaceDir,
|
|
391
406
|
meta.cwd,
|
|
392
407
|
meta.root_path,
|
|
393
408
|
meta.rootPath,
|
|
@@ -397,13 +412,28 @@ function extractWorkspaceCandidateFromRequest(requestObj, toolArgs) {
|
|
|
397
412
|
return sanitizeWorkspaceCandidate(rawCandidate);
|
|
398
413
|
}
|
|
399
414
|
|
|
400
|
-
function
|
|
415
|
+
function extractStrongWorkspaceCandidateFromEnv() {
|
|
401
416
|
const rawCandidate = firstNonEmptyString([
|
|
402
417
|
process.env.METHEUS_WORKSPACE_DIR,
|
|
418
|
+
process.env.METHEUS_WORKSPACE_URI,
|
|
419
|
+
process.env.CODEX_WORKSPACE_DIR,
|
|
420
|
+
process.env.CODEX_WORKSPACE_URI,
|
|
403
421
|
process.env.CLAUDE_WORKSPACE_DIR,
|
|
404
422
|
process.env.CLAUDE_WORKSPACE_URI,
|
|
405
423
|
process.env.CLAUDE_PROJECT_DIR,
|
|
406
|
-
|
|
424
|
+
]);
|
|
425
|
+
return sanitizeWorkspaceCandidate(rawCandidate);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function extractWorkspaceCandidateFromEnv() {
|
|
429
|
+
return firstNonEmptyString([
|
|
430
|
+
extractStrongWorkspaceCandidateFromEnv(),
|
|
431
|
+
extractWeakWorkspaceCandidateFromEnv(),
|
|
432
|
+
]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function extractWeakWorkspaceCandidateFromEnv() {
|
|
436
|
+
const rawCandidate = firstNonEmptyString([
|
|
407
437
|
process.env.WORKSPACE_DIR,
|
|
408
438
|
process.env.WORKSPACE_FOLDER,
|
|
409
439
|
process.env.VSCODE_WORKSPACE_FOLDER,
|
|
@@ -415,10 +445,20 @@ function extractWorkspaceCandidateFromEnv() {
|
|
|
415
445
|
}
|
|
416
446
|
|
|
417
447
|
function resolveWorkspaceDirForRequest(defaultWorkspaceDir, requestObj, toolArgs) {
|
|
418
|
-
const
|
|
419
|
-
const
|
|
448
|
+
const strongRequestCandidate = extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs);
|
|
449
|
+
const strongEnvCandidate = extractStrongWorkspaceCandidateFromEnv();
|
|
450
|
+
const weakRequestCandidate = extractWeakWorkspaceCandidateFromRequest(requestObj);
|
|
451
|
+
const weakEnvCandidate = extractWeakWorkspaceCandidateFromEnv();
|
|
420
452
|
const homeCandidate = firstNonEmptyString([process.env.USERPROFILE, process.env.HOME]);
|
|
421
|
-
for (const rawCandidate of [
|
|
453
|
+
for (const rawCandidate of [
|
|
454
|
+
strongRequestCandidate,
|
|
455
|
+
strongEnvCandidate,
|
|
456
|
+
weakRequestCandidate,
|
|
457
|
+
weakEnvCandidate,
|
|
458
|
+
defaultWorkspaceDir,
|
|
459
|
+
process.cwd(),
|
|
460
|
+
homeCandidate,
|
|
461
|
+
]) {
|
|
422
462
|
const resolved = sanitizeWorkspaceCandidate(rawCandidate);
|
|
423
463
|
if (resolved) return resolved;
|
|
424
464
|
}
|
|
@@ -2436,7 +2476,13 @@ function hasAllCtxpackFiles(baseDir, files) {
|
|
|
2436
2476
|
return true;
|
|
2437
2477
|
}
|
|
2438
2478
|
|
|
2439
|
-
function syncCtxpackToLocalCache({
|
|
2479
|
+
function syncCtxpackToLocalCache({
|
|
2480
|
+
siteBaseURL,
|
|
2481
|
+
projectID,
|
|
2482
|
+
ctxpack,
|
|
2483
|
+
workspaceDir,
|
|
2484
|
+
workspaceSignalTrusted = true,
|
|
2485
|
+
}) {
|
|
2440
2486
|
const ctxpackID = String(ctxpack?.ctxpack_id || "").trim();
|
|
2441
2487
|
const version = String(ctxpack?.version || "").trim();
|
|
2442
2488
|
const versionID = String(ctxpack?.version_id || ctxpack?.current_version_id || "").trim();
|
|
@@ -2458,6 +2504,17 @@ function syncCtxpackToLocalCache({ siteBaseURL, projectID, ctxpack, workspaceDir
|
|
|
2458
2504
|
};
|
|
2459
2505
|
}
|
|
2460
2506
|
|
|
2507
|
+
if (!workspaceSignalTrusted) {
|
|
2508
|
+
return {
|
|
2509
|
+
sync_status: "guarded",
|
|
2510
|
+
sync_message:
|
|
2511
|
+
"Workspace signal is missing in auto mode. Guardrail blocked ctxpack local write to avoid wrong folder sync.",
|
|
2512
|
+
local_path: cacheDir,
|
|
2513
|
+
workspace_path: resolvedWorkspaceDir,
|
|
2514
|
+
local_file_count: 0,
|
|
2515
|
+
};
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2461
2518
|
if (!ctxpackID || !version || files.length === 0) {
|
|
2462
2519
|
return {
|
|
2463
2520
|
sync_status: "not_available",
|
|
@@ -2542,6 +2599,7 @@ async function loadProjectSummaryForTool({
|
|
|
2542
2599
|
syncCtxpackLocal,
|
|
2543
2600
|
workspaceDir,
|
|
2544
2601
|
ctxpackPaths,
|
|
2602
|
+
workspaceSignalTrusted = true,
|
|
2545
2603
|
}) {
|
|
2546
2604
|
const encodedProjectID = encodeURIComponent(projectID);
|
|
2547
2605
|
let projectRaw = null;
|
|
@@ -2607,6 +2665,7 @@ async function loadProjectSummaryForTool({
|
|
|
2607
2665
|
projectID,
|
|
2608
2666
|
ctxpack,
|
|
2609
2667
|
workspaceDir,
|
|
2668
|
+
workspaceSignalTrusted,
|
|
2610
2669
|
});
|
|
2611
2670
|
ctxpackSyncStatus = syncResult.sync_status || "error";
|
|
2612
2671
|
ctxpackSyncMessage = String(syncResult.sync_message || "").trim();
|
|
@@ -3267,6 +3326,7 @@ async function maybeAutoSyncCtxpackForCall({
|
|
|
3267
3326
|
args,
|
|
3268
3327
|
token,
|
|
3269
3328
|
workspaceDir,
|
|
3329
|
+
workspaceSignalTrusted = true,
|
|
3270
3330
|
}) {
|
|
3271
3331
|
if (!isJsonRpcMethod(requestObj, "tools/call")) return null;
|
|
3272
3332
|
if (!token) return null;
|
|
@@ -3298,6 +3358,7 @@ async function maybeAutoSyncCtxpackForCall({
|
|
|
3298
3358
|
includeCtxpack: true,
|
|
3299
3359
|
syncCtxpackLocal: true,
|
|
3300
3360
|
workspaceDir: workspacePath,
|
|
3361
|
+
workspaceSignalTrusted,
|
|
3301
3362
|
});
|
|
3302
3363
|
} catch {
|
|
3303
3364
|
return null;
|
|
@@ -3329,7 +3390,7 @@ function appendAutoCtxpackSyncHint(responseObj, summary) {
|
|
|
3329
3390
|
return responseObj;
|
|
3330
3391
|
}
|
|
3331
3392
|
|
|
3332
|
-
async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
|
|
3393
|
+
async function appendWorkitemListHints(responseObj, args, toolArgs, token, workspaceSignalTrusted = true) {
|
|
3333
3394
|
const result = safeObject(responseObj.result);
|
|
3334
3395
|
const content = ensureArray(result.content);
|
|
3335
3396
|
if (!content.length) return responseObj;
|
|
@@ -3388,6 +3449,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
|
|
|
3388
3449
|
includeCtxpack: isEmptyBody,
|
|
3389
3450
|
syncCtxpackLocal: isEmptyBody,
|
|
3390
3451
|
workspaceDir: args.workspaceDir,
|
|
3452
|
+
workspaceSignalTrusted,
|
|
3391
3453
|
});
|
|
3392
3454
|
if (String(summary.access || "") === "granted") {
|
|
3393
3455
|
nextLines.push("Project context:");
|
|
@@ -3425,7 +3487,7 @@ async function appendWorkitemListHints(responseObj, args, toolArgs, token) {
|
|
|
3425
3487
|
return responseObj;
|
|
3426
3488
|
}
|
|
3427
3489
|
|
|
3428
|
-
function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj) {
|
|
3490
|
+
function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj, workspaceSignalTrusted = true) {
|
|
3429
3491
|
const result = safeObject(responseObj.result);
|
|
3430
3492
|
const content = ensureArray(result.content);
|
|
3431
3493
|
if (!content.length) return responseObj;
|
|
@@ -3459,6 +3521,7 @@ function appendCtxpackEnsureSyncHints(responseObj, args, toolArgs, requestObj) {
|
|
|
3459
3521
|
projectID,
|
|
3460
3522
|
ctxpack: body,
|
|
3461
3523
|
workspaceDir,
|
|
3524
|
+
workspaceSignalTrusted,
|
|
3462
3525
|
});
|
|
3463
3526
|
const baseVersionID = firstNonEmptyString([body.base_version_id, body.version_id, body.current_version_id]);
|
|
3464
3527
|
const currentVersionID = firstNonEmptyString([body.current_version_id, body.version_id, body.base_version_id]);
|
|
@@ -3616,7 +3679,15 @@ async function injectCtxpackPreflightToken(requestObj, toolName, toolArgs, args,
|
|
|
3616
3679
|
}
|
|
3617
3680
|
}
|
|
3618
3681
|
|
|
3619
|
-
async function appendCtxpackConflictHintToErrorResponse(
|
|
3682
|
+
async function appendCtxpackConflictHintToErrorResponse(
|
|
3683
|
+
responseObj,
|
|
3684
|
+
args,
|
|
3685
|
+
toolName,
|
|
3686
|
+
toolArgs,
|
|
3687
|
+
token,
|
|
3688
|
+
workspaceDir,
|
|
3689
|
+
workspaceSignalTrusted = true,
|
|
3690
|
+
) {
|
|
3620
3691
|
const out = safeObject(responseObj);
|
|
3621
3692
|
const errObj = safeObject(out.error);
|
|
3622
3693
|
const message = String(errObj.message || "").trim();
|
|
@@ -3648,6 +3719,7 @@ async function appendCtxpackConflictHintToErrorResponse(responseObj, args, toolN
|
|
|
3648
3719
|
projectID: projectIDHint,
|
|
3649
3720
|
ctxpack: safeObject(ctxpackRaw),
|
|
3650
3721
|
workspaceDir,
|
|
3722
|
+
workspaceSignalTrusted,
|
|
3651
3723
|
});
|
|
3652
3724
|
autoPullHint = ` auto-pull: ${String(syncResult.sync_status || "error")}${
|
|
3653
3725
|
syncResult.local_path ? ` (${String(syncResult.local_path)})` : ""
|
|
@@ -3684,6 +3756,7 @@ async function runProxy(flags) {
|
|
|
3684
3756
|
let lastRefreshAttemptAtMs = 0;
|
|
3685
3757
|
let lastRefreshError = "";
|
|
3686
3758
|
let sessionWorkspaceDir = "";
|
|
3759
|
+
let sessionWorkspaceTrusted = false;
|
|
3687
3760
|
|
|
3688
3761
|
const rl = readline.createInterface({
|
|
3689
3762
|
input: process.stdin,
|
|
@@ -3741,15 +3814,31 @@ async function runProxy(flags) {
|
|
|
3741
3814
|
}
|
|
3742
3815
|
|
|
3743
3816
|
const { name: toolName, args: toolArgs } = extractToolCall(requestObj);
|
|
3817
|
+
let strongRequestWorkspaceCandidate = "";
|
|
3818
|
+
let weakRequestWorkspaceCandidate = "";
|
|
3819
|
+
let strongEnvWorkspaceCandidate = "";
|
|
3820
|
+
let weakEnvWorkspaceCandidate = "";
|
|
3744
3821
|
if (!args.explicitPinnedWorkspace) {
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
sessionWorkspaceDir =
|
|
3822
|
+
strongRequestWorkspaceCandidate = extractStrongWorkspaceCandidateFromRequest(requestObj, toolArgs);
|
|
3823
|
+
weakRequestWorkspaceCandidate = extractWeakWorkspaceCandidateFromRequest(requestObj);
|
|
3824
|
+
strongEnvWorkspaceCandidate = extractStrongWorkspaceCandidateFromEnv();
|
|
3825
|
+
weakEnvWorkspaceCandidate = extractWeakWorkspaceCandidateFromEnv();
|
|
3826
|
+
if (strongRequestWorkspaceCandidate) {
|
|
3827
|
+
sessionWorkspaceDir = strongRequestWorkspaceCandidate;
|
|
3828
|
+
sessionWorkspaceTrusted = true;
|
|
3829
|
+
} else if (strongEnvWorkspaceCandidate) {
|
|
3830
|
+
sessionWorkspaceDir = strongEnvWorkspaceCandidate;
|
|
3831
|
+
sessionWorkspaceTrusted = true;
|
|
3832
|
+
} else if (weakRequestWorkspaceCandidate) {
|
|
3833
|
+
sessionWorkspaceDir = weakRequestWorkspaceCandidate;
|
|
3834
|
+
} else if (weakEnvWorkspaceCandidate) {
|
|
3835
|
+
sessionWorkspaceDir = weakEnvWorkspaceCandidate;
|
|
3751
3836
|
}
|
|
3752
3837
|
}
|
|
3838
|
+
const workspaceSignalTrusted =
|
|
3839
|
+
args.explicitPinnedWorkspace ||
|
|
3840
|
+
sessionWorkspaceTrusted ||
|
|
3841
|
+
Boolean(strongRequestWorkspaceCandidate || strongEnvWorkspaceCandidate);
|
|
3753
3842
|
const requestWorkspaceDir = args.explicitPinnedWorkspace
|
|
3754
3843
|
? resolveWorkspaceDir(args.workspaceDir || process.cwd())
|
|
3755
3844
|
: resolveWorkspaceDirForRequest(
|
|
@@ -3766,6 +3855,7 @@ async function runProxy(flags) {
|
|
|
3766
3855
|
args,
|
|
3767
3856
|
token,
|
|
3768
3857
|
workspaceDir: requestWorkspaceDir,
|
|
3858
|
+
workspaceSignalTrusted,
|
|
3769
3859
|
});
|
|
3770
3860
|
}
|
|
3771
3861
|
if (isJsonRpcMethod(requestObj, "tools/call") && LOCAL_PROJECT_TOOL_NAMES.includes(toolName)) {
|
|
@@ -3809,6 +3899,7 @@ async function runProxy(flags) {
|
|
|
3809
3899
|
includeCtxpack,
|
|
3810
3900
|
syncCtxpackLocal,
|
|
3811
3901
|
workspaceDir: requestWorkspaceDir,
|
|
3902
|
+
workspaceSignalTrusted,
|
|
3812
3903
|
});
|
|
3813
3904
|
const text = buildProjectSummaryText(summary);
|
|
3814
3905
|
process.stdout.write(
|
|
@@ -3962,6 +4053,7 @@ async function runProxy(flags) {
|
|
|
3962
4053
|
toolArgs,
|
|
3963
4054
|
token,
|
|
3964
4055
|
requestWorkspaceDir,
|
|
4056
|
+
workspaceSignalTrusted,
|
|
3965
4057
|
);
|
|
3966
4058
|
process.stdout.write(`${JSON.stringify(patched)}\n`);
|
|
3967
4059
|
return;
|
|
@@ -3971,9 +4063,15 @@ async function runProxy(flags) {
|
|
|
3971
4063
|
} else if (isJsonRpcMethod(requestObj, "initialize")) {
|
|
3972
4064
|
patched = appendProjectHintToInitialize(patched, args);
|
|
3973
4065
|
} else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "workitem.list") {
|
|
3974
|
-
patched = await appendWorkitemListHints(patched, args, toolArgs, token);
|
|
4066
|
+
patched = await appendWorkitemListHints(patched, args, toolArgs, token, workspaceSignalTrusted);
|
|
3975
4067
|
} else if (isJsonRpcMethod(requestObj, "tools/call") && toolName === "ctxpack.ensure") {
|
|
3976
|
-
patched = appendCtxpackEnsureSyncHints(
|
|
4068
|
+
patched = appendCtxpackEnsureSyncHints(
|
|
4069
|
+
patched,
|
|
4070
|
+
args,
|
|
4071
|
+
toolArgs,
|
|
4072
|
+
requestObj,
|
|
4073
|
+
workspaceSignalTrusted,
|
|
4074
|
+
);
|
|
3977
4075
|
}
|
|
3978
4076
|
if (autoSyncSummary) {
|
|
3979
4077
|
patched = appendAutoCtxpackSyncHint(patched, autoSyncSummary);
|
|
@@ -4070,18 +4168,23 @@ function resolveSetupContext(flags) {
|
|
|
4070
4168
|
const ctxpackKey = String(flags["ctxpack-key"] || buildCtxpackKeyFromMeta(workspaceMeta) || "").trim();
|
|
4071
4169
|
const baseURL = String(flags["base-url"] || DEFAULT_SITE_URL).trim().replace(/\/+$/, "");
|
|
4072
4170
|
const workspaceDirRaw = String(flags["workspace-dir"] || "").trim();
|
|
4073
|
-
const
|
|
4074
|
-
const
|
|
4075
|
-
// Default
|
|
4076
|
-
|
|
4077
|
-
|
|
4171
|
+
const workspaceFallbackDirRaw = String(flags["workspace-fallback-dir"] || "").trim();
|
|
4172
|
+
const hasWorkspaceDirFlag = Object.prototype.hasOwnProperty.call(flags, "workspace-dir");
|
|
4173
|
+
// Default to auto workspace mode for safer multi-project Codex sessions.
|
|
4174
|
+
const workspaceAutoMode = !hasWorkspaceDirFlag || isAutoWorkspaceMode(workspaceDirRaw);
|
|
4175
|
+
// Pin only when user explicitly set a non-auto workspace-dir.
|
|
4176
|
+
const shouldPinWorkspaceDir = hasWorkspaceDirFlag && !workspaceAutoMode;
|
|
4177
|
+
const workspaceFallbackDir = workspaceFallbackDirRaw
|
|
4178
|
+
? resolveWorkspaceDir(workspaceFallbackDirRaw)
|
|
4179
|
+
: "";
|
|
4078
4180
|
const workspaceDir = resolveWorkspaceDir(
|
|
4079
4181
|
shouldPinWorkspaceDir ? workspaceDirRaw || process.cwd() : process.cwd(),
|
|
4080
4182
|
);
|
|
4081
4183
|
const serverName = String(flags.name || DEFAULT_SERVER_NAME).trim() || DEFAULT_SERVER_NAME;
|
|
4082
4184
|
const proxyArgs = ["--base-url", `${baseURL}/governance/mcp`];
|
|
4083
|
-
|
|
4084
|
-
|
|
4185
|
+
if (workspaceAutoMode) {
|
|
4186
|
+
proxyArgs.push("--workspace-dir", "auto");
|
|
4187
|
+
} else if (shouldPinWorkspaceDir) {
|
|
4085
4188
|
proxyArgs.push("--workspace-dir", workspaceDir);
|
|
4086
4189
|
}
|
|
4087
4190
|
if (projectID) proxyArgs.push("--project-id", projectID);
|
|
@@ -4091,6 +4194,7 @@ function resolveSetupContext(flags) {
|
|
|
4091
4194
|
ctxpackKey,
|
|
4092
4195
|
baseURL,
|
|
4093
4196
|
workspaceDir,
|
|
4197
|
+
workspaceFallbackDir,
|
|
4094
4198
|
shouldPinWorkspaceDir,
|
|
4095
4199
|
workspaceAutoMode,
|
|
4096
4200
|
serverName,
|
|
@@ -4111,7 +4215,9 @@ function runSetupInternal(flags, options = {}) {
|
|
|
4111
4215
|
runRemove(cliBin, context.serverName);
|
|
4112
4216
|
}
|
|
4113
4217
|
const ok = tryRegister(cliBin, context.serverName, context.proxyArgs, {
|
|
4114
|
-
workspaceDir: context.
|
|
4218
|
+
workspaceDir: context.shouldPinWorkspaceDir
|
|
4219
|
+
? context.workspaceDir
|
|
4220
|
+
: context.workspaceFallbackDir,
|
|
4115
4221
|
});
|
|
4116
4222
|
const action = ensureOnly
|
|
4117
4223
|
? alreadyRegistered
|
|
@@ -4127,6 +4233,9 @@ function runSetupInternal(flags, options = {}) {
|
|
|
4127
4233
|
process.stdout.write(`Server: ${context.serverName}\n`);
|
|
4128
4234
|
process.stdout.write(`Gateway: ${context.baseURL}/governance/mcp\n`);
|
|
4129
4235
|
process.stdout.write(`Workspace: ${context.shouldPinWorkspaceDir ? context.workspaceDir : "auto (client current folder)"}\n`);
|
|
4236
|
+
if (!context.shouldPinWorkspaceDir && context.workspaceFallbackDir) {
|
|
4237
|
+
process.stdout.write(`Fallback: ${context.workspaceFallbackDir} (METHEUS_WORKSPACE_DIR)\n`);
|
|
4238
|
+
}
|
|
4130
4239
|
process.stdout.write(`Project: ${context.projectID || "auto-detect from .metheus_ctxpack_sync.json"}\n`);
|
|
4131
4240
|
if (context.ctxpackKey) {
|
|
4132
4241
|
process.stdout.write(`Ctxpack: ${context.ctxpackKey}\n`);
|