@triflux/core 10.50.2 → 10.51.0
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/hooks/agy-session-hook.mjs +11 -56
- package/hooks/codex-session-hook.mjs +11 -101
- package/hub/bridge.mjs +1 -79
- package/hub/cli-adapter-base.mjs +12 -90
- package/hub/codex-adapter.mjs +0 -1
- package/hub/codex-preflight.mjs +5 -28
- package/hub/index.mjs +1 -1
- package/hub/lib/known-errors.json +2 -2
- package/hub/lib/process-utils.mjs +0 -123
- package/hub/lib/spawn-trace.mjs +3 -2
- package/hub/lib/timeout-defaults.mjs +0 -1
- package/hub/role-contract.mjs +0 -2
- package/hud/cli-policy.mjs +0 -22
- package/hud/constants.mjs +11 -26
- package/hud/hud-qos-status.mjs +23 -51
- package/hud/providers/gemini.mjs +105 -20
- package/hud/renderers.mjs +50 -104
- package/hud/utils.mjs +2 -2
- package/package.json +1 -3
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +11 -59
- package/scripts/lib/session-presence.mjs +1 -1
- package/scripts/lib/skill-template.mjs +0 -245
- package/hub/dynamic-routing-engine.mjs +0 -511
- package/hub/lib/risk-tier.mjs +0 -53
- package/hub/lib/ssh-command.mjs +0 -231
- package/hub/lib/staged-file-detect.mjs +0 -43
- package/hub/lib/tfx-route-args.mjs +0 -353
- package/hub/routing-snapshot.mjs +0 -261
- package/mesh/index.mjs +0 -69
- package/mesh/mesh-budget.mjs +0 -137
- package/mesh/mesh-heartbeat.mjs +0 -100
- package/mesh/mesh-protocol.mjs +0 -96
- package/mesh/mesh-queue.mjs +0 -163
- package/mesh/mesh-registry.mjs +0 -78
- package/mesh/mesh-router.mjs +0 -77
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
|
@@ -15,10 +15,6 @@ import {
|
|
|
15
15
|
uniqueStrings,
|
|
16
16
|
} from "./mcp-server-catalog.mjs";
|
|
17
17
|
|
|
18
|
-
export const KNOWN_MCP_SERVERS = Object.freeze(
|
|
19
|
-
Object.keys(MCP_SERVER_TOOL_CATALOG),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
18
|
const SEARCH_INTENT_PATTERNS = Object.freeze([
|
|
23
19
|
/\b(search|web|browse|look ?up|find|latest|recent|news|current|today|release(?: note)?s?|changelog|announcement|pricing|status|verify|fact[- ]?check)\b/i,
|
|
24
20
|
/(검색|웹|브라우즈|찾아|조회|최신|최근|뉴스|현재|오늘|릴리즈|배포|변경사항|공지|가격|상태|검증)/u,
|
|
@@ -145,7 +141,7 @@ const PROFILE_DEFINITIONS = Object.freeze({
|
|
|
145
141
|
* 파이프라인 단계별 MCP 서버/도구 제한 (post-filter).
|
|
146
142
|
* role-based 프로필 위에 추가 적용. 빈 배열 = 전체 차단, 미정의 = 제한 없음.
|
|
147
143
|
*/
|
|
148
|
-
|
|
144
|
+
const PHASE_OVERRIDES = Object.freeze({
|
|
149
145
|
plan: Object.freeze({
|
|
150
146
|
description: "계획 단계: 읽기 전용 탐색만 허용",
|
|
151
147
|
allowedServers: Object.freeze(["context7"]),
|
|
@@ -166,7 +162,7 @@ export const PHASE_OVERRIDES = Object.freeze({
|
|
|
166
162
|
}),
|
|
167
163
|
});
|
|
168
164
|
|
|
169
|
-
|
|
165
|
+
const LEGACY_PROFILE_ALIASES = Object.freeze({
|
|
170
166
|
implement: "executor",
|
|
171
167
|
analyze: "analyze",
|
|
172
168
|
review: "reviewer",
|
|
@@ -257,30 +253,51 @@ function loadInventory(inventoryFile = "") {
|
|
|
257
253
|
}
|
|
258
254
|
}
|
|
259
255
|
|
|
256
|
+
function availableServersFromInventory(inventory, cliType) {
|
|
257
|
+
const servers = inventory?.[cliType]?.servers || [];
|
|
258
|
+
return uniqueStrings(
|
|
259
|
+
servers
|
|
260
|
+
.filter((server) => ["enabled", "configured"].includes(server.status))
|
|
261
|
+
.map((server) => server.name),
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function codexServersFromConfig(configFile) {
|
|
266
|
+
if (!configFile) return [];
|
|
267
|
+
try {
|
|
268
|
+
return uniqueStrings(
|
|
269
|
+
readFileSync(configFile, "utf8")
|
|
270
|
+
.split(/\r?\n/)
|
|
271
|
+
.map((line) => /^\[mcp_servers\.([^\].]+)\]$/.exec(line)?.[1])
|
|
272
|
+
.filter(Boolean),
|
|
273
|
+
).sort();
|
|
274
|
+
} catch {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
260
279
|
function buildInventoryIndex(inventory = null) {
|
|
261
280
|
const index = new Map();
|
|
262
281
|
if (!inventory || typeof inventory !== "object") return index;
|
|
263
282
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
tool_count
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
domain_tags:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
});
|
|
283
|
-
}
|
|
283
|
+
const servers = Array.isArray(inventory.codex?.servers)
|
|
284
|
+
? inventory.codex.servers
|
|
285
|
+
: [];
|
|
286
|
+
for (const server of servers) {
|
|
287
|
+
if (!server || typeof server.name !== "string" || !server.name.trim())
|
|
288
|
+
continue;
|
|
289
|
+
const name = server.name.trim();
|
|
290
|
+
const previous = index.get(name) || {};
|
|
291
|
+
index.set(name, {
|
|
292
|
+
...previous,
|
|
293
|
+
tool_count: Number.isFinite(server.tool_count)
|
|
294
|
+
? Math.max(previous.tool_count ?? 0, Math.trunc(server.tool_count))
|
|
295
|
+
: previous.tool_count,
|
|
296
|
+
domain_tags: uniqueStrings([
|
|
297
|
+
...(Array.isArray(previous.domain_tags) ? previous.domain_tags : []),
|
|
298
|
+
...(Array.isArray(server.domain_tags) ? server.domain_tags : []),
|
|
299
|
+
]),
|
|
300
|
+
});
|
|
284
301
|
}
|
|
285
302
|
|
|
286
303
|
return index;
|
|
@@ -498,7 +515,7 @@ export function resolveMcpProfile(agentType = "", requestedProfile = "auto") {
|
|
|
498
515
|
return normalized === "auto" ? resolveAutoProfile(agentType) : normalized;
|
|
499
516
|
}
|
|
500
517
|
|
|
501
|
-
|
|
518
|
+
function parseAvailableServers(rawAvailableServers = "") {
|
|
502
519
|
if (Array.isArray(rawAvailableServers))
|
|
503
520
|
return uniqueStrings(rawAvailableServers);
|
|
504
521
|
if (typeof rawAvailableServers !== "string" || !rawAvailableServers.trim())
|
|
@@ -554,15 +571,21 @@ function applyManifestFilter(servers) {
|
|
|
554
571
|
return servers.filter((s) => enabled.has(s));
|
|
555
572
|
}
|
|
556
573
|
|
|
557
|
-
|
|
574
|
+
function resolveAllowedServers(options = {}) {
|
|
558
575
|
const resolvedProfile = resolveMcpProfile(
|
|
559
576
|
options.agentType,
|
|
560
577
|
options.requestedProfile,
|
|
561
578
|
);
|
|
562
579
|
const profile = getProfileDefinition(resolvedProfile);
|
|
563
580
|
const availableServers = parseAvailableServers(options.availableServers);
|
|
564
|
-
const inventory =
|
|
565
|
-
|
|
581
|
+
const inventory =
|
|
582
|
+
options.inventory !== undefined
|
|
583
|
+
? options.inventory
|
|
584
|
+
: loadInventory(options.inventoryFile);
|
|
585
|
+
const inventoryIndex =
|
|
586
|
+
options.inventoryIndex instanceof Map
|
|
587
|
+
? options.inventoryIndex
|
|
588
|
+
: buildInventoryIndex(inventory);
|
|
566
589
|
const baseServers = availableServers.length
|
|
567
590
|
? profile.allowedServers.filter((server) =>
|
|
568
591
|
availableServers.includes(server),
|
|
@@ -585,8 +608,14 @@ export function buildPromptHint(options = {}) {
|
|
|
585
608
|
);
|
|
586
609
|
if (resolvedProfile === "none") return "";
|
|
587
610
|
|
|
588
|
-
const inventory =
|
|
589
|
-
|
|
611
|
+
const inventory =
|
|
612
|
+
options.inventory !== undefined
|
|
613
|
+
? options.inventory
|
|
614
|
+
: loadInventory(options.inventoryFile);
|
|
615
|
+
const inventoryIndex =
|
|
616
|
+
options.inventoryIndex instanceof Map
|
|
617
|
+
? options.inventoryIndex
|
|
618
|
+
: buildInventoryIndex(inventory);
|
|
590
619
|
const allowedServers = resolveAllowedServers({
|
|
591
620
|
...options,
|
|
592
621
|
inventory,
|
|
@@ -636,16 +665,7 @@ export function buildPromptHint(options = {}) {
|
|
|
636
665
|
.join(" ");
|
|
637
666
|
}
|
|
638
667
|
|
|
639
|
-
export function getGeminiAllowedServers(options = {}) {
|
|
640
|
-
return resolveAllowedServers(options);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
668
|
export function getCodexMcpConfig(options = {}) {
|
|
644
|
-
const allowedServers = new Set(resolveAllowedServers(options));
|
|
645
|
-
const resolvedProfile = resolveMcpProfile(
|
|
646
|
-
options.agentType,
|
|
647
|
-
options.requestedProfile,
|
|
648
|
-
);
|
|
649
669
|
// Codex에 실제 등록된 서버만 대상으로 config override 생성.
|
|
650
670
|
// 미등록 서버에 enabled=false를 보내면 "invalid transport" 에러 발생.
|
|
651
671
|
const registeredServers = parseAvailableServers(options.availableServers);
|
|
@@ -654,6 +674,11 @@ export function getCodexMcpConfig(options = {}) {
|
|
|
654
674
|
if (registeredServers.length === 0) {
|
|
655
675
|
return { mcp_servers: {} };
|
|
656
676
|
}
|
|
677
|
+
const allowedServers = new Set(resolveAllowedServers(options));
|
|
678
|
+
const resolvedProfile = resolveMcpProfile(
|
|
679
|
+
options.agentType,
|
|
680
|
+
options.requestedProfile,
|
|
681
|
+
);
|
|
657
682
|
const targetServers = registeredServers;
|
|
658
683
|
|
|
659
684
|
if (resolvedProfile === "none") {
|
|
@@ -712,9 +737,27 @@ export function getCodexConfigOverrides(options = {}) {
|
|
|
712
737
|
}
|
|
713
738
|
|
|
714
739
|
export function buildMcpPolicy(options = {}) {
|
|
715
|
-
const inventory =
|
|
740
|
+
const inventory =
|
|
741
|
+
options.inventory !== undefined
|
|
742
|
+
? options.inventory
|
|
743
|
+
: loadInventory(options.inventoryFile);
|
|
716
744
|
const inventoryIndex = buildInventoryIndex(inventory);
|
|
717
|
-
|
|
745
|
+
let availableServers = options.availableServers;
|
|
746
|
+
if (availableServers === undefined) {
|
|
747
|
+
availableServers = availableServersFromInventory(
|
|
748
|
+
inventory,
|
|
749
|
+
options.cliType,
|
|
750
|
+
);
|
|
751
|
+
if (availableServers.length === 0 && options.cliType === "codex") {
|
|
752
|
+
availableServers = codexServersFromConfig(options.codexConfig);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const resolvedOptions = {
|
|
756
|
+
...options,
|
|
757
|
+
availableServers,
|
|
758
|
+
inventory,
|
|
759
|
+
inventoryIndex,
|
|
760
|
+
};
|
|
718
761
|
const resolvedProfile = resolveMcpProfile(
|
|
719
762
|
options.agentType,
|
|
720
763
|
options.requestedProfile,
|
|
@@ -730,6 +773,12 @@ export function buildMcpPolicy(options = {}) {
|
|
|
730
773
|
allowedServers = allowedServers.filter((s) => !blocked.has(s));
|
|
731
774
|
}
|
|
732
775
|
|
|
776
|
+
// 플러그인 서버는 transport 설정이 없어 CLI override를 받으면 부팅이 실패한다.
|
|
777
|
+
const codexOptions = {
|
|
778
|
+
...resolvedOptions,
|
|
779
|
+
availableServers: codexServersFromConfig(options.codexConfig),
|
|
780
|
+
};
|
|
781
|
+
|
|
733
782
|
return {
|
|
734
783
|
requestedProfile:
|
|
735
784
|
typeof options.requestedProfile === "string" && options.requestedProfile
|
|
@@ -739,9 +788,8 @@ export function buildMcpPolicy(options = {}) {
|
|
|
739
788
|
resolvedPhase: phase || null,
|
|
740
789
|
allowedServers,
|
|
741
790
|
hint,
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
codexConfigOverrides: getCodexConfigOverrides(resolvedOptions),
|
|
791
|
+
codexConfig: getCodexMcpConfig(codexOptions),
|
|
792
|
+
codexConfigOverrides: getCodexConfigOverrides(codexOptions),
|
|
745
793
|
};
|
|
746
794
|
}
|
|
747
795
|
|
|
@@ -753,25 +801,25 @@ function shellArray(name, values) {
|
|
|
753
801
|
return `${name}=(${values.map((value) => shellEscape(value)).join(" ")})`;
|
|
754
802
|
}
|
|
755
803
|
|
|
756
|
-
|
|
804
|
+
function toDelimited(policy) {
|
|
757
805
|
const RS = "\x1e";
|
|
758
806
|
return [
|
|
759
807
|
policy.requestedProfile,
|
|
760
808
|
policy.resolvedProfile,
|
|
761
809
|
policy.hint,
|
|
762
|
-
policy.
|
|
763
|
-
policy.codexConfigOverrides.flatMap((o) => ["-c", o]).join("
|
|
810
|
+
policy.allowedServers.join(","),
|
|
811
|
+
policy.codexConfigOverrides.flatMap((o) => ["-c", o]).join("\x1f"),
|
|
764
812
|
JSON.stringify(policy.codexConfig),
|
|
765
813
|
policy.resolvedPhase || "",
|
|
766
814
|
].join(RS);
|
|
767
815
|
}
|
|
768
816
|
|
|
769
|
-
|
|
817
|
+
function toShellExports(policy) {
|
|
770
818
|
const lines = [
|
|
771
819
|
`MCP_PROFILE_REQUESTED=${shellEscape(policy.requestedProfile)}`,
|
|
772
820
|
`MCP_RESOLVED_PROFILE=${shellEscape(policy.resolvedProfile)}`,
|
|
773
821
|
`MCP_HINT=${shellEscape(policy.hint)}`,
|
|
774
|
-
shellArray("
|
|
822
|
+
shellArray("ALLOWED_MCP_SERVERS", policy.allowedServers),
|
|
775
823
|
shellArray(
|
|
776
824
|
"CODEX_CONFIG_FLAGS",
|
|
777
825
|
policy.codexConfigOverrides.flatMap((override) => ["-c", override]),
|
|
@@ -789,8 +837,10 @@ function parseCliArgs(argv) {
|
|
|
789
837
|
command: "json",
|
|
790
838
|
agentType: "",
|
|
791
839
|
requestedProfile: "auto",
|
|
792
|
-
availableServers:
|
|
840
|
+
availableServers: undefined,
|
|
793
841
|
inventoryFile: "",
|
|
842
|
+
cliType: "",
|
|
843
|
+
codexConfig: "",
|
|
794
844
|
searchTool: "",
|
|
795
845
|
taskText: "",
|
|
796
846
|
workerIndex: undefined,
|
|
@@ -821,6 +871,12 @@ function parseCliArgs(argv) {
|
|
|
821
871
|
case "--available":
|
|
822
872
|
args.availableServers = parseAvailableServers(next());
|
|
823
873
|
break;
|
|
874
|
+
case "--cli-type":
|
|
875
|
+
args.cliType = next();
|
|
876
|
+
break;
|
|
877
|
+
case "--codex-config":
|
|
878
|
+
args.codexConfig = next();
|
|
879
|
+
break;
|
|
824
880
|
case "--inventory-file":
|
|
825
881
|
args.inventoryFile = next();
|
|
826
882
|
break;
|
|
@@ -844,7 +900,7 @@ function parseCliArgs(argv) {
|
|
|
844
900
|
return args;
|
|
845
901
|
}
|
|
846
902
|
|
|
847
|
-
|
|
903
|
+
async function runCli(argv = process.argv.slice(2)) {
|
|
848
904
|
let args;
|
|
849
905
|
try {
|
|
850
906
|
args = parseCliArgs(argv);
|
|
@@ -224,7 +224,7 @@ export function parseMcpServersFromToml(content = "") {
|
|
|
224
224
|
return servers;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
function readMcpServers(configPath = DEFAULT_CONFIG_PATH) {
|
|
228
228
|
if (!existsSync(configPath)) return {};
|
|
229
229
|
try {
|
|
230
230
|
const content = readFileSync(configPath, "utf8");
|
|
@@ -754,7 +754,7 @@ function renderOutput(results, source, format) {
|
|
|
754
754
|
return JSON.stringify({ source, healthy, dead, results }, null, 2);
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
-
|
|
757
|
+
async function runCli(argv = process.argv.slice(2)) {
|
|
758
758
|
let args;
|
|
759
759
|
try {
|
|
760
760
|
args = parseCliArgs(argv);
|
|
@@ -296,7 +296,7 @@ export function uniqueStrings(values = []) {
|
|
|
296
296
|
];
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
function inferDomainTagsFromText(text = "") {
|
|
300
300
|
if (typeof text !== "string" || !text.trim()) return [];
|
|
301
301
|
const normalized = text.toLocaleLowerCase();
|
|
302
302
|
const matched = [];
|
|
@@ -314,7 +314,7 @@ export function inferDomainTagsFromText(text = "") {
|
|
|
314
314
|
return uniqueStrings(matched);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
function getDefaultServerMetadata(serverName = "") {
|
|
318
318
|
const toolCount = MCP_SERVER_TOOL_CATALOG[serverName]?.length || 0;
|
|
319
319
|
const domainTags = uniqueStrings([
|
|
320
320
|
...(MCP_SERVER_DOMAIN_TAGS[serverName] || []),
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const PSMUX_RECOMMENDED_VERSION = "3.3.1";
|
|
4
|
+
const PSMUX_REQUIRED_COMMANDS = [
|
|
5
5
|
"new-session",
|
|
6
6
|
"attach-session",
|
|
7
7
|
"kill-session",
|
|
8
8
|
"capture-pane",
|
|
9
9
|
];
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const PSMUX_OPTIONAL_COMMANDS = ["detach-client"];
|
|
12
12
|
|
|
13
13
|
// Windows 전용 설치 명령
|
|
14
|
-
|
|
14
|
+
const PSMUX_INSTALL_COMMANDS = [
|
|
15
15
|
"winget install psmux",
|
|
16
16
|
"scoop install psmux",
|
|
17
17
|
"choco install psmux",
|
|
18
18
|
"cargo install psmux",
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const PSMUX_UPDATE_COMMANDS = [
|
|
22
22
|
"winget upgrade psmux",
|
|
23
23
|
"scoop update psmux",
|
|
24
24
|
"choco upgrade psmux",
|
|
25
25
|
"cargo install psmux --force",
|
|
26
26
|
];
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
function getPsmuxInstallCommandsFor(platform = process.platform) {
|
|
29
29
|
if (platform === "win32") return PSMUX_INSTALL_COMMANDS;
|
|
30
30
|
return [platform === "darwin" ? "brew install tmux" : "apt install tmux"];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
function getPsmuxUpdateCommandsFor(platform = process.platform) {
|
|
34
34
|
if (platform === "win32") return PSMUX_UPDATE_COMMANDS;
|
|
35
35
|
return [
|
|
36
36
|
platform === "darwin"
|
|
@@ -39,7 +39,7 @@ export function getPsmuxUpdateCommandsFor(platform = process.platform) {
|
|
|
39
39
|
];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
function formatPsmuxCommandList(
|
|
43
43
|
commands = PSMUX_INSTALL_COMMANDS,
|
|
44
44
|
indent = "",
|
|
45
45
|
) {
|
|
@@ -60,12 +60,12 @@ export function formatPsmuxUpdateGuidance(
|
|
|
60
60
|
return formatPsmuxCommandList(getPsmuxUpdateCommandsFor(platform), indent);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
function parsePsmuxVersion(output = "") {
|
|
64
64
|
const match = String(output).match(/psmux\s+v?(\d+\.\d+\.\d+)/i);
|
|
65
65
|
return match?.[1] || null;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
function compareSemver(a, b) {
|
|
69
69
|
const left = String(a || "")
|
|
70
70
|
.split(".")
|
|
71
71
|
.map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -79,7 +79,7 @@ export function compareSemver(a, b) {
|
|
|
79
79
|
return 0;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
function isRecommendedPsmuxVersion(version) {
|
|
83
83
|
if (!version) return false;
|
|
84
84
|
return compareSemver(version, PSMUX_RECOMMENDED_VERSION) >= 0;
|
|
85
85
|
}
|
|
@@ -143,51 +143,3 @@ export function probePsmuxSupport(options = {}) {
|
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
export function probePrimaryMultiplexerSupport(options = {}) {
|
|
148
|
-
const platform = options.platform || process.platform;
|
|
149
|
-
const execFileSyncFn = options.execFileSyncFn || execFileSync;
|
|
150
|
-
|
|
151
|
-
if (platform === "win32") {
|
|
152
|
-
return {
|
|
153
|
-
kind: "psmux",
|
|
154
|
-
...probePsmuxSupport(options),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const bin = options.bin || "tmux";
|
|
159
|
-
try {
|
|
160
|
-
const versionOutput = execFileSyncFn(bin, ["-V"], {
|
|
161
|
-
encoding: "utf8",
|
|
162
|
-
timeout: 2000,
|
|
163
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
164
|
-
windowsHide: true,
|
|
165
|
-
});
|
|
166
|
-
return {
|
|
167
|
-
ok: true,
|
|
168
|
-
installed: true,
|
|
169
|
-
kind: "tmux",
|
|
170
|
-
version: String(versionOutput || "").trim() || null,
|
|
171
|
-
recommendedVersion: null,
|
|
172
|
-
recommended: true,
|
|
173
|
-
missingCommands: [],
|
|
174
|
-
missingOptionalCommands: [],
|
|
175
|
-
installHint: formatPsmuxInstallGuidance(" ", platform),
|
|
176
|
-
updateHint: formatPsmuxUpdateGuidance(" ", platform),
|
|
177
|
-
};
|
|
178
|
-
} catch (error) {
|
|
179
|
-
return {
|
|
180
|
-
ok: false,
|
|
181
|
-
installed: false,
|
|
182
|
-
kind: "tmux",
|
|
183
|
-
version: null,
|
|
184
|
-
recommendedVersion: null,
|
|
185
|
-
recommended: false,
|
|
186
|
-
missingCommands: ["tmux"],
|
|
187
|
-
missingOptionalCommands: [],
|
|
188
|
-
installHint: formatPsmuxInstallGuidance(" ", platform),
|
|
189
|
-
updateHint: formatPsmuxUpdateGuidance(" ", platform),
|
|
190
|
-
error: error?.message || String(error),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
@@ -139,7 +139,7 @@ function commandUsesClaudePrintMode(command) {
|
|
|
139
139
|
);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
function shouldSkipInteractiveRegistration(payload, seams = {}) {
|
|
142
|
+
export function shouldSkipInteractiveRegistration(payload, seams = {}) {
|
|
143
143
|
const declaredKind = String(
|
|
144
144
|
payload?.sessionKind || payload?.session_kind || "",
|
|
145
145
|
)
|