repowisestage 0.0.68 → 0.0.70
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/dist/bin/repowise.js +1497 -1348
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -620,388 +620,69 @@ var init_process_manager = __esm({
|
|
|
620
620
|
}
|
|
621
621
|
});
|
|
622
622
|
|
|
623
|
-
// ../listener/dist/
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
if (err) {
|
|
640
|
-
reject(err);
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
resolve5(String(stdout ?? ""));
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
function plistPath() {
|
|
648
|
-
return join13(homedir3(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
649
|
-
}
|
|
650
|
-
function logDir() {
|
|
651
|
-
return join13(getConfigDir(), "logs");
|
|
652
|
-
}
|
|
653
|
-
function buildPlist() {
|
|
654
|
-
const cmd = resolveListenerCommand();
|
|
655
|
-
const logs = logDir();
|
|
656
|
-
const programArgs = [process.execPath, cmd.script, ...cmd.args].map((a) => ` <string>${a}</string>`).join("\n");
|
|
657
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
658
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
659
|
-
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
660
|
-
<plist version="1.0">
|
|
661
|
-
<dict>
|
|
662
|
-
<key>Label</key>
|
|
663
|
-
<string>${PLIST_LABEL}</string>
|
|
664
|
-
<key>ProgramArguments</key>
|
|
665
|
-
<array>
|
|
666
|
-
${programArgs}
|
|
667
|
-
</array>
|
|
668
|
-
<key>RunAtLoad</key>
|
|
669
|
-
<true/>
|
|
670
|
-
<key>KeepAlive</key>
|
|
671
|
-
<true/>
|
|
672
|
-
<key>StandardOutPath</key>
|
|
673
|
-
<string>${join13(logs, "listener-stdout.log")}</string>
|
|
674
|
-
<key>StandardErrorPath</key>
|
|
675
|
-
<string>${join13(logs, "listener-stderr.log")}</string>
|
|
676
|
-
<key>ProcessType</key>
|
|
677
|
-
<string>Background</string>
|
|
678
|
-
<!--
|
|
679
|
-
SoftResourceLimits: raise the open-file descriptor limit from the macOS
|
|
680
|
-
default of 256 to 4096. When multiple LSP child processes (rust-analyzer,
|
|
681
|
-
jdtls, etc.) share the listener's fd budget they can exhaust the default
|
|
682
|
-
very quickly, causing EMFILE errors. 4096 matches the system-wide default
|
|
683
|
-
set by /etc/launchd.conf on modern macOS and gives enough headroom for
|
|
684
|
-
~10 concurrent LSP servers each opening ~300 fds.
|
|
685
|
-
|
|
686
|
-
MemoryLimit: intentionally NOT set here. The launchd MemoryLimit key
|
|
687
|
-
(available since macOS 12.3) terminates the entire LaunchAgent when RSS
|
|
688
|
-
exceeds the threshold \u2014 it cannot be scoped to individual child processes.
|
|
689
|
-
Killing the listener to evict a memory-hungry rust-analyzer instance is
|
|
690
|
-
undesirable. Per-child memory pressure is better handled by the LSP
|
|
691
|
-
process manager (process-manager.ts) or by OS-level memory pressure
|
|
692
|
-
signals (SIGTERM on macOS, OOM killer on Linux).
|
|
693
|
-
-->
|
|
694
|
-
<key>SoftResourceLimits</key>
|
|
695
|
-
<dict>
|
|
696
|
-
<key>NumberOfFiles</key>
|
|
697
|
-
<integer>4096</integer>
|
|
698
|
-
</dict>
|
|
699
|
-
</dict>
|
|
700
|
-
</plist>`;
|
|
701
|
-
}
|
|
702
|
-
async function darwinInstall() {
|
|
703
|
-
await mkdir8(logDir(), { recursive: true });
|
|
704
|
-
await mkdir8(join13(homedir3(), "Library", "LaunchAgents"), { recursive: true });
|
|
705
|
-
try {
|
|
706
|
-
await exec("launchctl", ["unload", plistPath()]);
|
|
707
|
-
} catch {
|
|
708
|
-
}
|
|
709
|
-
await writeFile8(plistPath(), buildPlist());
|
|
710
|
-
await exec("launchctl", ["load", plistPath()]);
|
|
711
|
-
}
|
|
712
|
-
async function darwinUninstall() {
|
|
713
|
-
try {
|
|
714
|
-
await exec("launchctl", ["unload", plistPath()]);
|
|
715
|
-
} catch {
|
|
716
|
-
}
|
|
717
|
-
try {
|
|
718
|
-
await unlink6(plistPath());
|
|
719
|
-
} catch {
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
async function darwinIsInstalled() {
|
|
723
|
-
try {
|
|
724
|
-
const stdout = await exec("launchctl", ["list"]);
|
|
725
|
-
return stdout.includes(PLIST_LABEL);
|
|
726
|
-
} catch {
|
|
727
|
-
return false;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
function unitPath() {
|
|
731
|
-
return join13(homedir3(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
|
|
732
|
-
}
|
|
733
|
-
function buildUnit() {
|
|
734
|
-
const cmd = resolveListenerCommand();
|
|
735
|
-
const execStart = [process.execPath, cmd.script, ...cmd.args].join(" ");
|
|
736
|
-
const logs = logDir();
|
|
737
|
-
return `[Unit]
|
|
738
|
-
Description=RepoWise Listener
|
|
739
|
-
After=network-online.target
|
|
740
|
-
Wants=network-online.target
|
|
741
|
-
|
|
742
|
-
[Service]
|
|
743
|
-
Type=simple
|
|
744
|
-
ExecStart=${execStart}
|
|
745
|
-
Restart=always
|
|
746
|
-
RestartSec=10
|
|
747
|
-
StandardOutput=append:${join13(logs, "listener-stdout.log")}
|
|
748
|
-
StandardError=append:${join13(logs, "listener-stderr.log")}
|
|
749
|
-
|
|
750
|
-
[Install]
|
|
751
|
-
WantedBy=default.target`;
|
|
752
|
-
}
|
|
753
|
-
async function linuxInstall() {
|
|
754
|
-
await mkdir8(logDir(), { recursive: true });
|
|
755
|
-
await mkdir8(join13(homedir3(), ".config", "systemd", "user"), { recursive: true });
|
|
756
|
-
await writeFile8(unitPath(), buildUnit());
|
|
757
|
-
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
758
|
-
await exec("systemctl", ["--user", "enable", SYSTEMD_SERVICE]);
|
|
759
|
-
await exec("systemctl", ["--user", "start", SYSTEMD_SERVICE]);
|
|
760
|
-
}
|
|
761
|
-
async function linuxUninstall() {
|
|
762
|
-
try {
|
|
763
|
-
await exec("systemctl", ["--user", "stop", SYSTEMD_SERVICE]);
|
|
764
|
-
} catch {
|
|
765
|
-
}
|
|
766
|
-
try {
|
|
767
|
-
await exec("systemctl", ["--user", "disable", SYSTEMD_SERVICE]);
|
|
768
|
-
} catch {
|
|
769
|
-
}
|
|
770
|
-
try {
|
|
771
|
-
await unlink6(unitPath());
|
|
772
|
-
} catch {
|
|
773
|
-
}
|
|
774
|
-
try {
|
|
775
|
-
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
776
|
-
} catch {
|
|
777
|
-
}
|
|
623
|
+
// ../listener/dist/lsp/registry.js
|
|
624
|
+
function resolvePhpLspOverride(env = process.env, configOverrides) {
|
|
625
|
+
const envChoice = env["PHP_LSP"];
|
|
626
|
+
const configChoice = configOverrides?.["php"];
|
|
627
|
+
const choice = envChoice ?? configChoice;
|
|
628
|
+
if (choice !== "intelephense")
|
|
629
|
+
return null;
|
|
630
|
+
return {
|
|
631
|
+
id: "intelephense",
|
|
632
|
+
displayName: "intelephense (user-provided)",
|
|
633
|
+
command: "intelephense",
|
|
634
|
+
args: ["--stdio"],
|
|
635
|
+
extensions: [".php"],
|
|
636
|
+
lspLanguageId: "php",
|
|
637
|
+
installHint: "Intelephense override is enabled \u2014 install it yourself: `npm i -g intelephense` (commercial licence required for premium features)."
|
|
638
|
+
};
|
|
778
639
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
return false;
|
|
640
|
+
function getEffectiveConfig(lang, env = process.env, configOverrides) {
|
|
641
|
+
if (lang === "php") {
|
|
642
|
+
const override = resolvePhpLspOverride(env, configOverrides);
|
|
643
|
+
if (override)
|
|
644
|
+
return override;
|
|
785
645
|
}
|
|
646
|
+
return LSP_REGISTRY[lang]?.[0];
|
|
786
647
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
"/create",
|
|
793
|
-
"/tn",
|
|
794
|
-
TASK_NAME,
|
|
795
|
-
"/tr",
|
|
796
|
-
taskCmd,
|
|
797
|
-
"/sc",
|
|
798
|
-
"onlogon",
|
|
799
|
-
"/ru",
|
|
800
|
-
process.env.USERNAME ?? "",
|
|
801
|
-
"/f"
|
|
802
|
-
]);
|
|
803
|
-
await exec("schtasks", ["/run", "/tn", TASK_NAME]);
|
|
804
|
-
}
|
|
805
|
-
async function win32Uninstall() {
|
|
806
|
-
try {
|
|
807
|
-
await exec("schtasks", ["/end", "/tn", TASK_NAME]);
|
|
808
|
-
} catch {
|
|
809
|
-
}
|
|
810
|
-
try {
|
|
811
|
-
await exec("schtasks", ["/delete", "/tn", TASK_NAME, "/f"]);
|
|
812
|
-
} catch {
|
|
648
|
+
function getEffectiveConfigList(lang, env = process.env, configOverrides) {
|
|
649
|
+
if (lang === "php") {
|
|
650
|
+
const override = resolvePhpLspOverride(env, configOverrides);
|
|
651
|
+
if (override)
|
|
652
|
+
return [override];
|
|
813
653
|
}
|
|
654
|
+
return LSP_REGISTRY[lang] ?? [];
|
|
814
655
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return
|
|
819
|
-
|
|
820
|
-
|
|
656
|
+
function detectLanguage(path) {
|
|
657
|
+
const dot = path.lastIndexOf(".");
|
|
658
|
+
if (dot < 0)
|
|
659
|
+
return null;
|
|
660
|
+
const ext = path.slice(dot).toLowerCase();
|
|
661
|
+
for (const [lang, configs] of Object.entries(LSP_REGISTRY)) {
|
|
662
|
+
if (configs.some((c) => c.extensions.includes(ext))) {
|
|
663
|
+
return lang;
|
|
664
|
+
}
|
|
821
665
|
}
|
|
666
|
+
return null;
|
|
822
667
|
}
|
|
823
|
-
async function
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
668
|
+
async function probeServers(isAvailable, env = process.env, configOverrides) {
|
|
669
|
+
const out = [];
|
|
670
|
+
for (const lang of Object.keys(LSP_REGISTRY)) {
|
|
671
|
+
const configs = getEffectiveConfigList(lang, env, configOverrides);
|
|
672
|
+
const checkedCommands = configs.map((c) => c.command);
|
|
673
|
+
let found = null;
|
|
674
|
+
for (const config2 of configs) {
|
|
675
|
+
if (await isAvailable(config2.command)) {
|
|
676
|
+
found = config2;
|
|
677
|
+
break;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
out.push({ language: lang, config: found, checkedCommands });
|
|
827
681
|
}
|
|
682
|
+
return out;
|
|
828
683
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
async function win32Stop() {
|
|
833
|
-
await exec("schtasks", ["/end", "/tn", TASK_NAME]);
|
|
834
|
-
}
|
|
835
|
-
async function darwinIsServiceRunning() {
|
|
836
|
-
try {
|
|
837
|
-
const stdout = await exec("launchctl", ["list", PLIST_LABEL]);
|
|
838
|
-
const pidMatch = stdout.match(/"PID"\s*=\s*(\d+)/);
|
|
839
|
-
return pidMatch !== null && parseInt(pidMatch[1], 10) > 0;
|
|
840
|
-
} catch {
|
|
841
|
-
return false;
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
async function linuxIsServiceRunning() {
|
|
845
|
-
try {
|
|
846
|
-
const stdout = await exec("systemctl", ["--user", "is-active", SYSTEMD_SERVICE]);
|
|
847
|
-
return stdout.trim() === "active";
|
|
848
|
-
} catch {
|
|
849
|
-
return false;
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
async function win32IsServiceRunning() {
|
|
853
|
-
try {
|
|
854
|
-
const stdout = await exec("schtasks", ["/query", "/tn", TASK_NAME, "/fo", "CSV"]);
|
|
855
|
-
return stdout.includes("Running");
|
|
856
|
-
} catch {
|
|
857
|
-
return false;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
async function stopService() {
|
|
861
|
-
switch (process.platform) {
|
|
862
|
-
case "darwin":
|
|
863
|
-
await darwinStop();
|
|
864
|
-
break;
|
|
865
|
-
case "linux":
|
|
866
|
-
await linuxStop();
|
|
867
|
-
break;
|
|
868
|
-
case "win32":
|
|
869
|
-
await win32Stop();
|
|
870
|
-
break;
|
|
871
|
-
default:
|
|
872
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
async function install() {
|
|
876
|
-
switch (process.platform) {
|
|
877
|
-
case "darwin":
|
|
878
|
-
await darwinInstall();
|
|
879
|
-
break;
|
|
880
|
-
case "linux":
|
|
881
|
-
await linuxInstall();
|
|
882
|
-
break;
|
|
883
|
-
case "win32":
|
|
884
|
-
await win32Install();
|
|
885
|
-
break;
|
|
886
|
-
default:
|
|
887
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
async function uninstall() {
|
|
891
|
-
switch (process.platform) {
|
|
892
|
-
case "darwin":
|
|
893
|
-
await darwinUninstall();
|
|
894
|
-
break;
|
|
895
|
-
case "linux":
|
|
896
|
-
await linuxUninstall();
|
|
897
|
-
break;
|
|
898
|
-
case "win32":
|
|
899
|
-
await win32Uninstall();
|
|
900
|
-
break;
|
|
901
|
-
default:
|
|
902
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
async function isInstalled() {
|
|
906
|
-
switch (process.platform) {
|
|
907
|
-
case "darwin":
|
|
908
|
-
return darwinIsInstalled();
|
|
909
|
-
case "linux":
|
|
910
|
-
return linuxIsInstalled();
|
|
911
|
-
case "win32":
|
|
912
|
-
return win32IsInstalled();
|
|
913
|
-
default:
|
|
914
|
-
return false;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
async function isServiceRunning() {
|
|
918
|
-
switch (process.platform) {
|
|
919
|
-
case "darwin":
|
|
920
|
-
return darwinIsServiceRunning();
|
|
921
|
-
case "linux":
|
|
922
|
-
return linuxIsServiceRunning();
|
|
923
|
-
case "win32":
|
|
924
|
-
return win32IsServiceRunning();
|
|
925
|
-
default:
|
|
926
|
-
return false;
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
var IS_STAGING, PLIST_LABEL, SYSTEMD_SERVICE, TASK_NAME;
|
|
930
|
-
var init_service_installer = __esm({
|
|
931
|
-
"../listener/dist/service-installer.js"() {
|
|
932
|
-
"use strict";
|
|
933
|
-
init_config_dir();
|
|
934
|
-
init_process_manager();
|
|
935
|
-
IS_STAGING = true ? true : false;
|
|
936
|
-
PLIST_LABEL = IS_STAGING ? "com.repowise-staging.listener" : "com.repowise.listener";
|
|
937
|
-
SYSTEMD_SERVICE = IS_STAGING ? "repowise-staging-listener" : "repowise-listener";
|
|
938
|
-
TASK_NAME = IS_STAGING ? "RepoWise Staging Listener" : "RepoWise Listener";
|
|
939
|
-
}
|
|
940
|
-
});
|
|
941
|
-
|
|
942
|
-
// ../listener/dist/lsp/registry.js
|
|
943
|
-
function resolvePhpLspOverride(env = process.env, configOverrides) {
|
|
944
|
-
const envChoice = env["PHP_LSP"];
|
|
945
|
-
const configChoice = configOverrides?.["php"];
|
|
946
|
-
const choice = envChoice ?? configChoice;
|
|
947
|
-
if (choice !== "intelephense")
|
|
948
|
-
return null;
|
|
949
|
-
return {
|
|
950
|
-
id: "intelephense",
|
|
951
|
-
displayName: "intelephense (user-provided)",
|
|
952
|
-
command: "intelephense",
|
|
953
|
-
args: ["--stdio"],
|
|
954
|
-
extensions: [".php"],
|
|
955
|
-
lspLanguageId: "php",
|
|
956
|
-
installHint: "Intelephense override is enabled \u2014 install it yourself: `npm i -g intelephense` (commercial licence required for premium features)."
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
function getEffectiveConfig(lang, env = process.env, configOverrides) {
|
|
960
|
-
if (lang === "php") {
|
|
961
|
-
const override = resolvePhpLspOverride(env, configOverrides);
|
|
962
|
-
if (override)
|
|
963
|
-
return override;
|
|
964
|
-
}
|
|
965
|
-
return LSP_REGISTRY[lang]?.[0];
|
|
966
|
-
}
|
|
967
|
-
function getEffectiveConfigList(lang, env = process.env, configOverrides) {
|
|
968
|
-
if (lang === "php") {
|
|
969
|
-
const override = resolvePhpLspOverride(env, configOverrides);
|
|
970
|
-
if (override)
|
|
971
|
-
return [override];
|
|
972
|
-
}
|
|
973
|
-
return LSP_REGISTRY[lang] ?? [];
|
|
974
|
-
}
|
|
975
|
-
function detectLanguage(path) {
|
|
976
|
-
const dot = path.lastIndexOf(".");
|
|
977
|
-
if (dot < 0)
|
|
978
|
-
return null;
|
|
979
|
-
const ext = path.slice(dot).toLowerCase();
|
|
980
|
-
for (const [lang, configs] of Object.entries(LSP_REGISTRY)) {
|
|
981
|
-
if (configs.some((c) => c.extensions.includes(ext))) {
|
|
982
|
-
return lang;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
return null;
|
|
986
|
-
}
|
|
987
|
-
async function probeServers(isAvailable, env = process.env, configOverrides) {
|
|
988
|
-
const out = [];
|
|
989
|
-
for (const lang of Object.keys(LSP_REGISTRY)) {
|
|
990
|
-
const configs = getEffectiveConfigList(lang, env, configOverrides);
|
|
991
|
-
const checkedCommands = configs.map((c) => c.command);
|
|
992
|
-
let found = null;
|
|
993
|
-
for (const config2 of configs) {
|
|
994
|
-
if (await isAvailable(config2.command)) {
|
|
995
|
-
found = config2;
|
|
996
|
-
break;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
out.push({ language: lang, config: found, checkedCommands });
|
|
1000
|
-
}
|
|
1001
|
-
return out;
|
|
1002
|
-
}
|
|
1003
|
-
function getBuildSpec(language) {
|
|
1004
|
-
return BUILD_SPECS[language] ?? null;
|
|
684
|
+
function getBuildSpec(language) {
|
|
685
|
+
return BUILD_SPECS[language] ?? null;
|
|
1005
686
|
}
|
|
1006
687
|
var LSP_REGISTRY, BUILD_SPECS;
|
|
1007
688
|
var init_registry = __esm({
|
|
@@ -1415,7 +1096,7 @@ var init_registry = __esm({
|
|
|
1415
1096
|
});
|
|
1416
1097
|
|
|
1417
1098
|
// ../listener/dist/lsp/jdk-probe.js
|
|
1418
|
-
import { spawn as
|
|
1099
|
+
import { spawn as spawn2 } from "child_process";
|
|
1419
1100
|
function parseJavaMajorVersion(stderr) {
|
|
1420
1101
|
const modernMatch = /\b(?:openjdk|java) version "(\d+)(?:\.\d+)*(?:[._]\w+)?"/.exec(stderr);
|
|
1421
1102
|
if (!modernMatch?.[1])
|
|
@@ -1430,166 +1111,503 @@ function parseJavaMajorVersion(stderr) {
|
|
|
1430
1111
|
return Number.isFinite(legacy) ? legacy : void 0;
|
|
1431
1112
|
}
|
|
1432
1113
|
}
|
|
1433
|
-
return first;
|
|
1114
|
+
return first;
|
|
1115
|
+
}
|
|
1116
|
+
async function probeJdk(options = {}) {
|
|
1117
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
1118
|
+
return new Promise((resolve5) => {
|
|
1119
|
+
let stderr = "";
|
|
1120
|
+
let settled = false;
|
|
1121
|
+
const child = spawn2("java", ["-version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
1122
|
+
const timer = setTimeout(() => {
|
|
1123
|
+
if (settled)
|
|
1124
|
+
return;
|
|
1125
|
+
settled = true;
|
|
1126
|
+
try {
|
|
1127
|
+
child.kill("SIGKILL");
|
|
1128
|
+
} catch {
|
|
1129
|
+
}
|
|
1130
|
+
resolve5({ present: false });
|
|
1131
|
+
}, timeoutMs);
|
|
1132
|
+
child.stderr.on("data", (chunk) => {
|
|
1133
|
+
stderr += chunk.toString("utf8");
|
|
1134
|
+
});
|
|
1135
|
+
child.on("error", () => {
|
|
1136
|
+
if (settled)
|
|
1137
|
+
return;
|
|
1138
|
+
settled = true;
|
|
1139
|
+
clearTimeout(timer);
|
|
1140
|
+
resolve5({ present: false });
|
|
1141
|
+
});
|
|
1142
|
+
child.on("close", (code) => {
|
|
1143
|
+
if (settled)
|
|
1144
|
+
return;
|
|
1145
|
+
settled = true;
|
|
1146
|
+
clearTimeout(timer);
|
|
1147
|
+
if (code !== 0) {
|
|
1148
|
+
resolve5({ present: false, rawOutput: stderr.trim() });
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
const major = parseJavaMajorVersion(stderr);
|
|
1152
|
+
if (major === void 0) {
|
|
1153
|
+
resolve5({ present: true, rawOutput: stderr.trim() });
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
resolve5({ present: true, majorVersion: major, rawOutput: stderr.trim() });
|
|
1157
|
+
});
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
var init_jdk_probe = __esm({
|
|
1161
|
+
"../listener/dist/lsp/jdk-probe.js"() {
|
|
1162
|
+
"use strict";
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
// ../listener/dist/lsp/native-installer.js
|
|
1167
|
+
import { createWriteStream } from "fs";
|
|
1168
|
+
import { promises as fs } from "fs";
|
|
1169
|
+
import { createGunzip } from "zlib";
|
|
1170
|
+
import { spawn as spawn3 } from "child_process";
|
|
1171
|
+
import { pipeline } from "stream/promises";
|
|
1172
|
+
import { createHash as createHash3 } from "crypto";
|
|
1173
|
+
import { join as join13, dirname as dirname5 } from "path";
|
|
1174
|
+
function getNativeLspDir() {
|
|
1175
|
+
return join13(getLspInstallDir(), "native");
|
|
1176
|
+
}
|
|
1177
|
+
function getNativeLspBinDir() {
|
|
1178
|
+
return join13(getNativeLspDir(), "bin");
|
|
1179
|
+
}
|
|
1180
|
+
async function ensureNativeLspInstalled(lspKey) {
|
|
1181
|
+
const entry = NATIVE_LSP_VERSIONS[lspKey];
|
|
1182
|
+
if (!entry)
|
|
1183
|
+
return { installed: false, alreadyPresent: false, skipped: "no-native-version" };
|
|
1184
|
+
const platformKey = getCurrentPlatformKey();
|
|
1185
|
+
if (!platformKey) {
|
|
1186
|
+
return { installed: false, alreadyPresent: false, skipped: "unsupported-platform" };
|
|
1187
|
+
}
|
|
1188
|
+
const asset = entry.assets[platformKey];
|
|
1189
|
+
if (!asset) {
|
|
1190
|
+
return { installed: false, alreadyPresent: false, skipped: "unsupported-platform" };
|
|
1191
|
+
}
|
|
1192
|
+
if (entry.requiresJdk !== void 0) {
|
|
1193
|
+
const jdk = await probeJdk();
|
|
1194
|
+
if (!jdk.present || jdk.majorVersion === void 0 || jdk.majorVersion < entry.requiresJdk) {
|
|
1195
|
+
return {
|
|
1196
|
+
installed: false,
|
|
1197
|
+
alreadyPresent: false,
|
|
1198
|
+
skipped: "jvm-missing",
|
|
1199
|
+
error: `${lspKey} requires JDK ${entry.requiresJdk.toString()}+ (found: ${jdk.present ? `Java ${jdk.majorVersion?.toString() ?? "?"}` : "no java on PATH"}). Install with: brew install openjdk@21 (macOS) or apt install openjdk-21-jdk (Linux)`
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
const usesWrapper = Boolean(asset.launcherJarGlob && asset.wrapperBinaryName);
|
|
1204
|
+
const versionDir = join13(getNativeLspDir(), lspKey, entry.version);
|
|
1205
|
+
if (usesWrapper && asset.launcherJarGlob && asset.wrapperBinaryName) {
|
|
1206
|
+
const jarPath = await resolveGlobInsideDir(versionDir, asset.launcherJarGlob);
|
|
1207
|
+
const shimPath = join13(getNativeLspBinDir(), asset.wrapperBinaryName);
|
|
1208
|
+
if (jarPath && await pathExists(shimPath)) {
|
|
1209
|
+
return { installed: false, alreadyPresent: true, binaryPath: shimPath };
|
|
1210
|
+
}
|
|
1211
|
+
} else {
|
|
1212
|
+
const installedBinary = join13(versionDir, asset.binaryPath);
|
|
1213
|
+
if (await pathExists(installedBinary)) {
|
|
1214
|
+
await ensureSymlinkInBin(lspKey, installedBinary, asset.binaryPath);
|
|
1215
|
+
return { installed: false, alreadyPresent: true, binaryPath: installedBinary };
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
try {
|
|
1219
|
+
await fs.mkdir(versionDir, { recursive: true });
|
|
1220
|
+
const tmpDownload = join13(versionDir, `.${asset.filename}.download`);
|
|
1221
|
+
const downloadUrl = entry.source.kind === "github-release" ? `https://github.com/${entry.source.repo}/releases/download/${entry.version}/${asset.filename}` : asset.url ?? "";
|
|
1222
|
+
if (!downloadUrl) {
|
|
1223
|
+
return {
|
|
1224
|
+
installed: false,
|
|
1225
|
+
alreadyPresent: false,
|
|
1226
|
+
error: `direct-url asset for ${lspKey} missing required \`url\` field`
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
await downloadFile(downloadUrl, tmpDownload);
|
|
1230
|
+
if (asset.sha256) {
|
|
1231
|
+
const actual = await sha256File(tmpDownload);
|
|
1232
|
+
if (actual !== asset.sha256) {
|
|
1233
|
+
await fs.unlink(tmpDownload).catch(() => void 0);
|
|
1234
|
+
return {
|
|
1235
|
+
installed: false,
|
|
1236
|
+
alreadyPresent: false,
|
|
1237
|
+
error: `SHA256 mismatch for ${lspKey}: expected ${asset.sha256}, got ${actual}`
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
} else {
|
|
1241
|
+
console.warn(`[lsp-install] WARN: SHA256 verification skipped for ${lspKey} (no pin in NATIVE_LSP_VERSIONS) \u2014 run apps/listener/scripts/pin-native-shas.ts to record one`);
|
|
1242
|
+
}
|
|
1243
|
+
await extractAsset(tmpDownload, versionDir, asset);
|
|
1244
|
+
await fs.unlink(tmpDownload).catch(() => void 0);
|
|
1245
|
+
if (usesWrapper && asset.launcherJarGlob && asset.wrapperBinaryName) {
|
|
1246
|
+
const jarPath = await resolveGlobInsideDir(versionDir, asset.launcherJarGlob);
|
|
1247
|
+
if (!jarPath) {
|
|
1248
|
+
return {
|
|
1249
|
+
installed: false,
|
|
1250
|
+
alreadyPresent: false,
|
|
1251
|
+
error: `extract completed but no JAR matched ${asset.launcherJarGlob} in ${versionDir}`
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
const shimPath = await writeJdtlsWrapper({
|
|
1255
|
+
binaryName: asset.wrapperBinaryName,
|
|
1256
|
+
versionDir,
|
|
1257
|
+
launcherJarPath: jarPath
|
|
1258
|
+
});
|
|
1259
|
+
await pruneStaleVersions(lspKey, entry.version);
|
|
1260
|
+
return { installed: true, alreadyPresent: false, binaryPath: shimPath };
|
|
1261
|
+
}
|
|
1262
|
+
const installedBinary = join13(versionDir, asset.binaryPath);
|
|
1263
|
+
if (!await pathExists(installedBinary)) {
|
|
1264
|
+
return {
|
|
1265
|
+
installed: false,
|
|
1266
|
+
alreadyPresent: false,
|
|
1267
|
+
error: `extract completed but binary missing at ${installedBinary}`
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
await fs.chmod(installedBinary, 493).catch(() => void 0);
|
|
1271
|
+
await ensureSymlinkInBin(lspKey, installedBinary, asset.binaryPath);
|
|
1272
|
+
await pruneStaleVersions(lspKey, entry.version);
|
|
1273
|
+
return { installed: true, alreadyPresent: false, binaryPath: installedBinary };
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
return {
|
|
1276
|
+
installed: false,
|
|
1277
|
+
alreadyPresent: false,
|
|
1278
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
async function resolveGlobInsideDir(versionDir, glob) {
|
|
1283
|
+
const parts = glob.split("/");
|
|
1284
|
+
let dir = versionDir;
|
|
1285
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
1286
|
+
dir = join13(dir, parts[i]);
|
|
1287
|
+
}
|
|
1288
|
+
const pattern = parts[parts.length - 1];
|
|
1289
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
1290
|
+
const re = new RegExp(`^${escaped}$`);
|
|
1291
|
+
let entries;
|
|
1292
|
+
try {
|
|
1293
|
+
entries = await fs.readdir(dir);
|
|
1294
|
+
} catch {
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
const matches = entries.filter((e) => re.test(e)).sort();
|
|
1298
|
+
const last = matches[matches.length - 1];
|
|
1299
|
+
return last ? join13(dir, last) : null;
|
|
1300
|
+
}
|
|
1301
|
+
async function pruneStaleVersions(lspKey, currentVersion) {
|
|
1302
|
+
const lspDir = join13(getNativeLspDir(), lspKey);
|
|
1303
|
+
let entries;
|
|
1304
|
+
try {
|
|
1305
|
+
entries = await fs.readdir(lspDir);
|
|
1306
|
+
} catch {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
await Promise.all(entries.filter((name) => name !== currentVersion).map(async (name) => {
|
|
1310
|
+
try {
|
|
1311
|
+
await fs.rm(join13(lspDir, name), { recursive: true, force: true });
|
|
1312
|
+
} catch {
|
|
1313
|
+
}
|
|
1314
|
+
}));
|
|
1315
|
+
}
|
|
1316
|
+
function shQuote(value) {
|
|
1317
|
+
return value.replace(/[\\"$`]/g, (ch) => `\\${ch}`);
|
|
1318
|
+
}
|
|
1319
|
+
function cmdQuote(value) {
|
|
1320
|
+
return value.replace(/"/g, '""').replace(/%/g, "%%");
|
|
1321
|
+
}
|
|
1322
|
+
async function writeJdtlsWrapper(input) {
|
|
1323
|
+
const binDir = getNativeLspBinDir();
|
|
1324
|
+
await fs.mkdir(binDir, { recursive: true });
|
|
1325
|
+
const shimPath = join13(binDir, input.binaryName);
|
|
1326
|
+
const platformCfgDir = process.platform === "darwin" ? "config_mac" : process.platform === "win32" ? "config_win" : "config_linux";
|
|
1327
|
+
const workspaceBase = join13(input.versionDir, "workspaces");
|
|
1328
|
+
const qLauncher = shQuote(input.launcherJarPath);
|
|
1329
|
+
const qConfig = shQuote(`${input.versionDir}/${platformCfgDir}`);
|
|
1330
|
+
const qWorkspaceBase = shQuote(workspaceBase);
|
|
1331
|
+
const unixScript = `#!/usr/bin/env bash
|
|
1332
|
+
# Generated by repowise listener \u2014 do not edit by hand.
|
|
1333
|
+
# Invokes Eclipse JDT.LS via the equinox launcher.
|
|
1334
|
+
set -euo pipefail
|
|
1335
|
+
WS_NAME="\${REPOWISE_JDTLS_WS_NAME:-default}"
|
|
1336
|
+
WS_DIR="${qWorkspaceBase}/\${WS_NAME}"
|
|
1337
|
+
mkdir -p "$WS_DIR"
|
|
1338
|
+
exec java \\
|
|
1339
|
+
-Declipse.application=org.eclipse.jdt.ls.core.id1 \\
|
|
1340
|
+
-Dosgi.bundles.defaultStartLevel=4 \\
|
|
1341
|
+
-Declipse.product=org.eclipse.jdt.ls.core.product \\
|
|
1342
|
+
-Dlog.level=ALL \\
|
|
1343
|
+
-Xms1g \\
|
|
1344
|
+
--add-modules=ALL-SYSTEM \\
|
|
1345
|
+
--add-opens java.base/java.util=ALL-UNNAMED \\
|
|
1346
|
+
--add-opens java.base/java.lang=ALL-UNNAMED \\
|
|
1347
|
+
-jar "${qLauncher}" \\
|
|
1348
|
+
-configuration "${qConfig}" \\
|
|
1349
|
+
-data "$WS_DIR" \\
|
|
1350
|
+
"$@"
|
|
1351
|
+
`;
|
|
1352
|
+
await fs.writeFile(shimPath, unixScript);
|
|
1353
|
+
await fs.chmod(shimPath, 493);
|
|
1354
|
+
if (process.platform === "win32") {
|
|
1355
|
+
const winShim = `${shimPath}.cmd`;
|
|
1356
|
+
const cqLauncher = cmdQuote(input.launcherJarPath);
|
|
1357
|
+
const cqConfig = cmdQuote(`${input.versionDir}\\${platformCfgDir}`);
|
|
1358
|
+
const cqWorkspaceBase = cmdQuote(workspaceBase);
|
|
1359
|
+
const winScript = `@echo off\r
|
|
1360
|
+
rem Generated by repowise listener\r
|
|
1361
|
+
if "%REPOWISE_JDTLS_WS_NAME%"=="" set REPOWISE_JDTLS_WS_NAME=default\r
|
|
1362
|
+
set WS_DIR=${cqWorkspaceBase}\\%REPOWISE_JDTLS_WS_NAME%\r
|
|
1363
|
+
if not exist "%WS_DIR%" mkdir "%WS_DIR%"\r
|
|
1364
|
+
java ^\r
|
|
1365
|
+
-Declipse.application=org.eclipse.jdt.ls.core.id1 ^\r
|
|
1366
|
+
-Dosgi.bundles.defaultStartLevel=4 ^\r
|
|
1367
|
+
-Declipse.product=org.eclipse.jdt.ls.core.product ^\r
|
|
1368
|
+
-Dlog.level=ALL ^\r
|
|
1369
|
+
-Xms1g ^\r
|
|
1370
|
+
--add-modules=ALL-SYSTEM ^\r
|
|
1371
|
+
--add-opens java.base/java.util=ALL-UNNAMED ^\r
|
|
1372
|
+
--add-opens java.base/java.lang=ALL-UNNAMED ^\r
|
|
1373
|
+
-jar "${cqLauncher}" ^\r
|
|
1374
|
+
-configuration "${cqConfig}" ^\r
|
|
1375
|
+
-data "%WS_DIR%" ^\r
|
|
1376
|
+
%*\r
|
|
1377
|
+
`;
|
|
1378
|
+
await fs.writeFile(winShim, winScript);
|
|
1379
|
+
}
|
|
1380
|
+
return shimPath;
|
|
1381
|
+
}
|
|
1382
|
+
async function ensureSymlinkInBin(lspKey, target, sourceAssetPath) {
|
|
1383
|
+
const binDir = getNativeLspBinDir();
|
|
1384
|
+
await fs.mkdir(binDir, { recursive: true });
|
|
1385
|
+
const winExtMatch = process.platform === "win32" && sourceAssetPath ? /\.(exe|bat|cmd|ps1)$/i.exec(sourceAssetPath) : null;
|
|
1386
|
+
const linkName = winExtMatch ? `${lspKey}${winExtMatch[0].toLowerCase()}` : lspKey;
|
|
1387
|
+
const linkPath = join13(binDir, linkName);
|
|
1388
|
+
try {
|
|
1389
|
+
await fs.unlink(linkPath);
|
|
1390
|
+
} catch {
|
|
1391
|
+
}
|
|
1392
|
+
try {
|
|
1393
|
+
await fs.symlink(target, linkPath);
|
|
1394
|
+
} catch (err) {
|
|
1395
|
+
if (err.code === "EPERM" || process.platform === "win32") {
|
|
1396
|
+
await fs.copyFile(target, linkPath);
|
|
1397
|
+
} else {
|
|
1398
|
+
throw err;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
async function downloadFile(url, dest) {
|
|
1403
|
+
const res = await fetch(url);
|
|
1404
|
+
if (!res.ok || !res.body) {
|
|
1405
|
+
throw new Error(`download ${url} failed: HTTP ${res.status.toString()}`);
|
|
1406
|
+
}
|
|
1407
|
+
await fs.mkdir(dirname5(dest), { recursive: true });
|
|
1408
|
+
const sink = createWriteStream(dest);
|
|
1409
|
+
await pipeline(res.body, sink);
|
|
1410
|
+
}
|
|
1411
|
+
async function sha256File(path) {
|
|
1412
|
+
const hash = createHash3("sha256");
|
|
1413
|
+
const data = await fs.readFile(path);
|
|
1414
|
+
hash.update(data);
|
|
1415
|
+
return hash.digest("hex");
|
|
1416
|
+
}
|
|
1417
|
+
async function extractAsset(source, destDir, asset) {
|
|
1418
|
+
const filename = asset.filename.toLowerCase();
|
|
1419
|
+
if (filename.endsWith(".tar.gz") || filename.endsWith(".tgz")) {
|
|
1420
|
+
await runExternal("tar", ["-xzf", source, "-C", destDir]);
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
if (filename.endsWith(".zip")) {
|
|
1424
|
+
if (process.platform === "win32") {
|
|
1425
|
+
await runExternal("powershell.exe", [
|
|
1426
|
+
"-NoProfile",
|
|
1427
|
+
"-Command",
|
|
1428
|
+
`Expand-Archive -Path '${source}' -DestinationPath '${destDir}' -Force`
|
|
1429
|
+
]);
|
|
1430
|
+
} else {
|
|
1431
|
+
await runExternal("unzip", ["-o", "-q", source, "-d", destDir]);
|
|
1432
|
+
}
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
if (filename.endsWith(".gz")) {
|
|
1436
|
+
const outPath = join13(destDir, asset.binaryPath);
|
|
1437
|
+
await fs.mkdir(dirname5(outPath), { recursive: true });
|
|
1438
|
+
await pipeline((await fs.open(source)).createReadStream(), createGunzip(), createWriteStream(outPath));
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
await fs.copyFile(source, join13(destDir, asset.binaryPath));
|
|
1434
1442
|
}
|
|
1435
|
-
async function
|
|
1436
|
-
|
|
1437
|
-
|
|
1443
|
+
async function runExternal(cmd, args) {
|
|
1444
|
+
return new Promise((resolve5, reject) => {
|
|
1445
|
+
const child = spawn3(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1438
1446
|
let stderr = "";
|
|
1439
|
-
let settled = false;
|
|
1440
|
-
const child = spawn3("java", ["-version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
1441
|
-
const timer = setTimeout(() => {
|
|
1442
|
-
if (settled)
|
|
1443
|
-
return;
|
|
1444
|
-
settled = true;
|
|
1445
|
-
try {
|
|
1446
|
-
child.kill("SIGKILL");
|
|
1447
|
-
} catch {
|
|
1448
|
-
}
|
|
1449
|
-
resolve5({ present: false });
|
|
1450
|
-
}, timeoutMs);
|
|
1451
1447
|
child.stderr.on("data", (chunk) => {
|
|
1452
|
-
stderr += chunk.toString(
|
|
1453
|
-
});
|
|
1454
|
-
child.on("error", () => {
|
|
1455
|
-
if (settled)
|
|
1456
|
-
return;
|
|
1457
|
-
settled = true;
|
|
1458
|
-
clearTimeout(timer);
|
|
1459
|
-
resolve5({ present: false });
|
|
1448
|
+
stderr += chunk.toString();
|
|
1460
1449
|
});
|
|
1450
|
+
child.on("error", reject);
|
|
1461
1451
|
child.on("close", (code) => {
|
|
1462
|
-
if (
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
if (code !== 0) {
|
|
1467
|
-
resolve5({ present: false, rawOutput: stderr.trim() });
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
const major = parseJavaMajorVersion(stderr);
|
|
1471
|
-
if (major === void 0) {
|
|
1472
|
-
resolve5({ present: true, rawOutput: stderr.trim() });
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
resolve5({ present: true, majorVersion: major, rawOutput: stderr.trim() });
|
|
1452
|
+
if (code === 0)
|
|
1453
|
+
resolve5();
|
|
1454
|
+
else
|
|
1455
|
+
reject(new Error(`${cmd} ${args.join(" ")} exited ${(code ?? -1).toString()}: ${stderr.split("\n").slice(0, 3).join(" ")}`));
|
|
1476
1456
|
});
|
|
1477
1457
|
});
|
|
1478
1458
|
}
|
|
1479
|
-
|
|
1480
|
-
|
|
1459
|
+
async function pathExists(p) {
|
|
1460
|
+
try {
|
|
1461
|
+
await fs.access(p);
|
|
1462
|
+
return true;
|
|
1463
|
+
} catch {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
var init_native_installer = __esm({
|
|
1468
|
+
"../listener/dist/lsp/native-installer.js"() {
|
|
1481
1469
|
"use strict";
|
|
1470
|
+
init_src();
|
|
1471
|
+
init_installer();
|
|
1472
|
+
init_jdk_probe();
|
|
1482
1473
|
}
|
|
1483
1474
|
});
|
|
1484
1475
|
|
|
1485
|
-
// ../listener/dist/lsp/
|
|
1486
|
-
import {
|
|
1487
|
-
import { promises as fs } from "fs";
|
|
1488
|
-
import { createGunzip } from "zlib";
|
|
1476
|
+
// ../listener/dist/lsp/coursier-installer.js
|
|
1477
|
+
import { promises as fs2 } from "fs";
|
|
1489
1478
|
import { spawn as spawn4 } from "child_process";
|
|
1490
|
-
import {
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
function getNativeLspDir() {
|
|
1494
|
-
return join15(getLspInstallDir(), "native");
|
|
1495
|
-
}
|
|
1496
|
-
function getNativeLspBinDir() {
|
|
1497
|
-
return join15(getNativeLspDir(), "bin");
|
|
1479
|
+
import { join as join14 } from "path";
|
|
1480
|
+
function getCoursierBinDir() {
|
|
1481
|
+
return join14(getLspInstallDir(), "coursier-bin");
|
|
1498
1482
|
}
|
|
1499
|
-
async function
|
|
1500
|
-
const entry =
|
|
1501
|
-
if (!entry)
|
|
1502
|
-
return { installed: false, alreadyPresent: false, skipped: "no-
|
|
1503
|
-
const platformKey = getCurrentPlatformKey();
|
|
1504
|
-
if (!platformKey) {
|
|
1505
|
-
return { installed: false, alreadyPresent: false, skipped: "unsupported-platform" };
|
|
1483
|
+
async function ensureCoursierLspInstalled(key) {
|
|
1484
|
+
const entry = COURSIER_LSPS[key];
|
|
1485
|
+
if (!entry) {
|
|
1486
|
+
return { installed: false, alreadyPresent: false, skipped: "no-coursier-entry" };
|
|
1506
1487
|
}
|
|
1507
|
-
const
|
|
1508
|
-
|
|
1509
|
-
|
|
1488
|
+
const binDir = getCoursierBinDir();
|
|
1489
|
+
const binaryPath = join14(binDir, entry.appName);
|
|
1490
|
+
const binaryPathExe = join14(binDir, `${entry.appName}.bat`);
|
|
1491
|
+
if (await pathExists2(binaryPath) || await pathExists2(binaryPathExe)) {
|
|
1492
|
+
return { installed: false, alreadyPresent: true, binaryPath };
|
|
1510
1493
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1494
|
+
const csBootstrap = await ensureNativeLspInstalled("coursier");
|
|
1495
|
+
if (csBootstrap.skipped || !csBootstrap.installed && !csBootstrap.alreadyPresent) {
|
|
1496
|
+
return {
|
|
1497
|
+
installed: false,
|
|
1498
|
+
alreadyPresent: false,
|
|
1499
|
+
skipped: "coursier-bootstrap-failed",
|
|
1500
|
+
error: csBootstrap.error ?? csBootstrap.skipped
|
|
1501
|
+
};
|
|
1521
1502
|
}
|
|
1522
|
-
const
|
|
1523
|
-
const
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
if (await pathExists(installedBinary)) {
|
|
1533
|
-
await ensureSymlinkInBin(lspKey, installedBinary, asset.binaryPath);
|
|
1534
|
-
return { installed: false, alreadyPresent: true, binaryPath: installedBinary };
|
|
1535
|
-
}
|
|
1503
|
+
const csPath = join14(getNativeLspBinDir(), "coursier");
|
|
1504
|
+
const csPathExe = join14(getNativeLspBinDir(), "coursier.exe");
|
|
1505
|
+
const cs = await pathExists2(csPath) ? csPath : await pathExists2(csPathExe) ? csPathExe : null;
|
|
1506
|
+
if (!cs) {
|
|
1507
|
+
return {
|
|
1508
|
+
installed: false,
|
|
1509
|
+
alreadyPresent: false,
|
|
1510
|
+
skipped: "coursier-bootstrap-failed",
|
|
1511
|
+
error: `coursier launcher not found at ${csPath} after bootstrap`
|
|
1512
|
+
};
|
|
1536
1513
|
}
|
|
1537
1514
|
try {
|
|
1538
|
-
await
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
if (!downloadUrl) {
|
|
1515
|
+
await fs2.mkdir(binDir, { recursive: true });
|
|
1516
|
+
await runCs(cs, ["install", "--install-dir", binDir, entry.appName]);
|
|
1517
|
+
if (!await pathExists2(binaryPath) && !await pathExists2(binaryPathExe)) {
|
|
1542
1518
|
return {
|
|
1543
1519
|
installed: false,
|
|
1544
1520
|
alreadyPresent: false,
|
|
1545
|
-
error: `
|
|
1521
|
+
error: `cs install ${entry.appName} completed but launcher missing at ${binaryPath}`
|
|
1546
1522
|
};
|
|
1547
1523
|
}
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
if (
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1524
|
+
return { installed: true, alreadyPresent: false, binaryPath };
|
|
1525
|
+
} catch (err) {
|
|
1526
|
+
return {
|
|
1527
|
+
installed: false,
|
|
1528
|
+
alreadyPresent: false,
|
|
1529
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
async function runCs(cs, args) {
|
|
1534
|
+
return new Promise((resolve5, reject) => {
|
|
1535
|
+
const child = spawn4(cs, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1536
|
+
let stderr = "";
|
|
1537
|
+
child.stderr.on("data", (chunk) => {
|
|
1538
|
+
stderr += chunk.toString();
|
|
1539
|
+
});
|
|
1540
|
+
child.on("error", reject);
|
|
1541
|
+
child.on("close", (code) => {
|
|
1542
|
+
if (code === 0)
|
|
1543
|
+
resolve5();
|
|
1544
|
+
else
|
|
1545
|
+
reject(new Error(`cs ${args.join(" ")} exited ${(code ?? -1).toString()}: ${stderr.split("\n").slice(0, 3).join(" ")}`));
|
|
1546
|
+
});
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
async function pathExists2(p) {
|
|
1550
|
+
try {
|
|
1551
|
+
await fs2.access(p);
|
|
1552
|
+
return true;
|
|
1553
|
+
} catch {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
var init_coursier_installer = __esm({
|
|
1558
|
+
"../listener/dist/lsp/coursier-installer.js"() {
|
|
1559
|
+
"use strict";
|
|
1560
|
+
init_src();
|
|
1561
|
+
init_installer();
|
|
1562
|
+
init_native_installer();
|
|
1563
|
+
}
|
|
1564
|
+
});
|
|
1565
|
+
|
|
1566
|
+
// ../listener/dist/lsp/toolchain-installer.js
|
|
1567
|
+
import { spawn as spawn5 } from "child_process";
|
|
1568
|
+
import { promises as fs3 } from "fs";
|
|
1569
|
+
import { homedir as homedir3 } from "os";
|
|
1570
|
+
import { join as join15 } from "path";
|
|
1571
|
+
async function ensureToolchainLspInstalled(key) {
|
|
1572
|
+
const entry = TOOLCHAIN_LSPS[key];
|
|
1573
|
+
if (!entry) {
|
|
1574
|
+
return { installed: false, alreadyPresent: false, skipped: "no-toolchain-entry" };
|
|
1575
|
+
}
|
|
1576
|
+
if (entry.bundled) {
|
|
1577
|
+
const found = await isCommandOnPath(entry.binaryName);
|
|
1578
|
+
if (found)
|
|
1579
|
+
return { installed: false, alreadyPresent: true };
|
|
1580
|
+
return { installed: false, alreadyPresent: false, skipped: "bundled-not-installable" };
|
|
1581
|
+
}
|
|
1582
|
+
if (await isCommandOnPath(entry.binaryName)) {
|
|
1583
|
+
return { installed: false, alreadyPresent: true, skipped: "already-on-path" };
|
|
1584
|
+
}
|
|
1585
|
+
if (!entry.toolchain) {
|
|
1586
|
+
return { installed: false, alreadyPresent: false, skipped: "toolchain-missing" };
|
|
1587
|
+
}
|
|
1588
|
+
if (!await isCommandOnPath(entry.toolchain)) {
|
|
1589
|
+
return {
|
|
1590
|
+
installed: false,
|
|
1591
|
+
alreadyPresent: false,
|
|
1592
|
+
skipped: "toolchain-missing",
|
|
1593
|
+
error: `${entry.toolchain} toolchain not on PATH`
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
let binDir;
|
|
1597
|
+
try {
|
|
1598
|
+
binDir = await resolveToolchainBinDir(entry);
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
return {
|
|
1601
|
+
installed: false,
|
|
1602
|
+
alreadyPresent: false,
|
|
1603
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
try {
|
|
1607
|
+
if (!entry.installArgs) {
|
|
1608
|
+
return { installed: false, alreadyPresent: false, skipped: "toolchain-missing" };
|
|
1588
1609
|
}
|
|
1589
|
-
await
|
|
1590
|
-
await ensureSymlinkInBin(lspKey, installedBinary, asset.binaryPath);
|
|
1591
|
-
await pruneStaleVersions(lspKey, entry.version);
|
|
1592
|
-
return { installed: true, alreadyPresent: false, binaryPath: installedBinary };
|
|
1610
|
+
await runToolchain(entry.toolchain, entry.installArgs);
|
|
1593
1611
|
} catch (err) {
|
|
1594
1612
|
return {
|
|
1595
1613
|
installed: false,
|
|
@@ -1597,714 +1615,766 @@ async function ensureNativeLspInstalled(lspKey) {
|
|
|
1597
1615
|
error: err instanceof Error ? err.message : String(err)
|
|
1598
1616
|
};
|
|
1599
1617
|
}
|
|
1618
|
+
const binaryPath = join15(binDir, entry.binaryName);
|
|
1619
|
+
if (!await pathExists3(binaryPath)) {
|
|
1620
|
+
return {
|
|
1621
|
+
installed: false,
|
|
1622
|
+
alreadyPresent: false,
|
|
1623
|
+
error: `${entry.toolchain} install of ${entry.binaryName} completed but binary missing at ${binaryPath}`,
|
|
1624
|
+
binDir
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
return { installed: true, alreadyPresent: false, binaryPath, binDir };
|
|
1600
1628
|
}
|
|
1601
|
-
async function
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
1605
|
-
dir = join15(dir, parts[i]);
|
|
1629
|
+
async function resolveToolchainBinDir(entry) {
|
|
1630
|
+
if (!entry.toolchain) {
|
|
1631
|
+
throw new Error("cannot resolve bin dir for entry without toolchain");
|
|
1606
1632
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
} catch {
|
|
1614
|
-
return null;
|
|
1633
|
+
if (entry.toolchainBinDir) {
|
|
1634
|
+
if (entry.toolchain === "go") {
|
|
1635
|
+
const gopath = process.env["GOPATH"] ?? join15(homedir3(), "go");
|
|
1636
|
+
return join15(gopath, "bin");
|
|
1637
|
+
}
|
|
1638
|
+
return join15(homedir3(), entry.toolchainBinDir);
|
|
1615
1639
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
}
|
|
1620
|
-
async function pruneStaleVersions(lspKey, currentVersion) {
|
|
1621
|
-
const lspDir = join15(getNativeLspDir(), lspKey);
|
|
1622
|
-
let entries;
|
|
1623
|
-
try {
|
|
1624
|
-
entries = await fs.readdir(lspDir);
|
|
1625
|
-
} catch {
|
|
1626
|
-
return;
|
|
1640
|
+
if (entry.toolchain === "gem") {
|
|
1641
|
+
const userdir = await captureStdout("gem", ["env", "userdir"]);
|
|
1642
|
+
return join15(userdir.trim(), "bin");
|
|
1627
1643
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1644
|
+
throw new Error(`no bin-dir resolution for toolchain ${entry.toolchain}`);
|
|
1645
|
+
}
|
|
1646
|
+
function getToolchainBinDirs() {
|
|
1647
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
1648
|
+
for (const entry of Object.values(TOOLCHAIN_LSPS)) {
|
|
1649
|
+
if (entry.bundled || !entry.toolchain || !entry.toolchainBinDir)
|
|
1650
|
+
continue;
|
|
1651
|
+
if (entry.toolchain === "go") {
|
|
1652
|
+
const gopath = process.env["GOPATH"] ?? join15(homedir3(), "go");
|
|
1653
|
+
dirs.add(join15(gopath, "bin"));
|
|
1654
|
+
} else {
|
|
1655
|
+
dirs.add(join15(homedir3(), entry.toolchainBinDir));
|
|
1632
1656
|
}
|
|
1633
|
-
}
|
|
1657
|
+
}
|
|
1658
|
+
return [...dirs];
|
|
1634
1659
|
}
|
|
1635
|
-
function
|
|
1636
|
-
return
|
|
1660
|
+
function runToolchain(cmd, args) {
|
|
1661
|
+
return new Promise((resolve5, reject) => {
|
|
1662
|
+
const child = spawn5(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1663
|
+
let stderr = "";
|
|
1664
|
+
child.stderr.on("data", (chunk) => {
|
|
1665
|
+
stderr += chunk.toString();
|
|
1666
|
+
});
|
|
1667
|
+
child.on("error", reject);
|
|
1668
|
+
child.on("close", (code) => {
|
|
1669
|
+
if (code === 0)
|
|
1670
|
+
resolve5();
|
|
1671
|
+
else
|
|
1672
|
+
reject(new Error(`${cmd} ${args.join(" ")} exited ${(code ?? -1).toString()}: ${stderr.split("\n").slice(0, 3).join(" ")}`));
|
|
1673
|
+
});
|
|
1674
|
+
});
|
|
1637
1675
|
}
|
|
1638
|
-
function
|
|
1639
|
-
return
|
|
1676
|
+
function captureStdout(cmd, args) {
|
|
1677
|
+
return new Promise((resolve5, reject) => {
|
|
1678
|
+
const child = spawn5(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1679
|
+
let stdout = "";
|
|
1680
|
+
let stderr = "";
|
|
1681
|
+
child.stdout.on("data", (chunk) => {
|
|
1682
|
+
stdout += chunk.toString();
|
|
1683
|
+
});
|
|
1684
|
+
child.stderr.on("data", (chunk) => {
|
|
1685
|
+
stderr += chunk.toString();
|
|
1686
|
+
});
|
|
1687
|
+
child.on("error", reject);
|
|
1688
|
+
child.on("close", (code) => {
|
|
1689
|
+
if (code === 0)
|
|
1690
|
+
resolve5(stdout);
|
|
1691
|
+
else
|
|
1692
|
+
reject(new Error(`${cmd} ${args.join(" ")} exited ${(code ?? -1).toString()}: ${stderr}`));
|
|
1693
|
+
});
|
|
1694
|
+
});
|
|
1640
1695
|
}
|
|
1641
|
-
async function
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
const unixScript = `#!/usr/bin/env bash
|
|
1651
|
-
# Generated by repowise listener \u2014 do not edit by hand.
|
|
1652
|
-
# Invokes Eclipse JDT.LS via the equinox launcher.
|
|
1653
|
-
set -euo pipefail
|
|
1654
|
-
WS_NAME="\${REPOWISE_JDTLS_WS_NAME:-default}"
|
|
1655
|
-
WS_DIR="${qWorkspaceBase}/\${WS_NAME}"
|
|
1656
|
-
mkdir -p "$WS_DIR"
|
|
1657
|
-
exec java \\
|
|
1658
|
-
-Declipse.application=org.eclipse.jdt.ls.core.id1 \\
|
|
1659
|
-
-Dosgi.bundles.defaultStartLevel=4 \\
|
|
1660
|
-
-Declipse.product=org.eclipse.jdt.ls.core.product \\
|
|
1661
|
-
-Dlog.level=ALL \\
|
|
1662
|
-
-Xms1g \\
|
|
1663
|
-
--add-modules=ALL-SYSTEM \\
|
|
1664
|
-
--add-opens java.base/java.util=ALL-UNNAMED \\
|
|
1665
|
-
--add-opens java.base/java.lang=ALL-UNNAMED \\
|
|
1666
|
-
-jar "${qLauncher}" \\
|
|
1667
|
-
-configuration "${qConfig}" \\
|
|
1668
|
-
-data "$WS_DIR" \\
|
|
1669
|
-
"$@"
|
|
1670
|
-
`;
|
|
1671
|
-
await fs.writeFile(shimPath, unixScript);
|
|
1672
|
-
await fs.chmod(shimPath, 493);
|
|
1673
|
-
if (process.platform === "win32") {
|
|
1674
|
-
const winShim = `${shimPath}.cmd`;
|
|
1675
|
-
const cqLauncher = cmdQuote(input.launcherJarPath);
|
|
1676
|
-
const cqConfig = cmdQuote(`${input.versionDir}\\${platformCfgDir}`);
|
|
1677
|
-
const cqWorkspaceBase = cmdQuote(workspaceBase);
|
|
1678
|
-
const winScript = `@echo off\r
|
|
1679
|
-
rem Generated by repowise listener\r
|
|
1680
|
-
if "%REPOWISE_JDTLS_WS_NAME%"=="" set REPOWISE_JDTLS_WS_NAME=default\r
|
|
1681
|
-
set WS_DIR=${cqWorkspaceBase}\\%REPOWISE_JDTLS_WS_NAME%\r
|
|
1682
|
-
if not exist "%WS_DIR%" mkdir "%WS_DIR%"\r
|
|
1683
|
-
java ^\r
|
|
1684
|
-
-Declipse.application=org.eclipse.jdt.ls.core.id1 ^\r
|
|
1685
|
-
-Dosgi.bundles.defaultStartLevel=4 ^\r
|
|
1686
|
-
-Declipse.product=org.eclipse.jdt.ls.core.product ^\r
|
|
1687
|
-
-Dlog.level=ALL ^\r
|
|
1688
|
-
-Xms1g ^\r
|
|
1689
|
-
--add-modules=ALL-SYSTEM ^\r
|
|
1690
|
-
--add-opens java.base/java.util=ALL-UNNAMED ^\r
|
|
1691
|
-
--add-opens java.base/java.lang=ALL-UNNAMED ^\r
|
|
1692
|
-
-jar "${cqLauncher}" ^\r
|
|
1693
|
-
-configuration "${cqConfig}" ^\r
|
|
1694
|
-
-data "%WS_DIR%" ^\r
|
|
1695
|
-
%*\r
|
|
1696
|
-
`;
|
|
1697
|
-
await fs.writeFile(winShim, winScript);
|
|
1698
|
-
}
|
|
1699
|
-
return shimPath;
|
|
1696
|
+
async function isCommandOnPath(command) {
|
|
1697
|
+
if (/[^\w./+-]/.test(command))
|
|
1698
|
+
return false;
|
|
1699
|
+
const probeCmd = process.platform === "win32" ? "where" : "which";
|
|
1700
|
+
return new Promise((resolve5) => {
|
|
1701
|
+
const child = spawn5(probeCmd, [command], { stdio: "ignore", timeout: 5e3 });
|
|
1702
|
+
child.on("error", () => resolve5(false));
|
|
1703
|
+
child.on("close", (code) => resolve5(code === 0));
|
|
1704
|
+
});
|
|
1700
1705
|
}
|
|
1701
|
-
async function
|
|
1702
|
-
const binDir = getNativeLspBinDir();
|
|
1703
|
-
await fs.mkdir(binDir, { recursive: true });
|
|
1704
|
-
const winExtMatch = process.platform === "win32" && sourceAssetPath ? /\.(exe|bat|cmd|ps1)$/i.exec(sourceAssetPath) : null;
|
|
1705
|
-
const linkName = winExtMatch ? `${lspKey}${winExtMatch[0].toLowerCase()}` : lspKey;
|
|
1706
|
-
const linkPath = join15(binDir, linkName);
|
|
1706
|
+
async function pathExists3(p) {
|
|
1707
1707
|
try {
|
|
1708
|
-
await
|
|
1708
|
+
await fs3.access(p);
|
|
1709
|
+
return true;
|
|
1709
1710
|
} catch {
|
|
1710
|
-
|
|
1711
|
-
try {
|
|
1712
|
-
await fs.symlink(target, linkPath);
|
|
1713
|
-
} catch (err) {
|
|
1714
|
-
if (err.code === "EPERM" || process.platform === "win32") {
|
|
1715
|
-
await fs.copyFile(target, linkPath);
|
|
1716
|
-
} else {
|
|
1717
|
-
throw err;
|
|
1718
|
-
}
|
|
1711
|
+
return false;
|
|
1719
1712
|
}
|
|
1720
1713
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1714
|
+
var init_toolchain_installer = __esm({
|
|
1715
|
+
"../listener/dist/lsp/toolchain-installer.js"() {
|
|
1716
|
+
"use strict";
|
|
1717
|
+
init_src();
|
|
1725
1718
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
// ../listener/dist/lsp/installer.js
|
|
1722
|
+
import { promises as fs4 } from "fs";
|
|
1723
|
+
import { join as join16, dirname as dirname6 } from "path";
|
|
1724
|
+
import { spawn as spawn6 } from "child_process";
|
|
1725
|
+
import lockfile3 from "proper-lockfile";
|
|
1726
|
+
function getLspInstallDir() {
|
|
1727
|
+
return join16(getConfigDir(), "lsp-servers");
|
|
1729
1728
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
const data = await fs.readFile(path);
|
|
1733
|
-
hash.update(data);
|
|
1734
|
-
return hash.digest("hex");
|
|
1729
|
+
function getLspBinDir() {
|
|
1730
|
+
return join16(getLspInstallDir(), "node_modules", ".bin");
|
|
1735
1731
|
}
|
|
1736
|
-
async function
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1732
|
+
async function ensureNpmLspInstalled(config2) {
|
|
1733
|
+
if (!config2.npmPackage)
|
|
1734
|
+
return { installed: false, skipped: "no-npm-package" };
|
|
1735
|
+
const installDir = getLspInstallDir();
|
|
1736
|
+
const binPath = join16(installDir, "node_modules", ".bin", config2.command);
|
|
1737
|
+
if (await pathExists4(binPath)) {
|
|
1738
|
+
return { installed: false, skipped: "already-present" };
|
|
1739
|
+
}
|
|
1740
|
+
try {
|
|
1741
|
+
await fs4.mkdir(installDir, { recursive: true });
|
|
1742
|
+
let release = null;
|
|
1743
|
+
try {
|
|
1744
|
+
release = await lockfile3.lock(installDir, {
|
|
1745
|
+
stale: 18e4,
|
|
1746
|
+
retries: { retries: 20, factor: 1.5, minTimeout: 500, maxTimeout: 5e3 },
|
|
1747
|
+
realpath: false
|
|
1748
|
+
});
|
|
1749
|
+
} catch {
|
|
1750
|
+
if (await pathExists4(binPath)) {
|
|
1751
|
+
return { installed: false, skipped: "already-present" };
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
try {
|
|
1755
|
+
if (await pathExists4(binPath)) {
|
|
1756
|
+
return { installed: false, skipped: "already-present" };
|
|
1757
|
+
}
|
|
1758
|
+
const pkgJsonPath = join16(installDir, "package.json");
|
|
1759
|
+
if (!await pathExists4(pkgJsonPath)) {
|
|
1760
|
+
await fs4.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
|
|
1761
|
+
}
|
|
1762
|
+
await runNpmInstall(installDir, config2.npmPackage);
|
|
1763
|
+
if (!await pathExists4(binPath)) {
|
|
1764
|
+
return {
|
|
1765
|
+
installed: false,
|
|
1766
|
+
error: `npm install completed but ${config2.command} still not at ${binPath}`
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
return { installed: true };
|
|
1770
|
+
} finally {
|
|
1771
|
+
if (release) {
|
|
1772
|
+
try {
|
|
1773
|
+
await release();
|
|
1774
|
+
} catch {
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
} catch (err) {
|
|
1779
|
+
return {
|
|
1780
|
+
installed: false,
|
|
1781
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1782
|
+
};
|
|
1741
1783
|
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
}
|
|
1750
|
-
await runExternal("unzip", ["-o", "-q", source, "-d", destDir]);
|
|
1784
|
+
}
|
|
1785
|
+
async function resolveNpmCommand() {
|
|
1786
|
+
const nodeDir = dirname6(process.execPath);
|
|
1787
|
+
for (const candidate of [join16(nodeDir, "npm"), join16(nodeDir, "npm.cmd")]) {
|
|
1788
|
+
try {
|
|
1789
|
+
await fs4.access(candidate);
|
|
1790
|
+
return candidate;
|
|
1791
|
+
} catch {
|
|
1751
1792
|
}
|
|
1752
|
-
return;
|
|
1753
1793
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1794
|
+
for (const candidate of ["/opt/homebrew/bin/npm", "/usr/local/bin/npm", "/usr/bin/npm"]) {
|
|
1795
|
+
try {
|
|
1796
|
+
await fs4.access(candidate);
|
|
1797
|
+
return candidate;
|
|
1798
|
+
} catch {
|
|
1799
|
+
}
|
|
1759
1800
|
}
|
|
1760
|
-
|
|
1801
|
+
return "npm";
|
|
1761
1802
|
}
|
|
1762
|
-
async function
|
|
1803
|
+
async function runNpmInstall(cwd, pkg2) {
|
|
1804
|
+
const npmCmd = await resolveNpmCommand();
|
|
1805
|
+
const nodeDir = dirname6(process.execPath);
|
|
1806
|
+
const augmentedPath = process.env.PATH ? `${nodeDir}:${process.env.PATH}` : nodeDir;
|
|
1763
1807
|
return new Promise((resolve5, reject) => {
|
|
1764
|
-
const child =
|
|
1808
|
+
const child = spawn6(npmCmd, ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
|
|
1809
|
+
cwd,
|
|
1810
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1811
|
+
env: { ...process.env, PATH: augmentedPath }
|
|
1812
|
+
});
|
|
1765
1813
|
let stderr = "";
|
|
1766
1814
|
child.stderr.on("data", (chunk) => {
|
|
1767
1815
|
stderr += chunk.toString();
|
|
1768
1816
|
});
|
|
1769
|
-
child.on("error", reject);
|
|
1817
|
+
child.on("error", (err) => reject(err));
|
|
1770
1818
|
child.on("close", (code) => {
|
|
1771
|
-
if (code === 0)
|
|
1819
|
+
if (code === 0) {
|
|
1772
1820
|
resolve5();
|
|
1773
|
-
else
|
|
1774
|
-
reject(new Error(
|
|
1821
|
+
} else {
|
|
1822
|
+
reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
|
|
1823
|
+
}
|
|
1775
1824
|
});
|
|
1776
1825
|
});
|
|
1777
1826
|
}
|
|
1778
|
-
|
|
1827
|
+
function sanitizeNpmStderr(raw) {
|
|
1828
|
+
const truncated = raw.split("\n").slice(0, 3).join(" ").trim();
|
|
1829
|
+
return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
|
|
1830
|
+
}
|
|
1831
|
+
async function pathExists4(p) {
|
|
1779
1832
|
try {
|
|
1780
|
-
await
|
|
1833
|
+
await fs4.access(p);
|
|
1781
1834
|
return true;
|
|
1782
1835
|
} catch {
|
|
1783
1836
|
return false;
|
|
1784
1837
|
}
|
|
1785
1838
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
}
|
|
1813
|
-
const csBootstrap = await ensureNativeLspInstalled("coursier");
|
|
1814
|
-
if (csBootstrap.skipped || !csBootstrap.installed && !csBootstrap.alreadyPresent) {
|
|
1815
|
-
return {
|
|
1816
|
-
installed: false,
|
|
1817
|
-
alreadyPresent: false,
|
|
1818
|
-
skipped: "coursier-bootstrap-failed",
|
|
1819
|
-
error: csBootstrap.error ?? csBootstrap.skipped
|
|
1820
|
-
};
|
|
1821
|
-
}
|
|
1822
|
-
const csPath = join16(getNativeLspBinDir(), "coursier");
|
|
1823
|
-
const csPathExe = join16(getNativeLspBinDir(), "coursier.exe");
|
|
1824
|
-
const cs = await pathExists2(csPath) ? csPath : await pathExists2(csPathExe) ? csPathExe : null;
|
|
1825
|
-
if (!cs) {
|
|
1826
|
-
return {
|
|
1827
|
-
installed: false,
|
|
1828
|
-
alreadyPresent: false,
|
|
1829
|
-
skipped: "coursier-bootstrap-failed",
|
|
1830
|
-
error: `coursier launcher not found at ${csPath} after bootstrap`
|
|
1831
|
-
};
|
|
1839
|
+
async function detectRepoLanguages(repoRoot) {
|
|
1840
|
+
const found = /* @__PURE__ */ new Set();
|
|
1841
|
+
let inspected = 0;
|
|
1842
|
+
const MAX_INSPECT = 200;
|
|
1843
|
+
async function inspect(dir) {
|
|
1844
|
+
if (inspected >= MAX_INSPECT)
|
|
1845
|
+
return;
|
|
1846
|
+
let entries;
|
|
1847
|
+
try {
|
|
1848
|
+
entries = await fs4.readdir(dir);
|
|
1849
|
+
} catch {
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
for (const name of entries) {
|
|
1853
|
+
if (inspected >= MAX_INSPECT)
|
|
1854
|
+
return;
|
|
1855
|
+
if (name.startsWith("."))
|
|
1856
|
+
continue;
|
|
1857
|
+
if (name === "node_modules" || name === "dist" || name === "build")
|
|
1858
|
+
continue;
|
|
1859
|
+
const lang = detectLanguage(name);
|
|
1860
|
+
if (lang) {
|
|
1861
|
+
found.add(lang);
|
|
1862
|
+
inspected += 1;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1832
1865
|
}
|
|
1866
|
+
await inspect(repoRoot);
|
|
1867
|
+
let topEntries = [];
|
|
1833
1868
|
try {
|
|
1834
|
-
await
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1869
|
+
topEntries = await fs4.readdir(repoRoot);
|
|
1870
|
+
} catch {
|
|
1871
|
+
return found;
|
|
1872
|
+
}
|
|
1873
|
+
for (const name of topEntries) {
|
|
1874
|
+
if (name.startsWith("."))
|
|
1875
|
+
continue;
|
|
1876
|
+
if (name === "node_modules" || name === "dist" || name === "build")
|
|
1877
|
+
continue;
|
|
1878
|
+
const sub = join16(repoRoot, name);
|
|
1879
|
+
try {
|
|
1880
|
+
const stat8 = await fs4.stat(sub);
|
|
1881
|
+
if (stat8.isDirectory())
|
|
1882
|
+
await inspect(sub);
|
|
1883
|
+
} catch {
|
|
1842
1884
|
}
|
|
1843
|
-
return { installed: true, alreadyPresent: false, binaryPath };
|
|
1844
|
-
} catch (err) {
|
|
1845
|
-
return {
|
|
1846
|
-
installed: false,
|
|
1847
|
-
alreadyPresent: false,
|
|
1848
|
-
error: err instanceof Error ? err.message : String(err)
|
|
1849
|
-
};
|
|
1850
1885
|
}
|
|
1886
|
+
return found;
|
|
1851
1887
|
}
|
|
1852
|
-
async function
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1888
|
+
async function prepareLspServersForRepos(repos, options = {}) {
|
|
1889
|
+
const detected = /* @__PURE__ */ new Set();
|
|
1890
|
+
for (const r of repos) {
|
|
1891
|
+
if (!r.localPath)
|
|
1892
|
+
continue;
|
|
1893
|
+
try {
|
|
1894
|
+
const stat8 = await fs4.stat(r.localPath);
|
|
1895
|
+
if (!stat8.isDirectory())
|
|
1896
|
+
continue;
|
|
1897
|
+
} catch {
|
|
1898
|
+
continue;
|
|
1899
|
+
}
|
|
1900
|
+
try {
|
|
1901
|
+
const langs = await detectRepoLanguages(r.localPath);
|
|
1902
|
+
for (const l of langs)
|
|
1903
|
+
detected.add(l);
|
|
1904
|
+
} catch {
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
const results = [];
|
|
1908
|
+
for (const language of detected) {
|
|
1909
|
+
const configs = getEffectiveConfigList(language, process.env, options.lspOverrides);
|
|
1910
|
+
const npmConfig = configs.find((c) => c.npmPackage);
|
|
1911
|
+
if (npmConfig) {
|
|
1912
|
+
const outcome = await ensureNpmLspInstalled(npmConfig);
|
|
1913
|
+
results.push({
|
|
1914
|
+
language,
|
|
1915
|
+
installed: outcome.installed,
|
|
1916
|
+
alreadyPresent: outcome.skipped === "already-present",
|
|
1917
|
+
skippedNoNpmPackage: false,
|
|
1918
|
+
installMethod: "npm",
|
|
1919
|
+
error: outcome.error
|
|
1920
|
+
});
|
|
1921
|
+
continue;
|
|
1922
|
+
}
|
|
1923
|
+
const nativeConfig = configs.find((c) => c.nativeInstallKey);
|
|
1924
|
+
if (nativeConfig?.nativeInstallKey) {
|
|
1925
|
+
const outcome = await ensureNativeLspInstalled(nativeConfig.nativeInstallKey);
|
|
1926
|
+
results.push({
|
|
1927
|
+
language,
|
|
1928
|
+
installed: outcome.installed,
|
|
1929
|
+
alreadyPresent: outcome.alreadyPresent,
|
|
1930
|
+
skippedNoNpmPackage: false,
|
|
1931
|
+
installMethod: "native",
|
|
1932
|
+
skipped: outcome.skipped,
|
|
1933
|
+
hint: outcome.skipped ? nativeConfig.installHint : void 0,
|
|
1934
|
+
error: outcome.error
|
|
1935
|
+
});
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
const coursierConfig = configs.find((c) => c.coursierInstallKey);
|
|
1939
|
+
if (coursierConfig?.coursierInstallKey) {
|
|
1940
|
+
const outcome = await ensureCoursierLspInstalled(coursierConfig.coursierInstallKey);
|
|
1941
|
+
results.push({
|
|
1942
|
+
language,
|
|
1943
|
+
installed: outcome.installed,
|
|
1944
|
+
alreadyPresent: outcome.alreadyPresent,
|
|
1945
|
+
skippedNoNpmPackage: false,
|
|
1946
|
+
installMethod: "coursier",
|
|
1947
|
+
skipped: outcome.skipped,
|
|
1948
|
+
hint: outcome.skipped ? coursierConfig.installHint : void 0,
|
|
1949
|
+
error: outcome.error
|
|
1950
|
+
});
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
const toolchainConfig = configs.find((c) => c.toolchainInstallKey);
|
|
1954
|
+
if (toolchainConfig?.toolchainInstallKey) {
|
|
1955
|
+
const outcome = await ensureToolchainLspInstalled(toolchainConfig.toolchainInstallKey);
|
|
1956
|
+
results.push({
|
|
1957
|
+
language,
|
|
1958
|
+
installed: outcome.installed,
|
|
1959
|
+
alreadyPresent: outcome.alreadyPresent,
|
|
1960
|
+
skippedNoNpmPackage: false,
|
|
1961
|
+
installMethod: "toolchain",
|
|
1962
|
+
skipped: outcome.skipped,
|
|
1963
|
+
// Surface the install hint for any skip reason — toolchain
|
|
1964
|
+
// missing means user needs to install it; bundled SDK means
|
|
1965
|
+
// user needs the SDK.
|
|
1966
|
+
hint: outcome.skipped ? toolchainConfig.installHint : void 0,
|
|
1967
|
+
error: outcome.error
|
|
1968
|
+
});
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
results.push({
|
|
1972
|
+
language,
|
|
1973
|
+
installed: false,
|
|
1974
|
+
alreadyPresent: false,
|
|
1975
|
+
skippedNoNpmPackage: true,
|
|
1976
|
+
hint: configs[0]?.installHint
|
|
1865
1977
|
});
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
async function pathExists2(p) {
|
|
1869
|
-
try {
|
|
1870
|
-
await fs2.access(p);
|
|
1871
|
-
return true;
|
|
1872
|
-
} catch {
|
|
1873
|
-
return false;
|
|
1874
1978
|
}
|
|
1979
|
+
return results;
|
|
1875
1980
|
}
|
|
1876
|
-
var
|
|
1877
|
-
"../listener/dist/lsp/
|
|
1981
|
+
var init_installer = __esm({
|
|
1982
|
+
"../listener/dist/lsp/installer.js"() {
|
|
1878
1983
|
"use strict";
|
|
1879
|
-
|
|
1880
|
-
|
|
1984
|
+
init_config_dir();
|
|
1985
|
+
init_registry();
|
|
1881
1986
|
init_native_installer();
|
|
1987
|
+
init_coursier_installer();
|
|
1988
|
+
init_toolchain_installer();
|
|
1882
1989
|
}
|
|
1883
1990
|
});
|
|
1884
1991
|
|
|
1885
|
-
// ../listener/dist/lsp/
|
|
1886
|
-
import { spawn as spawn6 } from "child_process";
|
|
1887
|
-
import { promises as fs3 } from "fs";
|
|
1992
|
+
// ../listener/dist/lsp/daemon-path.js
|
|
1888
1993
|
import { homedir as homedir4 } from "os";
|
|
1889
|
-
import { join as join17 } from "path";
|
|
1890
|
-
|
|
1891
|
-
const
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1994
|
+
import { delimiter, dirname as dirname7, join as join17 } from "path";
|
|
1995
|
+
function commonBinDirs() {
|
|
1996
|
+
const home = homedir4();
|
|
1997
|
+
return [
|
|
1998
|
+
"/opt/homebrew/bin",
|
|
1999
|
+
// Apple Silicon Homebrew
|
|
2000
|
+
"/opt/homebrew/sbin",
|
|
2001
|
+
"/usr/local/bin",
|
|
2002
|
+
// Intel Homebrew / common installs
|
|
2003
|
+
"/usr/bin",
|
|
2004
|
+
"/bin",
|
|
2005
|
+
"/usr/sbin",
|
|
2006
|
+
"/sbin",
|
|
2007
|
+
join17(home, ".local", "bin"),
|
|
2008
|
+
// pipx / pip --user / uv
|
|
2009
|
+
join17(home, ".npm-global", "bin"),
|
|
2010
|
+
// common npm global prefix
|
|
2011
|
+
join17(home, "go", "bin"),
|
|
2012
|
+
// gopls
|
|
2013
|
+
join17(home, ".cargo", "bin")
|
|
2014
|
+
// rust-analyzer via cargo
|
|
2015
|
+
];
|
|
2016
|
+
}
|
|
2017
|
+
function managedBinDirs() {
|
|
2018
|
+
return [getLspBinDir(), getNativeLspBinDir(), getCoursierBinDir(), ...getToolchainBinDirs()];
|
|
2019
|
+
}
|
|
2020
|
+
function dedup(dirs) {
|
|
2021
|
+
return [...new Set(dirs.filter((d) => d.length > 0))];
|
|
2022
|
+
}
|
|
2023
|
+
function daemonPathDirs() {
|
|
2024
|
+
return dedup([dirname7(process.execPath), ...commonBinDirs(), ...managedBinDirs()]);
|
|
2025
|
+
}
|
|
2026
|
+
function buildDaemonPath() {
|
|
2027
|
+
return daemonPathDirs().join(delimiter);
|
|
2028
|
+
}
|
|
2029
|
+
var init_daemon_path = __esm({
|
|
2030
|
+
"../listener/dist/lsp/daemon-path.js"() {
|
|
2031
|
+
"use strict";
|
|
2032
|
+
init_installer();
|
|
2033
|
+
init_native_installer();
|
|
2034
|
+
init_coursier_installer();
|
|
2035
|
+
init_toolchain_installer();
|
|
1924
2036
|
}
|
|
2037
|
+
});
|
|
2038
|
+
|
|
2039
|
+
// ../listener/dist/service-installer.js
|
|
2040
|
+
var service_installer_exports = {};
|
|
2041
|
+
__export(service_installer_exports, {
|
|
2042
|
+
install: () => install,
|
|
2043
|
+
isInstalled: () => isInstalled,
|
|
2044
|
+
isServiceRunning: () => isServiceRunning,
|
|
2045
|
+
stopService: () => stopService,
|
|
2046
|
+
uninstall: () => uninstall
|
|
2047
|
+
});
|
|
2048
|
+
import { execFile as execFile4 } from "child_process";
|
|
2049
|
+
import { writeFile as writeFile8, mkdir as mkdir8, unlink as unlink6 } from "fs/promises";
|
|
2050
|
+
import { homedir as homedir5 } from "os";
|
|
2051
|
+
import { join as join18 } from "path";
|
|
2052
|
+
function exec(cmd, args) {
|
|
2053
|
+
return new Promise((resolve5, reject) => {
|
|
2054
|
+
execFile4(cmd, args, (err, stdout) => {
|
|
2055
|
+
if (err) {
|
|
2056
|
+
reject(err);
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
resolve5(String(stdout ?? ""));
|
|
2060
|
+
});
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
function xmlEscape(value) {
|
|
2064
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2065
|
+
}
|
|
2066
|
+
function sanitizeEnvValue(value) {
|
|
2067
|
+
return Array.from(value).filter((ch) => ch.charCodeAt(0) >= 32).join("");
|
|
2068
|
+
}
|
|
2069
|
+
function plistPath() {
|
|
2070
|
+
return join18(homedir5(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
2071
|
+
}
|
|
2072
|
+
function logDir() {
|
|
2073
|
+
return join18(getConfigDir(), "logs");
|
|
2074
|
+
}
|
|
2075
|
+
function buildPlist() {
|
|
2076
|
+
const cmd = resolveListenerCommand();
|
|
2077
|
+
const logs = logDir();
|
|
2078
|
+
const programArgs = [process.execPath, cmd.script, ...cmd.args].map((a) => ` <string>${xmlEscape(a)}</string>`).join("\n");
|
|
2079
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2080
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
2081
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2082
|
+
<plist version="1.0">
|
|
2083
|
+
<dict>
|
|
2084
|
+
<key>Label</key>
|
|
2085
|
+
<string>${xmlEscape(PLIST_LABEL)}</string>
|
|
2086
|
+
<key>ProgramArguments</key>
|
|
2087
|
+
<array>
|
|
2088
|
+
${programArgs}
|
|
2089
|
+
</array>
|
|
2090
|
+
<key>RunAtLoad</key>
|
|
2091
|
+
<true/>
|
|
2092
|
+
<key>KeepAlive</key>
|
|
2093
|
+
<true/>
|
|
2094
|
+
<!--
|
|
2095
|
+
FIX-8: launchd inherits a minimal PATH (/usr/bin:/bin:\u2026) that excludes
|
|
2096
|
+
/opt/homebrew/bin + the npm-global bin, so user-installed LSP servers
|
|
2097
|
+
(pyright, rust-analyzer, \u2026) cannot be spawned and the typed-resolution
|
|
2098
|
+
which-probe fails. Inject a rich PATH (single source of truth:
|
|
2099
|
+
buildDaemonPath in lsp/daemon-path.ts) so the daemon resolves them.
|
|
2100
|
+
-->
|
|
2101
|
+
<key>EnvironmentVariables</key>
|
|
2102
|
+
<dict>
|
|
2103
|
+
<key>PATH</key>
|
|
2104
|
+
<string>${xmlEscape(buildDaemonPath())}</string>
|
|
2105
|
+
</dict>
|
|
2106
|
+
<key>StandardOutPath</key>
|
|
2107
|
+
<string>${xmlEscape(join18(logs, "listener-stdout.log"))}</string>
|
|
2108
|
+
<key>StandardErrorPath</key>
|
|
2109
|
+
<string>${xmlEscape(join18(logs, "listener-stderr.log"))}</string>
|
|
2110
|
+
<key>ProcessType</key>
|
|
2111
|
+
<string>Background</string>
|
|
2112
|
+
<!--
|
|
2113
|
+
SoftResourceLimits: raise the open-file descriptor limit from the macOS
|
|
2114
|
+
default of 256 to 4096. When multiple LSP child processes (rust-analyzer,
|
|
2115
|
+
jdtls, etc.) share the listener's fd budget they can exhaust the default
|
|
2116
|
+
very quickly, causing EMFILE errors. 4096 matches the system-wide default
|
|
2117
|
+
set by /etc/launchd.conf on modern macOS and gives enough headroom for
|
|
2118
|
+
~10 concurrent LSP servers each opening ~300 fds.
|
|
2119
|
+
|
|
2120
|
+
MemoryLimit: intentionally NOT set here. The launchd MemoryLimit key
|
|
2121
|
+
(available since macOS 12.3) terminates the entire LaunchAgent when RSS
|
|
2122
|
+
exceeds the threshold \u2014 it cannot be scoped to individual child processes.
|
|
2123
|
+
Killing the listener to evict a memory-hungry rust-analyzer instance is
|
|
2124
|
+
undesirable. Per-child memory pressure is better handled by the LSP
|
|
2125
|
+
process manager (process-manager.ts) or by OS-level memory pressure
|
|
2126
|
+
signals (SIGTERM on macOS, OOM killer on Linux).
|
|
2127
|
+
-->
|
|
2128
|
+
<key>SoftResourceLimits</key>
|
|
2129
|
+
<dict>
|
|
2130
|
+
<key>NumberOfFiles</key>
|
|
2131
|
+
<integer>4096</integer>
|
|
2132
|
+
</dict>
|
|
2133
|
+
</dict>
|
|
2134
|
+
</plist>`;
|
|
2135
|
+
}
|
|
2136
|
+
async function darwinInstall() {
|
|
2137
|
+
await mkdir8(logDir(), { recursive: true });
|
|
2138
|
+
await mkdir8(join18(homedir5(), "Library", "LaunchAgents"), { recursive: true });
|
|
1925
2139
|
try {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
}
|
|
1929
|
-
await runToolchain(entry.toolchain, entry.installArgs);
|
|
1930
|
-
} catch (err) {
|
|
1931
|
-
return {
|
|
1932
|
-
installed: false,
|
|
1933
|
-
alreadyPresent: false,
|
|
1934
|
-
error: err instanceof Error ? err.message : String(err)
|
|
1935
|
-
};
|
|
1936
|
-
}
|
|
1937
|
-
const binaryPath = join17(binDir, entry.binaryName);
|
|
1938
|
-
if (!await pathExists3(binaryPath)) {
|
|
1939
|
-
return {
|
|
1940
|
-
installed: false,
|
|
1941
|
-
alreadyPresent: false,
|
|
1942
|
-
error: `${entry.toolchain} install of ${entry.binaryName} completed but binary missing at ${binaryPath}`,
|
|
1943
|
-
binDir
|
|
1944
|
-
};
|
|
2140
|
+
await exec("launchctl", ["unload", plistPath()]);
|
|
2141
|
+
} catch {
|
|
1945
2142
|
}
|
|
1946
|
-
|
|
2143
|
+
await writeFile8(plistPath(), buildPlist());
|
|
2144
|
+
await exec("launchctl", ["load", plistPath()]);
|
|
1947
2145
|
}
|
|
1948
|
-
async function
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
}
|
|
1952
|
-
if (entry.toolchainBinDir) {
|
|
1953
|
-
if (entry.toolchain === "go") {
|
|
1954
|
-
const gopath = process.env["GOPATH"] ?? join17(homedir4(), "go");
|
|
1955
|
-
return join17(gopath, "bin");
|
|
1956
|
-
}
|
|
1957
|
-
return join17(homedir4(), entry.toolchainBinDir);
|
|
2146
|
+
async function darwinUninstall() {
|
|
2147
|
+
try {
|
|
2148
|
+
await exec("launchctl", ["unload", plistPath()]);
|
|
2149
|
+
} catch {
|
|
1958
2150
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2151
|
+
try {
|
|
2152
|
+
await unlink6(plistPath());
|
|
2153
|
+
} catch {
|
|
1962
2154
|
}
|
|
1963
|
-
throw new Error(`no bin-dir resolution for toolchain ${entry.toolchain}`);
|
|
1964
2155
|
}
|
|
1965
|
-
function
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
const gopath = process.env["GOPATH"] ?? join17(homedir4(), "go");
|
|
1972
|
-
dirs.add(join17(gopath, "bin"));
|
|
1973
|
-
} else {
|
|
1974
|
-
dirs.add(join17(homedir4(), entry.toolchainBinDir));
|
|
1975
|
-
}
|
|
2156
|
+
async function darwinIsInstalled() {
|
|
2157
|
+
try {
|
|
2158
|
+
const stdout = await exec("launchctl", ["list"]);
|
|
2159
|
+
return stdout.includes(PLIST_LABEL);
|
|
2160
|
+
} catch {
|
|
2161
|
+
return false;
|
|
1976
2162
|
}
|
|
1977
|
-
return [...dirs];
|
|
1978
2163
|
}
|
|
1979
|
-
function
|
|
1980
|
-
return
|
|
1981
|
-
const child = spawn6(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
1982
|
-
let stderr = "";
|
|
1983
|
-
child.stderr.on("data", (chunk) => {
|
|
1984
|
-
stderr += chunk.toString();
|
|
1985
|
-
});
|
|
1986
|
-
child.on("error", reject);
|
|
1987
|
-
child.on("close", (code) => {
|
|
1988
|
-
if (code === 0)
|
|
1989
|
-
resolve5();
|
|
1990
|
-
else
|
|
1991
|
-
reject(new Error(`${cmd} ${args.join(" ")} exited ${(code ?? -1).toString()}: ${stderr.split("\n").slice(0, 3).join(" ")}`));
|
|
1992
|
-
});
|
|
1993
|
-
});
|
|
2164
|
+
function unitPath() {
|
|
2165
|
+
return join18(homedir5(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
|
|
1994
2166
|
}
|
|
1995
|
-
function
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2167
|
+
function buildUnit() {
|
|
2168
|
+
const cmd = resolveListenerCommand();
|
|
2169
|
+
const execStart = [process.execPath, cmd.script, ...cmd.args].join(" ");
|
|
2170
|
+
const logs = logDir();
|
|
2171
|
+
return `[Unit]
|
|
2172
|
+
Description=RepoWise Listener
|
|
2173
|
+
After=network-online.target
|
|
2174
|
+
Wants=network-online.target
|
|
2175
|
+
|
|
2176
|
+
[Service]
|
|
2177
|
+
Type=simple
|
|
2178
|
+
# FIX-8: systemd user services run with a minimal PATH and don't load shell
|
|
2179
|
+
# profiles. Inject a rich PATH so LSP servers + the typed-resolution probe
|
|
2180
|
+
# resolve (single source of truth: buildDaemonPath() in lsp/daemon-path.ts).
|
|
2181
|
+
Environment=PATH=${sanitizeEnvValue(buildDaemonPath())}
|
|
2182
|
+
ExecStart=${execStart}
|
|
2183
|
+
Restart=always
|
|
2184
|
+
RestartSec=10
|
|
2185
|
+
StandardOutput=append:${join18(logs, "listener-stdout.log")}
|
|
2186
|
+
StandardError=append:${join18(logs, "listener-stderr.log")}
|
|
2187
|
+
|
|
2188
|
+
[Install]
|
|
2189
|
+
WantedBy=default.target`;
|
|
2014
2190
|
}
|
|
2015
|
-
async function
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
child.on("close", (code) => resolve5(code === 0));
|
|
2023
|
-
});
|
|
2191
|
+
async function linuxInstall() {
|
|
2192
|
+
await mkdir8(logDir(), { recursive: true });
|
|
2193
|
+
await mkdir8(join18(homedir5(), ".config", "systemd", "user"), { recursive: true });
|
|
2194
|
+
await writeFile8(unitPath(), buildUnit());
|
|
2195
|
+
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
2196
|
+
await exec("systemctl", ["--user", "enable", SYSTEMD_SERVICE]);
|
|
2197
|
+
await exec("systemctl", ["--user", "start", SYSTEMD_SERVICE]);
|
|
2024
2198
|
}
|
|
2025
|
-
async function
|
|
2199
|
+
async function linuxUninstall() {
|
|
2026
2200
|
try {
|
|
2027
|
-
await
|
|
2028
|
-
|
|
2201
|
+
await exec("systemctl", ["--user", "stop", SYSTEMD_SERVICE]);
|
|
2202
|
+
} catch {
|
|
2203
|
+
}
|
|
2204
|
+
try {
|
|
2205
|
+
await exec("systemctl", ["--user", "disable", SYSTEMD_SERVICE]);
|
|
2206
|
+
} catch {
|
|
2207
|
+
}
|
|
2208
|
+
try {
|
|
2209
|
+
await unlink6(unitPath());
|
|
2210
|
+
} catch {
|
|
2211
|
+
}
|
|
2212
|
+
try {
|
|
2213
|
+
await exec("systemctl", ["--user", "daemon-reload"]);
|
|
2029
2214
|
} catch {
|
|
2030
|
-
return false;
|
|
2031
2215
|
}
|
|
2032
2216
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
"
|
|
2036
|
-
|
|
2217
|
+
async function linuxIsInstalled() {
|
|
2218
|
+
try {
|
|
2219
|
+
const stdout = await exec("systemctl", ["--user", "is-enabled", SYSTEMD_SERVICE]);
|
|
2220
|
+
return stdout.trim() === "enabled";
|
|
2221
|
+
} catch {
|
|
2222
|
+
return false;
|
|
2037
2223
|
}
|
|
2038
|
-
});
|
|
2039
|
-
|
|
2040
|
-
// ../listener/dist/lsp/installer.js
|
|
2041
|
-
import { promises as fs4 } from "fs";
|
|
2042
|
-
import { join as join18, dirname as dirname6 } from "path";
|
|
2043
|
-
import { spawn as spawn7 } from "child_process";
|
|
2044
|
-
import lockfile3 from "proper-lockfile";
|
|
2045
|
-
function getLspInstallDir() {
|
|
2046
|
-
return join18(getConfigDir(), "lsp-servers");
|
|
2047
2224
|
}
|
|
2048
|
-
function
|
|
2049
|
-
|
|
2225
|
+
async function win32Install() {
|
|
2226
|
+
await mkdir8(logDir(), { recursive: true });
|
|
2227
|
+
const cmd = resolveListenerCommand();
|
|
2228
|
+
const taskCmd = [process.execPath, cmd.script, ...cmd.args].map((a) => `"${a}"`).join(" ");
|
|
2229
|
+
await exec("schtasks", [
|
|
2230
|
+
"/create",
|
|
2231
|
+
"/tn",
|
|
2232
|
+
TASK_NAME,
|
|
2233
|
+
"/tr",
|
|
2234
|
+
taskCmd,
|
|
2235
|
+
"/sc",
|
|
2236
|
+
"onlogon",
|
|
2237
|
+
"/ru",
|
|
2238
|
+
process.env.USERNAME ?? "",
|
|
2239
|
+
"/f"
|
|
2240
|
+
]);
|
|
2241
|
+
await exec("schtasks", ["/run", "/tn", TASK_NAME]);
|
|
2050
2242
|
}
|
|
2051
|
-
async function
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
const binPath = join18(installDir, "node_modules", ".bin", config2.command);
|
|
2056
|
-
if (await pathExists4(binPath)) {
|
|
2057
|
-
return { installed: false, skipped: "already-present" };
|
|
2243
|
+
async function win32Uninstall() {
|
|
2244
|
+
try {
|
|
2245
|
+
await exec("schtasks", ["/end", "/tn", TASK_NAME]);
|
|
2246
|
+
} catch {
|
|
2058
2247
|
}
|
|
2059
2248
|
try {
|
|
2060
|
-
await
|
|
2061
|
-
|
|
2062
|
-
try {
|
|
2063
|
-
release = await lockfile3.lock(installDir, {
|
|
2064
|
-
stale: 18e4,
|
|
2065
|
-
retries: { retries: 20, factor: 1.5, minTimeout: 500, maxTimeout: 5e3 },
|
|
2066
|
-
realpath: false
|
|
2067
|
-
});
|
|
2068
|
-
} catch {
|
|
2069
|
-
if (await pathExists4(binPath)) {
|
|
2070
|
-
return { installed: false, skipped: "already-present" };
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
try {
|
|
2074
|
-
if (await pathExists4(binPath)) {
|
|
2075
|
-
return { installed: false, skipped: "already-present" };
|
|
2076
|
-
}
|
|
2077
|
-
const pkgJsonPath = join18(installDir, "package.json");
|
|
2078
|
-
if (!await pathExists4(pkgJsonPath)) {
|
|
2079
|
-
await fs4.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
|
|
2080
|
-
}
|
|
2081
|
-
await runNpmInstall(installDir, config2.npmPackage);
|
|
2082
|
-
if (!await pathExists4(binPath)) {
|
|
2083
|
-
return {
|
|
2084
|
-
installed: false,
|
|
2085
|
-
error: `npm install completed but ${config2.command} still not at ${binPath}`
|
|
2086
|
-
};
|
|
2087
|
-
}
|
|
2088
|
-
return { installed: true };
|
|
2089
|
-
} finally {
|
|
2090
|
-
if (release) {
|
|
2091
|
-
try {
|
|
2092
|
-
await release();
|
|
2093
|
-
} catch {
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
} catch (err) {
|
|
2098
|
-
return {
|
|
2099
|
-
installed: false,
|
|
2100
|
-
error: err instanceof Error ? err.message : String(err)
|
|
2101
|
-
};
|
|
2249
|
+
await exec("schtasks", ["/delete", "/tn", TASK_NAME, "/f"]);
|
|
2250
|
+
} catch {
|
|
2102
2251
|
}
|
|
2103
2252
|
}
|
|
2104
|
-
async function
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
} catch {
|
|
2111
|
-
}
|
|
2253
|
+
async function win32IsInstalled() {
|
|
2254
|
+
try {
|
|
2255
|
+
await exec("schtasks", ["/query", "/tn", TASK_NAME]);
|
|
2256
|
+
return true;
|
|
2257
|
+
} catch {
|
|
2258
|
+
return false;
|
|
2112
2259
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
}
|
|
2260
|
+
}
|
|
2261
|
+
async function darwinStop() {
|
|
2262
|
+
try {
|
|
2263
|
+
await exec("launchctl", ["unload", plistPath()]);
|
|
2264
|
+
} catch {
|
|
2119
2265
|
}
|
|
2120
|
-
return "npm";
|
|
2121
2266
|
}
|
|
2122
|
-
async function
|
|
2123
|
-
|
|
2124
|
-
const nodeDir = dirname6(process.execPath);
|
|
2125
|
-
const augmentedPath = process.env.PATH ? `${nodeDir}:${process.env.PATH}` : nodeDir;
|
|
2126
|
-
return new Promise((resolve5, reject) => {
|
|
2127
|
-
const child = spawn7(npmCmd, ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
|
|
2128
|
-
cwd,
|
|
2129
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
2130
|
-
env: { ...process.env, PATH: augmentedPath }
|
|
2131
|
-
});
|
|
2132
|
-
let stderr = "";
|
|
2133
|
-
child.stderr.on("data", (chunk) => {
|
|
2134
|
-
stderr += chunk.toString();
|
|
2135
|
-
});
|
|
2136
|
-
child.on("error", (err) => reject(err));
|
|
2137
|
-
child.on("close", (code) => {
|
|
2138
|
-
if (code === 0) {
|
|
2139
|
-
resolve5();
|
|
2140
|
-
} else {
|
|
2141
|
-
reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
|
|
2142
|
-
}
|
|
2143
|
-
});
|
|
2144
|
-
});
|
|
2267
|
+
async function linuxStop() {
|
|
2268
|
+
await exec("systemctl", ["--user", "stop", SYSTEMD_SERVICE]);
|
|
2145
2269
|
}
|
|
2146
|
-
function
|
|
2147
|
-
|
|
2148
|
-
return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
|
|
2270
|
+
async function win32Stop() {
|
|
2271
|
+
await exec("schtasks", ["/end", "/tn", TASK_NAME]);
|
|
2149
2272
|
}
|
|
2150
|
-
async function
|
|
2273
|
+
async function darwinIsServiceRunning() {
|
|
2151
2274
|
try {
|
|
2152
|
-
await
|
|
2153
|
-
|
|
2275
|
+
const stdout = await exec("launchctl", ["list", PLIST_LABEL]);
|
|
2276
|
+
const pidMatch = stdout.match(/"PID"\s*=\s*(\d+)/);
|
|
2277
|
+
return pidMatch !== null && parseInt(pidMatch[1], 10) > 0;
|
|
2154
2278
|
} catch {
|
|
2155
2279
|
return false;
|
|
2156
2280
|
}
|
|
2157
2281
|
}
|
|
2158
|
-
async function
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
return;
|
|
2165
|
-
let entries;
|
|
2166
|
-
try {
|
|
2167
|
-
entries = await fs4.readdir(dir);
|
|
2168
|
-
} catch {
|
|
2169
|
-
return;
|
|
2170
|
-
}
|
|
2171
|
-
for (const name of entries) {
|
|
2172
|
-
if (inspected >= MAX_INSPECT)
|
|
2173
|
-
return;
|
|
2174
|
-
if (name.startsWith("."))
|
|
2175
|
-
continue;
|
|
2176
|
-
if (name === "node_modules" || name === "dist" || name === "build")
|
|
2177
|
-
continue;
|
|
2178
|
-
const lang = detectLanguage(name);
|
|
2179
|
-
if (lang) {
|
|
2180
|
-
found.add(lang);
|
|
2181
|
-
inspected += 1;
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2282
|
+
async function linuxIsServiceRunning() {
|
|
2283
|
+
try {
|
|
2284
|
+
const stdout = await exec("systemctl", ["--user", "is-active", SYSTEMD_SERVICE]);
|
|
2285
|
+
return stdout.trim() === "active";
|
|
2286
|
+
} catch {
|
|
2287
|
+
return false;
|
|
2184
2288
|
}
|
|
2185
|
-
|
|
2186
|
-
|
|
2289
|
+
}
|
|
2290
|
+
async function win32IsServiceRunning() {
|
|
2187
2291
|
try {
|
|
2188
|
-
|
|
2292
|
+
const stdout = await exec("schtasks", ["/query", "/tn", TASK_NAME, "/fo", "CSV"]);
|
|
2293
|
+
return stdout.includes("Running");
|
|
2189
2294
|
} catch {
|
|
2190
|
-
return
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
async function stopService() {
|
|
2299
|
+
switch (process.platform) {
|
|
2300
|
+
case "darwin":
|
|
2301
|
+
await darwinStop();
|
|
2302
|
+
break;
|
|
2303
|
+
case "linux":
|
|
2304
|
+
await linuxStop();
|
|
2305
|
+
break;
|
|
2306
|
+
case "win32":
|
|
2307
|
+
await win32Stop();
|
|
2308
|
+
break;
|
|
2309
|
+
default:
|
|
2310
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
async function install() {
|
|
2314
|
+
switch (process.platform) {
|
|
2315
|
+
case "darwin":
|
|
2316
|
+
await darwinInstall();
|
|
2317
|
+
break;
|
|
2318
|
+
case "linux":
|
|
2319
|
+
await linuxInstall();
|
|
2320
|
+
break;
|
|
2321
|
+
case "win32":
|
|
2322
|
+
await win32Install();
|
|
2323
|
+
break;
|
|
2324
|
+
default:
|
|
2325
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
2191
2326
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2327
|
+
}
|
|
2328
|
+
async function uninstall() {
|
|
2329
|
+
switch (process.platform) {
|
|
2330
|
+
case "darwin":
|
|
2331
|
+
await darwinUninstall();
|
|
2332
|
+
break;
|
|
2333
|
+
case "linux":
|
|
2334
|
+
await linuxUninstall();
|
|
2335
|
+
break;
|
|
2336
|
+
case "win32":
|
|
2337
|
+
await win32Uninstall();
|
|
2338
|
+
break;
|
|
2339
|
+
default:
|
|
2340
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
2204
2341
|
}
|
|
2205
|
-
return found;
|
|
2206
2342
|
}
|
|
2207
|
-
async function
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
continue;
|
|
2218
|
-
}
|
|
2219
|
-
try {
|
|
2220
|
-
const langs = await detectRepoLanguages(r.localPath);
|
|
2221
|
-
for (const l of langs)
|
|
2222
|
-
detected.add(l);
|
|
2223
|
-
} catch {
|
|
2224
|
-
}
|
|
2343
|
+
async function isInstalled() {
|
|
2344
|
+
switch (process.platform) {
|
|
2345
|
+
case "darwin":
|
|
2346
|
+
return darwinIsInstalled();
|
|
2347
|
+
case "linux":
|
|
2348
|
+
return linuxIsInstalled();
|
|
2349
|
+
case "win32":
|
|
2350
|
+
return win32IsInstalled();
|
|
2351
|
+
default:
|
|
2352
|
+
return false;
|
|
2225
2353
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
installMethod: "npm",
|
|
2238
|
-
error: outcome.error
|
|
2239
|
-
});
|
|
2240
|
-
continue;
|
|
2241
|
-
}
|
|
2242
|
-
const nativeConfig = configs.find((c) => c.nativeInstallKey);
|
|
2243
|
-
if (nativeConfig?.nativeInstallKey) {
|
|
2244
|
-
const outcome = await ensureNativeLspInstalled(nativeConfig.nativeInstallKey);
|
|
2245
|
-
results.push({
|
|
2246
|
-
language,
|
|
2247
|
-
installed: outcome.installed,
|
|
2248
|
-
alreadyPresent: outcome.alreadyPresent,
|
|
2249
|
-
skippedNoNpmPackage: false,
|
|
2250
|
-
installMethod: "native",
|
|
2251
|
-
skipped: outcome.skipped,
|
|
2252
|
-
hint: outcome.skipped ? nativeConfig.installHint : void 0,
|
|
2253
|
-
error: outcome.error
|
|
2254
|
-
});
|
|
2255
|
-
continue;
|
|
2256
|
-
}
|
|
2257
|
-
const coursierConfig = configs.find((c) => c.coursierInstallKey);
|
|
2258
|
-
if (coursierConfig?.coursierInstallKey) {
|
|
2259
|
-
const outcome = await ensureCoursierLspInstalled(coursierConfig.coursierInstallKey);
|
|
2260
|
-
results.push({
|
|
2261
|
-
language,
|
|
2262
|
-
installed: outcome.installed,
|
|
2263
|
-
alreadyPresent: outcome.alreadyPresent,
|
|
2264
|
-
skippedNoNpmPackage: false,
|
|
2265
|
-
installMethod: "coursier",
|
|
2266
|
-
skipped: outcome.skipped,
|
|
2267
|
-
hint: outcome.skipped ? coursierConfig.installHint : void 0,
|
|
2268
|
-
error: outcome.error
|
|
2269
|
-
});
|
|
2270
|
-
continue;
|
|
2271
|
-
}
|
|
2272
|
-
const toolchainConfig = configs.find((c) => c.toolchainInstallKey);
|
|
2273
|
-
if (toolchainConfig?.toolchainInstallKey) {
|
|
2274
|
-
const outcome = await ensureToolchainLspInstalled(toolchainConfig.toolchainInstallKey);
|
|
2275
|
-
results.push({
|
|
2276
|
-
language,
|
|
2277
|
-
installed: outcome.installed,
|
|
2278
|
-
alreadyPresent: outcome.alreadyPresent,
|
|
2279
|
-
skippedNoNpmPackage: false,
|
|
2280
|
-
installMethod: "toolchain",
|
|
2281
|
-
skipped: outcome.skipped,
|
|
2282
|
-
// Surface the install hint for any skip reason — toolchain
|
|
2283
|
-
// missing means user needs to install it; bundled SDK means
|
|
2284
|
-
// user needs the SDK.
|
|
2285
|
-
hint: outcome.skipped ? toolchainConfig.installHint : void 0,
|
|
2286
|
-
error: outcome.error
|
|
2287
|
-
});
|
|
2288
|
-
continue;
|
|
2289
|
-
}
|
|
2290
|
-
results.push({
|
|
2291
|
-
language,
|
|
2292
|
-
installed: false,
|
|
2293
|
-
alreadyPresent: false,
|
|
2294
|
-
skippedNoNpmPackage: true,
|
|
2295
|
-
hint: configs[0]?.installHint
|
|
2296
|
-
});
|
|
2354
|
+
}
|
|
2355
|
+
async function isServiceRunning() {
|
|
2356
|
+
switch (process.platform) {
|
|
2357
|
+
case "darwin":
|
|
2358
|
+
return darwinIsServiceRunning();
|
|
2359
|
+
case "linux":
|
|
2360
|
+
return linuxIsServiceRunning();
|
|
2361
|
+
case "win32":
|
|
2362
|
+
return win32IsServiceRunning();
|
|
2363
|
+
default:
|
|
2364
|
+
return false;
|
|
2297
2365
|
}
|
|
2298
|
-
return results;
|
|
2299
2366
|
}
|
|
2300
|
-
var
|
|
2301
|
-
|
|
2367
|
+
var IS_STAGING, PLIST_LABEL, SYSTEMD_SERVICE, TASK_NAME;
|
|
2368
|
+
var init_service_installer = __esm({
|
|
2369
|
+
"../listener/dist/service-installer.js"() {
|
|
2302
2370
|
"use strict";
|
|
2303
2371
|
init_config_dir();
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2372
|
+
init_process_manager();
|
|
2373
|
+
init_daemon_path();
|
|
2374
|
+
IS_STAGING = true ? true : false;
|
|
2375
|
+
PLIST_LABEL = IS_STAGING ? "com.repowise-staging.listener" : "com.repowise.listener";
|
|
2376
|
+
SYSTEMD_SERVICE = IS_STAGING ? "repowise-staging-listener" : "repowise-listener";
|
|
2377
|
+
TASK_NAME = IS_STAGING ? "RepoWise Staging Listener" : "RepoWise Listener";
|
|
2308
2378
|
}
|
|
2309
2379
|
});
|
|
2310
2380
|
|
|
@@ -2316,7 +2386,7 @@ __export(sidecar_cache_exports, {
|
|
|
2316
2386
|
sidecarCachePaths: () => sidecarCachePaths
|
|
2317
2387
|
});
|
|
2318
2388
|
import { mkdir as mkdir9, readFile as readFile8, readdir as readdir3, stat as stat2, unlink as unlink8, writeFile as writeFile9 } from "fs/promises";
|
|
2319
|
-
import { dirname as
|
|
2389
|
+
import { dirname as dirname9, join as join20 } from "path";
|
|
2320
2390
|
function repoIdSafe(repoId) {
|
|
2321
2391
|
return /^[A-Za-z0-9_.-]{1,128}$/.test(repoId) && !repoId.startsWith(".");
|
|
2322
2392
|
}
|
|
@@ -2330,8 +2400,8 @@ function sidecarCachePaths(repoId, commitSha) {
|
|
|
2330
2400
|
if (!commitShaSafe(commitSha)) {
|
|
2331
2401
|
throw new Error(`unsafe commitSha: ${commitSha}`);
|
|
2332
2402
|
}
|
|
2333
|
-
const repoDir =
|
|
2334
|
-
const fullPath =
|
|
2403
|
+
const repoDir = join20(getConfigDir(), "typed-resolution", repoId);
|
|
2404
|
+
const fullPath = join20(repoDir, `${commitSha}.jsonl`);
|
|
2335
2405
|
return { fullPath, repoDir };
|
|
2336
2406
|
}
|
|
2337
2407
|
async function persistMergedSidecar(repoId, commitSha, sidecar) {
|
|
@@ -2354,7 +2424,7 @@ async function sweepSidecarDir(repoDir) {
|
|
|
2354
2424
|
const withMtime = [];
|
|
2355
2425
|
for (const name of jsonlFiles) {
|
|
2356
2426
|
try {
|
|
2357
|
-
const s = await stat2(
|
|
2427
|
+
const s = await stat2(join20(repoDir, name));
|
|
2358
2428
|
withMtime.push({ name, mtimeMs: s.mtimeMs });
|
|
2359
2429
|
} catch {
|
|
2360
2430
|
}
|
|
@@ -2365,7 +2435,7 @@ async function sweepSidecarDir(repoDir) {
|
|
|
2365
2435
|
for (const { name, mtimeMs } of candidates) {
|
|
2366
2436
|
if (now - mtimeMs >= SWEEP_MAX_AGE_MS) {
|
|
2367
2437
|
try {
|
|
2368
|
-
await unlink8(
|
|
2438
|
+
await unlink8(join20(repoDir, name));
|
|
2369
2439
|
} catch {
|
|
2370
2440
|
}
|
|
2371
2441
|
}
|
|
@@ -2469,7 +2539,10 @@ async function uploadSidecar(req, fetchImpl = fetch) {
|
|
|
2469
2539
|
throw new Error("upload-url response missing `data.url`");
|
|
2470
2540
|
const putRes = await fetchImpl(presignedUrl, {
|
|
2471
2541
|
method: "PUT",
|
|
2472
|
-
headers: {
|
|
2542
|
+
headers: {
|
|
2543
|
+
"content-type": "application/json",
|
|
2544
|
+
"x-amz-server-side-encryption": "aws:kms"
|
|
2545
|
+
},
|
|
2473
2546
|
body
|
|
2474
2547
|
});
|
|
2475
2548
|
if (!putRes.ok) {
|
|
@@ -3060,13 +3133,13 @@ var init_telemetry = __esm({
|
|
|
3060
3133
|
// bin/repowise.ts
|
|
3061
3134
|
import { readFileSync as readFileSync3 } from "fs";
|
|
3062
3135
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
3063
|
-
import { dirname as
|
|
3136
|
+
import { dirname as dirname23, join as join61 } from "path";
|
|
3064
3137
|
import { Command } from "commander";
|
|
3065
3138
|
|
|
3066
3139
|
// ../listener/dist/main.js
|
|
3067
3140
|
init_config_dir();
|
|
3068
3141
|
import { readFile as readFile13, writeFile as writeFile15, mkdir as mkdir16, stat as fsStat } from "fs/promises";
|
|
3069
|
-
import { join as
|
|
3142
|
+
import { join as join41, dirname as dirname17 } from "path";
|
|
3070
3143
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3071
3144
|
import lockfile4 from "proper-lockfile";
|
|
3072
3145
|
|
|
@@ -4877,7 +4950,7 @@ init_config_dir();
|
|
|
4877
4950
|
init_process_manager();
|
|
4878
4951
|
init_service_installer();
|
|
4879
4952
|
import { unlink as unlink7 } from "fs/promises";
|
|
4880
|
-
import { join as
|
|
4953
|
+
import { join as join19 } from "path";
|
|
4881
4954
|
async function getListenerStatus() {
|
|
4882
4955
|
const pid = await readPid();
|
|
4883
4956
|
if (pid !== null) {
|
|
@@ -4886,7 +4959,7 @@ async function getListenerStatus() {
|
|
|
4886
4959
|
return { running: true, method: "pid", pid, serviceInstalled: serviceInstalled2 };
|
|
4887
4960
|
}
|
|
4888
4961
|
try {
|
|
4889
|
-
await unlink7(
|
|
4962
|
+
await unlink7(join19(getConfigDir(), "listener.pid"));
|
|
4890
4963
|
} catch {
|
|
4891
4964
|
}
|
|
4892
4965
|
}
|
|
@@ -4931,15 +5004,15 @@ async function stopListener() {
|
|
|
4931
5004
|
|
|
4932
5005
|
// ../listener/dist/mcp/bootstrap.js
|
|
4933
5006
|
init_config_dir();
|
|
4934
|
-
import { join as
|
|
5007
|
+
import { join as join23 } from "path";
|
|
4935
5008
|
|
|
4936
5009
|
// ../listener/dist/lsp/workspace-session.js
|
|
4937
5010
|
import { pathToFileURL } from "url";
|
|
4938
5011
|
import { readFile as readFile7 } from "fs/promises";
|
|
4939
|
-
import { resolve as pathResolve2, sep as pathSep, dirname as
|
|
5012
|
+
import { resolve as pathResolve2, sep as pathSep, dirname as dirname8, delimiter as delimiter2 } from "path";
|
|
4940
5013
|
|
|
4941
5014
|
// ../listener/dist/lsp/lsp-client.js
|
|
4942
|
-
import { spawn as
|
|
5015
|
+
import { spawn as spawn7 } from "child_process";
|
|
4943
5016
|
import { EventEmitter, once } from "events";
|
|
4944
5017
|
import { Buffer as Buffer2 } from "buffer";
|
|
4945
5018
|
var LspTimeoutError = class extends Error {
|
|
@@ -4984,7 +5057,7 @@ var LspClient = class extends EventEmitter {
|
|
|
4984
5057
|
closed = false;
|
|
4985
5058
|
constructor(options) {
|
|
4986
5059
|
super();
|
|
4987
|
-
this.child = options.spawn ? options.spawn() :
|
|
5060
|
+
this.child = options.spawn ? options.spawn() : spawn7(options.command, [...options.args ?? []], {
|
|
4988
5061
|
cwd: options.cwd,
|
|
4989
5062
|
env: options.env ?? process.env,
|
|
4990
5063
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -5207,10 +5280,7 @@ var LspClient = class extends EventEmitter {
|
|
|
5207
5280
|
};
|
|
5208
5281
|
|
|
5209
5282
|
// ../listener/dist/lsp/workspace-session.js
|
|
5210
|
-
|
|
5211
|
-
init_native_installer();
|
|
5212
|
-
init_coursier_installer();
|
|
5213
|
-
init_toolchain_installer();
|
|
5283
|
+
init_daemon_path();
|
|
5214
5284
|
|
|
5215
5285
|
// ../listener/dist/lsp/bloop-lifecycle.js
|
|
5216
5286
|
import { spawn as spawn8 } from "child_process";
|
|
@@ -5270,13 +5340,7 @@ var WorkspaceManager = class {
|
|
|
5270
5340
|
this.rssSampler = opts.rssSampler ?? (() => process.memoryUsage().rss);
|
|
5271
5341
|
this.clientFactory = opts.clientFactory ?? ((config2, cwd) => {
|
|
5272
5342
|
const env = { ...process.env };
|
|
5273
|
-
|
|
5274
|
-
getLspBinDir(),
|
|
5275
|
-
getNativeLspBinDir(),
|
|
5276
|
-
getCoursierBinDir(),
|
|
5277
|
-
...getToolchainBinDirs()
|
|
5278
|
-
];
|
|
5279
|
-
env.PATH = buildLspSpawnPath(env.PATH, dirname7(process.execPath), lspBinDirs);
|
|
5343
|
+
env.PATH = buildLspSpawnPath(env.PATH, dirname8(process.execPath), managedBinDirs());
|
|
5280
5344
|
const client = new LspClient({
|
|
5281
5345
|
command: config2.command,
|
|
5282
5346
|
args: config2.args,
|
|
@@ -5645,14 +5709,19 @@ var PathEscapeError = class extends Error {
|
|
|
5645
5709
|
}
|
|
5646
5710
|
};
|
|
5647
5711
|
function buildLspSpawnPath(basePath, nodeDir, lspBinDirs) {
|
|
5648
|
-
const
|
|
5649
|
-
|
|
5712
|
+
const parts = [
|
|
5713
|
+
nodeDir,
|
|
5714
|
+
...basePath ? basePath.split(delimiter2) : [],
|
|
5715
|
+
...commonBinDirs(),
|
|
5716
|
+
...lspBinDirs
|
|
5717
|
+
];
|
|
5718
|
+
return [...new Set(parts.filter((d) => d.length > 0))].join(delimiter2);
|
|
5650
5719
|
}
|
|
5651
5720
|
|
|
5652
5721
|
// ../listener/dist/mcp/graph-cache.js
|
|
5653
5722
|
init_config_dir();
|
|
5654
5723
|
import { readFile as readFile9, stat as stat3 } from "fs/promises";
|
|
5655
|
-
import { join as
|
|
5724
|
+
import { join as join21 } from "path";
|
|
5656
5725
|
var EVICT_DEBOUNCE_MS = 6e4;
|
|
5657
5726
|
function assertSafeRepoId(repoId) {
|
|
5658
5727
|
if (!repoId || typeof repoId !== "string") {
|
|
@@ -5667,7 +5736,7 @@ function assertSafeRepoId(repoId) {
|
|
|
5667
5736
|
}
|
|
5668
5737
|
function createGraphCache(options = {}) {
|
|
5669
5738
|
const evictMs = options.evictDebounceMs ?? EVICT_DEBOUNCE_MS;
|
|
5670
|
-
const resolvePath = options.resolveGraphPath ?? ((repoId) =>
|
|
5739
|
+
const resolvePath = options.resolveGraphPath ?? ((repoId) => join21(defaultRepoWiseHome(), "graphs", `${repoId}.json`));
|
|
5671
5740
|
const entries = /* @__PURE__ */ new Map();
|
|
5672
5741
|
const inFlight = /* @__PURE__ */ new Map();
|
|
5673
5742
|
async function loadFromDisk(repoId) {
|
|
@@ -5761,7 +5830,7 @@ function defaultRepoWiseHome() {
|
|
|
5761
5830
|
|
|
5762
5831
|
// ../listener/dist/mcp/graph-downloader.js
|
|
5763
5832
|
import { mkdir as mkdir10, rename as rename3, writeFile as writeFile10 } from "fs/promises";
|
|
5764
|
-
import { dirname as
|
|
5833
|
+
import { dirname as dirname10 } from "path";
|
|
5765
5834
|
function createGraphDownloader(options) {
|
|
5766
5835
|
const fetchFn = options.fetchImpl ?? fetch;
|
|
5767
5836
|
let lastSha = null;
|
|
@@ -5812,7 +5881,7 @@ function createGraphDownloader(options) {
|
|
|
5812
5881
|
message: `graph parse: ${err instanceof Error ? err.message : String(err)}`
|
|
5813
5882
|
};
|
|
5814
5883
|
}
|
|
5815
|
-
await mkdir10(
|
|
5884
|
+
await mkdir10(dirname10(options.targetPath), { recursive: true });
|
|
5816
5885
|
const tmpPath = `${options.targetPath}.${Date.now()}.tmp`;
|
|
5817
5886
|
await writeFile10(tmpPath, body, { encoding: "utf-8", mode: 384 });
|
|
5818
5887
|
await rename3(tmpPath, options.targetPath);
|
|
@@ -5838,7 +5907,7 @@ function createGraphDownloader(options) {
|
|
|
5838
5907
|
// ../listener/dist/mcp/log-encryption.js
|
|
5839
5908
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
5840
5909
|
import { mkdir as mkdir11, readFile as readFile10, stat as stat4, writeFile as writeFile11 } from "fs/promises";
|
|
5841
|
-
import { dirname as
|
|
5910
|
+
import { dirname as dirname11 } from "path";
|
|
5842
5911
|
var KEY_BYTES = 32;
|
|
5843
5912
|
var IV_BYTES = 12;
|
|
5844
5913
|
var TAG_BYTES = 16;
|
|
@@ -5885,7 +5954,7 @@ function createFileKeyStore(keyPath) {
|
|
|
5885
5954
|
return parsed;
|
|
5886
5955
|
}
|
|
5887
5956
|
const fresh = randomBytes(KEY_BYTES);
|
|
5888
|
-
await mkdir11(
|
|
5957
|
+
await mkdir11(dirname11(keyPath), { recursive: true });
|
|
5889
5958
|
const tmp = `${keyPath}.tmp`;
|
|
5890
5959
|
await writeFile11(tmp, fresh.toString("base64") + "\n", {
|
|
5891
5960
|
encoding: "utf-8",
|
|
@@ -5927,7 +5996,7 @@ function decryptLine(encoded, key) {
|
|
|
5927
5996
|
|
|
5928
5997
|
// ../listener/dist/mcp/mcp-logger.js
|
|
5929
5998
|
import { appendFile, mkdir as mkdir12, stat as stat5, unlink as unlink9, writeFile as writeFile12, readFile as readFile11 } from "fs/promises";
|
|
5930
|
-
import { dirname as
|
|
5999
|
+
import { dirname as dirname12 } from "path";
|
|
5931
6000
|
var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
|
|
5932
6001
|
function createMcpLogger(options) {
|
|
5933
6002
|
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
@@ -5950,7 +6019,7 @@ function createMcpLogger(options) {
|
|
|
5950
6019
|
await migrateLegacyPlaintext();
|
|
5951
6020
|
const key = await options.keyStore.getKey();
|
|
5952
6021
|
const encoded = encryptLine(JSON.stringify(entry), key) + "\n";
|
|
5953
|
-
await mkdir12(
|
|
6022
|
+
await mkdir12(dirname12(options.filePath), { recursive: true });
|
|
5954
6023
|
await appendFile(options.filePath, encoded, { encoding: "utf-8", mode: 384 });
|
|
5955
6024
|
try {
|
|
5956
6025
|
const s = await stat5(options.filePath);
|
|
@@ -5984,7 +6053,7 @@ async function rotate(path, size) {
|
|
|
5984
6053
|
// ../listener/dist/mcp/mcp-log-uploader.js
|
|
5985
6054
|
import { randomUUID } from "crypto";
|
|
5986
6055
|
import { readFile as readFile12, writeFile as writeFile13, mkdir as mkdir13 } from "fs/promises";
|
|
5987
|
-
import { dirname as
|
|
6056
|
+
import { dirname as dirname13 } from "path";
|
|
5988
6057
|
var DEFAULT_MAX_ENTRIES = 5e3;
|
|
5989
6058
|
var DEFAULT_MAX_BYTES2 = 1 * 1024 * 1024;
|
|
5990
6059
|
function createMcpLogUploader(options) {
|
|
@@ -6134,7 +6203,7 @@ async function readPendingBatch(watermarkPath) {
|
|
|
6134
6203
|
}
|
|
6135
6204
|
}
|
|
6136
6205
|
async function writePendingBatch(watermarkPath, batchId) {
|
|
6137
|
-
await mkdir13(
|
|
6206
|
+
await mkdir13(dirname13(watermarkPath), { recursive: true });
|
|
6138
6207
|
await writeFile13(pendingPath(watermarkPath), batchId, { encoding: "utf-8", mode: 384 });
|
|
6139
6208
|
}
|
|
6140
6209
|
async function clearPendingBatch(watermarkPath) {
|
|
@@ -6156,7 +6225,7 @@ async function readWatermark(path) {
|
|
|
6156
6225
|
}
|
|
6157
6226
|
}
|
|
6158
6227
|
async function writeWatermark(path, offset) {
|
|
6159
|
-
await mkdir13(
|
|
6228
|
+
await mkdir13(dirname13(path), { recursive: true });
|
|
6160
6229
|
const tmp = `${path}.tmp`;
|
|
6161
6230
|
await writeFile13(tmp, offset.toString() + "\n", { encoding: "utf-8", mode: 384 });
|
|
6162
6231
|
const { rename: rename5 } = await import("fs/promises");
|
|
@@ -6176,7 +6245,7 @@ async function isLocallyConsented(flagPath2) {
|
|
|
6176
6245
|
init_config_dir();
|
|
6177
6246
|
import { createServer } from "http";
|
|
6178
6247
|
import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
|
|
6179
|
-
import { dirname as
|
|
6248
|
+
import { dirname as dirname14, join as join22 } from "path";
|
|
6180
6249
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "crypto";
|
|
6181
6250
|
|
|
6182
6251
|
// ../listener/dist/mcp/sanitize.js
|
|
@@ -7694,7 +7763,7 @@ async function readJson(req) {
|
|
|
7694
7763
|
}
|
|
7695
7764
|
}
|
|
7696
7765
|
async function writeEndpointFile(path, endpoint, secret) {
|
|
7697
|
-
await mkdir14(
|
|
7766
|
+
await mkdir14(dirname14(path), { recursive: true });
|
|
7698
7767
|
await writeFile14(path, formatEndpointFile({ endpoint, secret }), {
|
|
7699
7768
|
encoding: "utf-8",
|
|
7700
7769
|
mode: 384
|
|
@@ -7708,7 +7777,7 @@ function extractBearer(header) {
|
|
|
7708
7777
|
return m ? m[1] : null;
|
|
7709
7778
|
}
|
|
7710
7779
|
function defaultEndpointFile() {
|
|
7711
|
-
return
|
|
7780
|
+
return join22(getConfigDir(), "listener.endpoint");
|
|
7712
7781
|
}
|
|
7713
7782
|
|
|
7714
7783
|
// ../listener/dist/mcp/bootstrap.js
|
|
@@ -7716,7 +7785,7 @@ async function startMcp(options) {
|
|
|
7716
7785
|
const disabled = process.env.REPOWISE_MCP_DISABLED === "true";
|
|
7717
7786
|
const graphsDir = options.graphsDir ?? defaultGraphsDir();
|
|
7718
7787
|
const graphCache = createGraphCache({
|
|
7719
|
-
resolveGraphPath: (repoId) =>
|
|
7788
|
+
resolveGraphPath: (repoId) => join23(graphsDir, `${repoId}.json`)
|
|
7720
7789
|
});
|
|
7721
7790
|
if (disabled) {
|
|
7722
7791
|
return {
|
|
@@ -7739,12 +7808,12 @@ async function startMcp(options) {
|
|
|
7739
7808
|
}
|
|
7740
7809
|
const firstRepoLocal = options.repos.find((r) => r.localPath)?.localPath;
|
|
7741
7810
|
const mcpHome = defaultMcpHome();
|
|
7742
|
-
const logFilePath =
|
|
7743
|
-
const keyStore = createFileKeyStore(
|
|
7811
|
+
const logFilePath = join23(mcpHome, "mcp-log.jsonl.enc");
|
|
7812
|
+
const keyStore = createFileKeyStore(join23(mcpHome, "mcp-log.key"));
|
|
7744
7813
|
const mcpLogger = createMcpLogger({ filePath: logFilePath, keyStore });
|
|
7745
|
-
const flagFilePath =
|
|
7746
|
-
const watermarkFilePath =
|
|
7747
|
-
const consentSentMarkerPath =
|
|
7814
|
+
const flagFilePath = join23(mcpHome, "mcp-log.flag");
|
|
7815
|
+
const watermarkFilePath = join23(mcpHome, "mcp-log.watermark");
|
|
7816
|
+
const consentSentMarkerPath = join23(mcpHome, "mcp-log.consent-sent");
|
|
7748
7817
|
let uploader = null;
|
|
7749
7818
|
let lastConsentState = false;
|
|
7750
7819
|
let serverConsentEnsuredThisProcess = false;
|
|
@@ -7791,7 +7860,7 @@ async function startMcp(options) {
|
|
|
7791
7860
|
apiBaseUrl: repo.apiUrl,
|
|
7792
7861
|
getAuthToken: options.getAuthToken,
|
|
7793
7862
|
repoId: repo.repoId,
|
|
7794
|
-
targetPath:
|
|
7863
|
+
targetPath: join23(graphsDir, `${repo.repoId}.json`),
|
|
7795
7864
|
graphCache,
|
|
7796
7865
|
...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
|
|
7797
7866
|
}));
|
|
@@ -7876,7 +7945,7 @@ async function startMcp(options) {
|
|
|
7876
7945
|
apiBaseUrl: repo.apiUrl,
|
|
7877
7946
|
getAuthToken: options.getAuthToken,
|
|
7878
7947
|
repoId: repo.repoId,
|
|
7879
|
-
targetPath:
|
|
7948
|
+
targetPath: join23(graphsDir, `${repo.repoId}.json`),
|
|
7880
7949
|
graphCache,
|
|
7881
7950
|
...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
|
|
7882
7951
|
}));
|
|
@@ -7897,7 +7966,7 @@ async function startMcp(options) {
|
|
|
7897
7966
|
};
|
|
7898
7967
|
}
|
|
7899
7968
|
function defaultGraphsDir() {
|
|
7900
|
-
return
|
|
7969
|
+
return join23(getConfigDir(), "graphs");
|
|
7901
7970
|
}
|
|
7902
7971
|
function defaultMcpHome() {
|
|
7903
7972
|
return getConfigDir();
|
|
@@ -7950,16 +8019,16 @@ async function ensureServerConsent(opts) {
|
|
|
7950
8019
|
}
|
|
7951
8020
|
|
|
7952
8021
|
// ../listener/dist/mcp/auto-config/index.js
|
|
7953
|
-
import { homedir as
|
|
8022
|
+
import { homedir as homedir6 } from "os";
|
|
7954
8023
|
import { basename as basename3 } from "path";
|
|
7955
8024
|
|
|
7956
8025
|
// ../listener/dist/mcp/auto-config/writers/claude-code.js
|
|
7957
8026
|
import { promises as fs6 } from "fs";
|
|
7958
|
-
import { join as
|
|
8027
|
+
import { join as join24 } from "path";
|
|
7959
8028
|
|
|
7960
8029
|
// ../listener/dist/mcp/auto-config/markers.js
|
|
7961
8030
|
import { promises as fs5 } from "fs";
|
|
7962
|
-
import { dirname as
|
|
8031
|
+
import { dirname as dirname15 } from "path";
|
|
7963
8032
|
async function writeMergedConfig(params) {
|
|
7964
8033
|
const current = await readConfig(params.path);
|
|
7965
8034
|
const servers = { ...current.mcpServers ?? {} };
|
|
@@ -7969,7 +8038,7 @@ async function writeMergedConfig(params) {
|
|
|
7969
8038
|
const existing = safeExistingContent(params.path, current);
|
|
7970
8039
|
if (existing === canonical)
|
|
7971
8040
|
return "unchanged";
|
|
7972
|
-
await fs5.mkdir(
|
|
8041
|
+
await fs5.mkdir(dirname15(params.path), { recursive: true });
|
|
7973
8042
|
await fs5.writeFile(params.path, canonical, "utf-8");
|
|
7974
8043
|
return "written";
|
|
7975
8044
|
}
|
|
@@ -8035,10 +8104,10 @@ function safeExistingContent(path, current) {
|
|
|
8035
8104
|
var claudeCodeWriter = {
|
|
8036
8105
|
tool: "claude-code",
|
|
8037
8106
|
async detect(repoRoot, home) {
|
|
8038
|
-
return await fileExists2(
|
|
8107
|
+
return await fileExists2(join24(repoRoot, "CLAUDE.md")) || await hasClaudeBinary(home);
|
|
8039
8108
|
},
|
|
8040
8109
|
async write(ctx) {
|
|
8041
|
-
const path =
|
|
8110
|
+
const path = join24(ctx.repoRoot, ".mcp.json");
|
|
8042
8111
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8043
8112
|
const status2 = await writeMergedConfig({
|
|
8044
8113
|
path,
|
|
@@ -8048,7 +8117,7 @@ var claudeCodeWriter = {
|
|
|
8048
8117
|
return { status: status2, path };
|
|
8049
8118
|
},
|
|
8050
8119
|
async remove(ctx) {
|
|
8051
|
-
const path =
|
|
8120
|
+
const path = join24(ctx.repoRoot, ".mcp.json");
|
|
8052
8121
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8053
8122
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8054
8123
|
}
|
|
@@ -8062,20 +8131,20 @@ async function fileExists2(path) {
|
|
|
8062
8131
|
}
|
|
8063
8132
|
}
|
|
8064
8133
|
async function hasClaudeBinary(home) {
|
|
8065
|
-
return fileExists2(
|
|
8134
|
+
return fileExists2(join24(home, ".claude", "claude.json"));
|
|
8066
8135
|
}
|
|
8067
8136
|
|
|
8068
8137
|
// ../listener/dist/mcp/auto-config/writers/claude-code-hooks.js
|
|
8069
8138
|
import { promises as fs7 } from "fs";
|
|
8070
|
-
import { join as
|
|
8139
|
+
import { join as join25 } from "path";
|
|
8071
8140
|
var claudeCodeHooksWriter = {
|
|
8072
8141
|
tool: "claude-code-hooks",
|
|
8073
8142
|
async detect(repoRoot, home) {
|
|
8074
|
-
return await fileExists3(
|
|
8143
|
+
return await fileExists3(join25(repoRoot, "CLAUDE.md")) || await fileExists3(join25(home, ".claude.json"));
|
|
8075
8144
|
},
|
|
8076
8145
|
async write(ctx) {
|
|
8077
8146
|
const result = await writeClaudeHooksToRepo(ctx.repoRoot, ctx.contextFolder ?? "repowise-context", ctx.variant);
|
|
8078
|
-
return { status: result.status, path:
|
|
8147
|
+
return { status: result.status, path: join25(ctx.repoRoot, result.relPath) };
|
|
8079
8148
|
},
|
|
8080
8149
|
async remove(ctx) {
|
|
8081
8150
|
await removeClaudeHooksFromRepo(ctx.repoRoot);
|
|
@@ -8092,14 +8161,14 @@ async function fileExists3(path) {
|
|
|
8092
8161
|
|
|
8093
8162
|
// ../listener/dist/mcp/auto-config/writers/cline.js
|
|
8094
8163
|
import { promises as fs8 } from "fs";
|
|
8095
|
-
import { join as
|
|
8164
|
+
import { join as join26 } from "path";
|
|
8096
8165
|
var clineWriter = {
|
|
8097
8166
|
tool: "cline",
|
|
8098
8167
|
async detect(repoRoot, home) {
|
|
8099
|
-
return await fileExists4(
|
|
8168
|
+
return await fileExists4(join26(repoRoot, ".clinerules")) || await fileExists4(join26(home, ".cline"));
|
|
8100
8169
|
},
|
|
8101
8170
|
async write(ctx) {
|
|
8102
|
-
const path =
|
|
8171
|
+
const path = join26(ctx.home, ".cline", "mcp.json");
|
|
8103
8172
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8104
8173
|
const status2 = await writeMergedConfig({
|
|
8105
8174
|
path,
|
|
@@ -8109,7 +8178,7 @@ var clineWriter = {
|
|
|
8109
8178
|
return { status: status2, path };
|
|
8110
8179
|
},
|
|
8111
8180
|
async remove(ctx) {
|
|
8112
|
-
const path =
|
|
8181
|
+
const path = join26(ctx.home, ".cline", "mcp.json");
|
|
8113
8182
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8114
8183
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8115
8184
|
}
|
|
@@ -8125,13 +8194,13 @@ async function fileExists4(path) {
|
|
|
8125
8194
|
|
|
8126
8195
|
// ../listener/dist/mcp/auto-config/writers/cline-hooks.js
|
|
8127
8196
|
import { promises as fs9 } from "fs";
|
|
8128
|
-
import { join as
|
|
8197
|
+
import { join as join27 } from "path";
|
|
8129
8198
|
var SCRIPT_REL = ".clinerules/hooks/UserPromptSubmit";
|
|
8130
8199
|
var OWNERSHIP_MARKER = "managed by RepoWise";
|
|
8131
8200
|
var clineHooksWriter = {
|
|
8132
8201
|
tool: "cline-hooks",
|
|
8133
8202
|
async detect(repoRoot) {
|
|
8134
|
-
return fileExists5(
|
|
8203
|
+
return fileExists5(join27(repoRoot, ".clinerules"));
|
|
8135
8204
|
},
|
|
8136
8205
|
async write(ctx) {
|
|
8137
8206
|
if (await isGitTracked(ctx.repoRoot, SCRIPT_REL)) {
|
|
@@ -8141,7 +8210,7 @@ var clineHooksWriter = {
|
|
|
8141
8210
|
reason: `${SCRIPT_REL} is git-tracked; update it manually to opt in`
|
|
8142
8211
|
};
|
|
8143
8212
|
}
|
|
8144
|
-
const path =
|
|
8213
|
+
const path = join27(ctx.repoRoot, SCRIPT_REL);
|
|
8145
8214
|
const next = buildClineHookScript({
|
|
8146
8215
|
repoName: ctx.repoName,
|
|
8147
8216
|
contextFolder: ctx.contextFolder ?? "repowise-context",
|
|
@@ -8158,14 +8227,14 @@ var clineHooksWriter = {
|
|
|
8158
8227
|
await ensureExecutable(path);
|
|
8159
8228
|
return { status: "unchanged", path };
|
|
8160
8229
|
}
|
|
8161
|
-
await fs9.mkdir(
|
|
8230
|
+
await fs9.mkdir(join27(ctx.repoRoot, ".clinerules", "hooks"), { recursive: true });
|
|
8162
8231
|
await fs9.writeFile(path, next, { encoding: "utf-8", mode: 493 });
|
|
8163
8232
|
await ensureExecutable(path);
|
|
8164
8233
|
await applyGitignoreChanges(ctx.repoRoot, { add: [SCRIPT_REL] });
|
|
8165
8234
|
return { status: "written", path };
|
|
8166
8235
|
},
|
|
8167
8236
|
async remove(ctx) {
|
|
8168
|
-
const path =
|
|
8237
|
+
const path = join27(ctx.repoRoot, SCRIPT_REL);
|
|
8169
8238
|
const existing = await readOrNull(path);
|
|
8170
8239
|
if (existing !== null && existing.includes(OWNERSHIP_MARKER)) {
|
|
8171
8240
|
await fs9.unlink(path);
|
|
@@ -8200,14 +8269,14 @@ async function readOrNull(path) {
|
|
|
8200
8269
|
|
|
8201
8270
|
// ../listener/dist/mcp/auto-config/writers/codex.js
|
|
8202
8271
|
import { promises as fs10 } from "fs";
|
|
8203
|
-
import { join as
|
|
8272
|
+
import { join as join28 } from "path";
|
|
8204
8273
|
var codexWriter = {
|
|
8205
8274
|
tool: "codex",
|
|
8206
8275
|
async detect(_repoRoot, home) {
|
|
8207
|
-
return fileExists6(
|
|
8276
|
+
return fileExists6(join28(home, ".codex"));
|
|
8208
8277
|
},
|
|
8209
8278
|
async write(ctx) {
|
|
8210
|
-
const path =
|
|
8279
|
+
const path = join28(ctx.home, ".codex", "mcp.json");
|
|
8211
8280
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8212
8281
|
const status2 = await writeMergedConfig({
|
|
8213
8282
|
path,
|
|
@@ -8217,7 +8286,7 @@ var codexWriter = {
|
|
|
8217
8286
|
return { status: status2, path };
|
|
8218
8287
|
},
|
|
8219
8288
|
async remove(ctx) {
|
|
8220
|
-
const path =
|
|
8289
|
+
const path = join28(ctx.home, ".codex", "mcp.json");
|
|
8221
8290
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8222
8291
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8223
8292
|
}
|
|
@@ -8233,15 +8302,15 @@ async function fileExists6(path) {
|
|
|
8233
8302
|
|
|
8234
8303
|
// ../listener/dist/mcp/auto-config/writers/codex-hooks.js
|
|
8235
8304
|
import { promises as fs11 } from "fs";
|
|
8236
|
-
import { join as
|
|
8305
|
+
import { join as join29 } from "path";
|
|
8237
8306
|
var HOOKS_REL = ".codex/hooks.json";
|
|
8238
8307
|
var codexHooksWriter = {
|
|
8239
8308
|
tool: "codex-hooks",
|
|
8240
8309
|
async detect(repoRoot, home) {
|
|
8241
|
-
return await fileExists7(
|
|
8310
|
+
return await fileExists7(join29(home, ".codex")) || await fileExists7(join29(repoRoot, ".codex"));
|
|
8242
8311
|
},
|
|
8243
8312
|
async write(ctx) {
|
|
8244
|
-
const repoSignal = await fileExists7(
|
|
8313
|
+
const repoSignal = await fileExists7(join29(ctx.repoRoot, ".codex"));
|
|
8245
8314
|
const selected = ctx.selectedTools?.includes("codex") ?? false;
|
|
8246
8315
|
if (!repoSignal && !selected) {
|
|
8247
8316
|
return { status: "skipped", reason: "no repo-scoped Codex signal and not selected" };
|
|
@@ -8253,7 +8322,7 @@ var codexHooksWriter = {
|
|
|
8253
8322
|
reason: `${HOOKS_REL} is git-tracked; add the RepoWise UserPromptSubmit hook manually to opt in`
|
|
8254
8323
|
};
|
|
8255
8324
|
}
|
|
8256
|
-
const path =
|
|
8325
|
+
const path = join29(ctx.repoRoot, HOOKS_REL);
|
|
8257
8326
|
const existing = await readOrNull2(path);
|
|
8258
8327
|
const merged = mergeCodexHookSettings(existing, {
|
|
8259
8328
|
repoName: ctx.repoName,
|
|
@@ -8263,13 +8332,13 @@ var codexHooksWriter = {
|
|
|
8263
8332
|
if (merged === existing) {
|
|
8264
8333
|
return { status: "unchanged", path };
|
|
8265
8334
|
}
|
|
8266
|
-
await fs11.mkdir(
|
|
8335
|
+
await fs11.mkdir(join29(ctx.repoRoot, ".codex"), { recursive: true });
|
|
8267
8336
|
await fs11.writeFile(path, merged, "utf-8");
|
|
8268
8337
|
await applyGitignoreChanges(ctx.repoRoot, { add: [HOOKS_REL] });
|
|
8269
8338
|
return { status: "written", path };
|
|
8270
8339
|
},
|
|
8271
8340
|
async remove(ctx) {
|
|
8272
|
-
const path =
|
|
8341
|
+
const path = join29(ctx.repoRoot, HOOKS_REL);
|
|
8273
8342
|
const existing = await readOrNull2(path);
|
|
8274
8343
|
if (existing !== null) {
|
|
8275
8344
|
const next = removeCodexHookSettings(existing);
|
|
@@ -8300,14 +8369,14 @@ async function readOrNull2(path) {
|
|
|
8300
8369
|
|
|
8301
8370
|
// ../listener/dist/mcp/auto-config/writers/copilot.js
|
|
8302
8371
|
import { promises as fs12 } from "fs";
|
|
8303
|
-
import { join as
|
|
8372
|
+
import { join as join30 } from "path";
|
|
8304
8373
|
var copilotWriter = {
|
|
8305
8374
|
tool: "copilot",
|
|
8306
8375
|
async detect(repoRoot) {
|
|
8307
|
-
return fileExists8(
|
|
8376
|
+
return fileExists8(join30(repoRoot, ".vscode"));
|
|
8308
8377
|
},
|
|
8309
8378
|
async write(ctx) {
|
|
8310
|
-
const path =
|
|
8379
|
+
const path = join30(ctx.repoRoot, ".vscode", "mcp.json");
|
|
8311
8380
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8312
8381
|
const status2 = await writeMergedConfig({
|
|
8313
8382
|
path,
|
|
@@ -8317,7 +8386,7 @@ var copilotWriter = {
|
|
|
8317
8386
|
return { status: status2, path };
|
|
8318
8387
|
},
|
|
8319
8388
|
async remove(ctx) {
|
|
8320
|
-
const path =
|
|
8389
|
+
const path = join30(ctx.repoRoot, ".vscode", "mcp.json");
|
|
8321
8390
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8322
8391
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8323
8392
|
}
|
|
@@ -8333,15 +8402,15 @@ async function fileExists8(path) {
|
|
|
8333
8402
|
|
|
8334
8403
|
// ../listener/dist/mcp/auto-config/writers/copilot-hooks.js
|
|
8335
8404
|
import { promises as fs13 } from "fs";
|
|
8336
|
-
import { join as
|
|
8405
|
+
import { join as join31 } from "path";
|
|
8337
8406
|
var HOOKS_REL2 = ".github/hooks/repowise.json";
|
|
8338
8407
|
var copilotHooksWriter = {
|
|
8339
8408
|
tool: "copilot-hooks",
|
|
8340
8409
|
async detect(repoRoot) {
|
|
8341
|
-
return fileExists9(
|
|
8410
|
+
return fileExists9(join31(repoRoot, ".github", "copilot-instructions.md"));
|
|
8342
8411
|
},
|
|
8343
8412
|
async write(ctx) {
|
|
8344
|
-
const path =
|
|
8413
|
+
const path = join31(ctx.repoRoot, HOOKS_REL2);
|
|
8345
8414
|
const next = buildCopilotHooksFile({
|
|
8346
8415
|
repoName: ctx.repoName,
|
|
8347
8416
|
contextFolder: ctx.contextFolder ?? "repowise-context",
|
|
@@ -8361,14 +8430,14 @@ var copilotHooksWriter = {
|
|
|
8361
8430
|
if (existing === next) {
|
|
8362
8431
|
return { status: "unchanged", path };
|
|
8363
8432
|
}
|
|
8364
|
-
await fs13.mkdir(
|
|
8433
|
+
await fs13.mkdir(join31(ctx.repoRoot, ".github", "hooks"), { recursive: true });
|
|
8365
8434
|
await fs13.writeFile(path, next, "utf-8");
|
|
8366
8435
|
const userSelected = ctx.selectedTools?.includes("copilot") ?? false;
|
|
8367
8436
|
await applyGitignoreChanges(ctx.repoRoot, userSelected ? { remove: [HOOKS_REL2] } : { add: [HOOKS_REL2] });
|
|
8368
8437
|
return { status: "written", path };
|
|
8369
8438
|
},
|
|
8370
8439
|
async remove(ctx) {
|
|
8371
|
-
const path =
|
|
8440
|
+
const path = join31(ctx.repoRoot, HOOKS_REL2);
|
|
8372
8441
|
if (!await isGitTracked(ctx.repoRoot, HOOKS_REL2)) {
|
|
8373
8442
|
await fs13.unlink(path).catch(() => {
|
|
8374
8443
|
});
|
|
@@ -8394,14 +8463,14 @@ async function readOrNull3(path) {
|
|
|
8394
8463
|
|
|
8395
8464
|
// ../listener/dist/mcp/auto-config/writers/cursor.js
|
|
8396
8465
|
import { promises as fs14 } from "fs";
|
|
8397
|
-
import { join as
|
|
8466
|
+
import { join as join32 } from "path";
|
|
8398
8467
|
var cursorWriter = {
|
|
8399
8468
|
tool: "cursor",
|
|
8400
8469
|
async detect(repoRoot) {
|
|
8401
|
-
return await fileExists10(
|
|
8470
|
+
return await fileExists10(join32(repoRoot, ".cursor")) || await fileExists10(join32(repoRoot, ".cursorrules"));
|
|
8402
8471
|
},
|
|
8403
8472
|
async write(ctx) {
|
|
8404
|
-
const path =
|
|
8473
|
+
const path = join32(ctx.repoRoot, ".cursor", "mcp.json");
|
|
8405
8474
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8406
8475
|
const status2 = await writeMergedConfig({
|
|
8407
8476
|
path,
|
|
@@ -8411,7 +8480,7 @@ var cursorWriter = {
|
|
|
8411
8480
|
return { status: status2, path };
|
|
8412
8481
|
},
|
|
8413
8482
|
async remove(ctx) {
|
|
8414
|
-
const path =
|
|
8483
|
+
const path = join32(ctx.repoRoot, ".cursor", "mcp.json");
|
|
8415
8484
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8416
8485
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8417
8486
|
}
|
|
@@ -8427,14 +8496,14 @@ async function fileExists10(path) {
|
|
|
8427
8496
|
|
|
8428
8497
|
// ../listener/dist/mcp/auto-config/writers/gemini-cli.js
|
|
8429
8498
|
import { promises as fs15 } from "fs";
|
|
8430
|
-
import { join as
|
|
8499
|
+
import { join as join33 } from "path";
|
|
8431
8500
|
var geminiCliWriter = {
|
|
8432
8501
|
tool: "gemini-cli",
|
|
8433
8502
|
async detect(_repoRoot, home) {
|
|
8434
|
-
return fileExists11(
|
|
8503
|
+
return fileExists11(join33(home, ".gemini"));
|
|
8435
8504
|
},
|
|
8436
8505
|
async write(ctx) {
|
|
8437
|
-
const path =
|
|
8506
|
+
const path = join33(ctx.home, ".gemini", "settings.json");
|
|
8438
8507
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8439
8508
|
const status2 = await writeMergedConfig({
|
|
8440
8509
|
path,
|
|
@@ -8444,7 +8513,7 @@ var geminiCliWriter = {
|
|
|
8444
8513
|
return { status: status2, path };
|
|
8445
8514
|
},
|
|
8446
8515
|
async remove(ctx) {
|
|
8447
|
-
const path =
|
|
8516
|
+
const path = join33(ctx.home, ".gemini", "settings.json");
|
|
8448
8517
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8449
8518
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8450
8519
|
}
|
|
@@ -8460,15 +8529,15 @@ async function fileExists11(path) {
|
|
|
8460
8529
|
|
|
8461
8530
|
// ../listener/dist/mcp/auto-config/writers/gemini-hooks.js
|
|
8462
8531
|
import { promises as fs16 } from "fs";
|
|
8463
|
-
import { join as
|
|
8532
|
+
import { join as join34 } from "path";
|
|
8464
8533
|
var SETTINGS_REL = ".gemini/settings.json";
|
|
8465
8534
|
var geminiHooksWriter = {
|
|
8466
8535
|
tool: "gemini-hooks",
|
|
8467
8536
|
async detect(repoRoot, home) {
|
|
8468
|
-
return await fileExists12(
|
|
8537
|
+
return await fileExists12(join34(home, ".gemini")) || await fileExists12(join34(repoRoot, ".gemini"));
|
|
8469
8538
|
},
|
|
8470
8539
|
async write(ctx) {
|
|
8471
|
-
const repoSignal = await fileExists12(
|
|
8540
|
+
const repoSignal = await fileExists12(join34(ctx.repoRoot, ".gemini")) || await fileExists12(join34(ctx.repoRoot, "GEMINI.md"));
|
|
8472
8541
|
const selected = ctx.selectedTools?.includes("gemini") ?? false;
|
|
8473
8542
|
if (!repoSignal && !selected) {
|
|
8474
8543
|
return { status: "skipped", reason: "no repo-scoped Gemini signal and not selected" };
|
|
@@ -8480,7 +8549,7 @@ var geminiHooksWriter = {
|
|
|
8480
8549
|
reason: `${SETTINGS_REL} is git-tracked; add the RepoWise BeforeAgent hook manually to opt in`
|
|
8481
8550
|
};
|
|
8482
8551
|
}
|
|
8483
|
-
const path =
|
|
8552
|
+
const path = join34(ctx.repoRoot, SETTINGS_REL);
|
|
8484
8553
|
const existing = await readOrNull4(path);
|
|
8485
8554
|
const merged = mergeGeminiHookSettings(existing, {
|
|
8486
8555
|
repoName: ctx.repoName,
|
|
@@ -8490,13 +8559,13 @@ var geminiHooksWriter = {
|
|
|
8490
8559
|
if (merged === existing) {
|
|
8491
8560
|
return { status: "unchanged", path };
|
|
8492
8561
|
}
|
|
8493
|
-
await fs16.mkdir(
|
|
8562
|
+
await fs16.mkdir(join34(ctx.repoRoot, ".gemini"), { recursive: true });
|
|
8494
8563
|
await fs16.writeFile(path, merged, "utf-8");
|
|
8495
8564
|
await applyGitignoreChanges(ctx.repoRoot, { add: [SETTINGS_REL] });
|
|
8496
8565
|
return { status: "written", path };
|
|
8497
8566
|
},
|
|
8498
8567
|
async remove(ctx) {
|
|
8499
|
-
const path =
|
|
8568
|
+
const path = join34(ctx.repoRoot, SETTINGS_REL);
|
|
8500
8569
|
const existing = await readOrNull4(path);
|
|
8501
8570
|
if (existing !== null) {
|
|
8502
8571
|
const next = removeGeminiHookSettings(existing);
|
|
@@ -8527,14 +8596,14 @@ async function readOrNull4(path) {
|
|
|
8527
8596
|
|
|
8528
8597
|
// ../listener/dist/mcp/auto-config/writers/roo.js
|
|
8529
8598
|
import { promises as fs17 } from "fs";
|
|
8530
|
-
import { join as
|
|
8599
|
+
import { join as join35 } from "path";
|
|
8531
8600
|
var rooWriter = {
|
|
8532
8601
|
tool: "roo",
|
|
8533
8602
|
async detect(repoRoot, home) {
|
|
8534
|
-
return await fileExists13(
|
|
8603
|
+
return await fileExists13(join35(repoRoot, ".roo")) || await fileExists13(join35(home, ".roo"));
|
|
8535
8604
|
},
|
|
8536
8605
|
async write(ctx) {
|
|
8537
|
-
const repoConfig =
|
|
8606
|
+
const repoConfig = join35(ctx.repoRoot, ".roo", "mcp.json");
|
|
8538
8607
|
const before = await readOrNull5(repoConfig);
|
|
8539
8608
|
await this.remove(ctx);
|
|
8540
8609
|
const after = await readOrNull5(repoConfig);
|
|
@@ -8544,9 +8613,9 @@ var rooWriter = {
|
|
|
8544
8613
|
};
|
|
8545
8614
|
},
|
|
8546
8615
|
async remove(ctx) {
|
|
8547
|
-
const repoConfig =
|
|
8548
|
-
const homeConfig =
|
|
8549
|
-
const homeSettings =
|
|
8616
|
+
const repoConfig = join35(ctx.repoRoot, ".roo", "mcp.json");
|
|
8617
|
+
const homeConfig = join35(ctx.home, ".roo", "mcp.json");
|
|
8618
|
+
const homeSettings = join35(ctx.home, ".roo", "settings.json");
|
|
8550
8619
|
for (const path of [repoConfig, homeConfig, homeSettings]) {
|
|
8551
8620
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`).catch(() => {
|
|
8552
8621
|
});
|
|
@@ -8573,14 +8642,14 @@ async function readOrNull5(path) {
|
|
|
8573
8642
|
|
|
8574
8643
|
// ../listener/dist/mcp/auto-config/writers/windsurf.js
|
|
8575
8644
|
import { promises as fs18 } from "fs";
|
|
8576
|
-
import { join as
|
|
8645
|
+
import { join as join36 } from "path";
|
|
8577
8646
|
var windsurfWriter = {
|
|
8578
8647
|
tool: "windsurf",
|
|
8579
8648
|
async detect(_repoRoot, home) {
|
|
8580
|
-
return fileExists14(
|
|
8649
|
+
return fileExists14(join36(home, ".codeium", "windsurf"));
|
|
8581
8650
|
},
|
|
8582
8651
|
async write(ctx) {
|
|
8583
|
-
const path =
|
|
8652
|
+
const path = join36(ctx.home, ".codeium", "windsurf", "mcp_config.json");
|
|
8584
8653
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8585
8654
|
const status2 = await writeMergedConfig({
|
|
8586
8655
|
path,
|
|
@@ -8590,7 +8659,7 @@ var windsurfWriter = {
|
|
|
8590
8659
|
return { status: status2, path };
|
|
8591
8660
|
},
|
|
8592
8661
|
async remove(ctx) {
|
|
8593
|
-
const path =
|
|
8662
|
+
const path = join36(ctx.home, ".codeium", "windsurf", "mcp_config.json");
|
|
8594
8663
|
await removeFromConfig(path, `RepoWise MCP for ${ctx.repoName}`);
|
|
8595
8664
|
await removeFromConfig(path, `repowise-${ctx.repoId}`);
|
|
8596
8665
|
}
|
|
@@ -8623,7 +8692,7 @@ var WRITERS = [
|
|
|
8623
8692
|
|
|
8624
8693
|
// ../listener/dist/mcp/auto-config/index.js
|
|
8625
8694
|
async function runAutoConfig(opts) {
|
|
8626
|
-
const home = opts.home ??
|
|
8695
|
+
const home = opts.home ?? homedir6();
|
|
8627
8696
|
const writers = opts.writers ?? WRITERS;
|
|
8628
8697
|
const results = [];
|
|
8629
8698
|
for (const writer of writers) {
|
|
@@ -8672,7 +8741,7 @@ init_installer();
|
|
|
8672
8741
|
init_registry();
|
|
8673
8742
|
init_lsp_tools();
|
|
8674
8743
|
import { promises as fs19 } from "fs";
|
|
8675
|
-
import { join as
|
|
8744
|
+
import { join as join37 } from "path";
|
|
8676
8745
|
async function collectRepresentativeFiles(repoRoot) {
|
|
8677
8746
|
const reps = /* @__PURE__ */ new Map();
|
|
8678
8747
|
let inspected = 0;
|
|
@@ -8713,7 +8782,7 @@ async function collectRepresentativeFiles(repoRoot) {
|
|
|
8713
8782
|
continue;
|
|
8714
8783
|
if (name === "node_modules" || name === "dist" || name === "build")
|
|
8715
8784
|
continue;
|
|
8716
|
-
const sub =
|
|
8785
|
+
const sub = join37(repoRoot, name);
|
|
8717
8786
|
try {
|
|
8718
8787
|
const stat8 = await fs19.stat(sub);
|
|
8719
8788
|
if (stat8.isDirectory())
|
|
@@ -8761,7 +8830,7 @@ init_config_dir();
|
|
|
8761
8830
|
import { promises as fs20 } from "fs";
|
|
8762
8831
|
import { spawn as spawn9, execFile as execFile5 } from "child_process";
|
|
8763
8832
|
import { createWriteStream as createWriteStream2 } from "fs";
|
|
8764
|
-
import { join as
|
|
8833
|
+
import { join as join38 } from "path";
|
|
8765
8834
|
import { promisify as promisify3 } from "util";
|
|
8766
8835
|
var execFileAsync3 = promisify3(execFile5);
|
|
8767
8836
|
async function isCommandOnPath2(cmd) {
|
|
@@ -8825,7 +8894,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
8825
8894
|
if (e.isDirectory()) {
|
|
8826
8895
|
if (skip.has(e.name) || e.name.startsWith("."))
|
|
8827
8896
|
continue;
|
|
8828
|
-
await rec(
|
|
8897
|
+
await rec(join38(dir, e.name));
|
|
8829
8898
|
continue;
|
|
8830
8899
|
}
|
|
8831
8900
|
const dot = e.name.lastIndexOf(".");
|
|
@@ -8834,7 +8903,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
8834
8903
|
const ext = e.name.slice(dot);
|
|
8835
8904
|
if (!C_EXTS.has(ext) && !CPP_EXTS.has(ext))
|
|
8836
8905
|
continue;
|
|
8837
|
-
sources.push({ path:
|
|
8906
|
+
sources.push({ path: join38(dir, e.name), ext });
|
|
8838
8907
|
}
|
|
8839
8908
|
}
|
|
8840
8909
|
await rec(repoRoot);
|
|
@@ -8850,9 +8919,9 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
8850
8919
|
command: `${driver} ${std} -I. -I./include -c "${src}"`
|
|
8851
8920
|
};
|
|
8852
8921
|
});
|
|
8853
|
-
const outDir =
|
|
8922
|
+
const outDir = join38(repoRoot, ".repowise");
|
|
8854
8923
|
await fs20.mkdir(outDir, { recursive: true });
|
|
8855
|
-
const outPath =
|
|
8924
|
+
const outPath = join38(outDir, "compile_commands.json");
|
|
8856
8925
|
await fs20.writeFile(outPath, JSON.stringify(entries, null, 2));
|
|
8857
8926
|
const capHit = sources.length >= MAX_STUB_SOURCES;
|
|
8858
8927
|
console.log(`[workspace-prep] ${repoId}: wrote ${entries.length.toString()}-entry compile_commands stub to .repowise/${capHit ? " (cap reached \u2014 additional sources truncated)" : ""}`);
|
|
@@ -8861,7 +8930,7 @@ async function maybeWriteClangdStub(repoRoot, repoId) {
|
|
|
8861
8930
|
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
8862
8931
|
async function fileExists15(repoRoot, name) {
|
|
8863
8932
|
try {
|
|
8864
|
-
await fs20.access(
|
|
8933
|
+
await fs20.access(join38(repoRoot, name));
|
|
8865
8934
|
return true;
|
|
8866
8935
|
} catch {
|
|
8867
8936
|
return false;
|
|
@@ -8872,7 +8941,7 @@ async function detectWorkspaceDeps(repoRoot) {
|
|
|
8872
8941
|
if (await fileExists15(repoRoot, "package.json")) {
|
|
8873
8942
|
let pkgRaw = "";
|
|
8874
8943
|
try {
|
|
8875
|
-
pkgRaw = await fs20.readFile(
|
|
8944
|
+
pkgRaw = await fs20.readFile(join38(repoRoot, "package.json"), "utf8");
|
|
8876
8945
|
} catch {
|
|
8877
8946
|
}
|
|
8878
8947
|
if (pkgRaw) {
|
|
@@ -8975,7 +9044,7 @@ async function runWorkspacePreps(opts) {
|
|
|
8975
9044
|
if (opts.missing.length === 0)
|
|
8976
9045
|
return [];
|
|
8977
9046
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8978
|
-
const logPath2 =
|
|
9047
|
+
const logPath2 = join38(getConfigDir(), `install-log.${safeRepoId}.txt`);
|
|
8979
9048
|
await fs20.mkdir(getConfigDir(), { recursive: true });
|
|
8980
9049
|
const stream = opts.logStream ?? createWriteStream2(logPath2, { flags: "a" });
|
|
8981
9050
|
stream.on("error", () => {
|
|
@@ -9126,7 +9195,7 @@ async function prepareWorkspaceDepsForRepos(repos) {
|
|
|
9126
9195
|
init_registry();
|
|
9127
9196
|
import { execFile as execFileCb, spawn as spawn10 } from "child_process";
|
|
9128
9197
|
import { access as access3, readdir as readdir4 } from "fs/promises";
|
|
9129
|
-
import { join as
|
|
9198
|
+
import { join as join39 } from "path";
|
|
9130
9199
|
import { promisify as promisify4 } from "util";
|
|
9131
9200
|
var execFile6 = promisify4(execFileCb);
|
|
9132
9201
|
var DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
@@ -9179,7 +9248,7 @@ async function ensureIndexable(indexRoot, language, options = {}) {
|
|
|
9179
9248
|
}
|
|
9180
9249
|
}
|
|
9181
9250
|
try {
|
|
9182
|
-
await access3(
|
|
9251
|
+
await access3(join39(indexRoot, spec.indexStoreProbe));
|
|
9183
9252
|
return { ready: true, built: false };
|
|
9184
9253
|
} catch {
|
|
9185
9254
|
}
|
|
@@ -9219,7 +9288,9 @@ async function ensureIndexable(indexRoot, language, options = {}) {
|
|
|
9219
9288
|
init_src();
|
|
9220
9289
|
init_registry();
|
|
9221
9290
|
import { execFile as execFileCb2 } from "child_process";
|
|
9291
|
+
import { dirname as dirname16 } from "path";
|
|
9222
9292
|
import { promisify as promisify5 } from "util";
|
|
9293
|
+
init_daemon_path();
|
|
9223
9294
|
|
|
9224
9295
|
// ../listener/dist/typed-resolution/lsp-upgrade-strategy.js
|
|
9225
9296
|
var goStrategy = {
|
|
@@ -9701,7 +9772,13 @@ async function isCommandOnPath4(command) {
|
|
|
9701
9772
|
return false;
|
|
9702
9773
|
const probeCmd = process.platform === "win32" ? "where" : "which";
|
|
9703
9774
|
try {
|
|
9704
|
-
await execFile7(probeCmd, [command], {
|
|
9775
|
+
await execFile7(probeCmd, [command], {
|
|
9776
|
+
timeout: 5e3,
|
|
9777
|
+
env: {
|
|
9778
|
+
...process.env,
|
|
9779
|
+
PATH: buildLspSpawnPath(process.env.PATH, dirname16(process.execPath), managedBinDirs())
|
|
9780
|
+
}
|
|
9781
|
+
});
|
|
9705
9782
|
return true;
|
|
9706
9783
|
} catch {
|
|
9707
9784
|
return false;
|
|
@@ -9905,13 +9982,13 @@ init_config_dir();
|
|
|
9905
9982
|
import { execFile as execFileCb3 } from "child_process";
|
|
9906
9983
|
import { createHash as createHash5 } from "crypto";
|
|
9907
9984
|
import { mkdir as mkdir15, readdir as readdir5, rm, stat as stat6 } from "fs/promises";
|
|
9908
|
-
import { join as
|
|
9985
|
+
import { join as join40 } from "path";
|
|
9909
9986
|
import { promisify as promisify6 } from "util";
|
|
9910
9987
|
var execFile8 = promisify6(execFileCb3);
|
|
9911
9988
|
var GIT_OP_TIMEOUT_MS = 6e4;
|
|
9912
9989
|
var MAX_CONCURRENT_WORKTREES = 3;
|
|
9913
9990
|
function worktreeBaseDir() {
|
|
9914
|
-
return
|
|
9991
|
+
return join40(getConfigDir(), "lsp-worktrees");
|
|
9915
9992
|
}
|
|
9916
9993
|
async function reapOrphanWorktrees(maxAgeMs = 24 * 60 * 60 * 1e3, base = worktreeBaseDir()) {
|
|
9917
9994
|
let reaped = 0;
|
|
@@ -9923,7 +10000,7 @@ async function reapOrphanWorktrees(maxAgeMs = 24 * 60 * 60 * 1e3, base = worktre
|
|
|
9923
10000
|
}
|
|
9924
10001
|
const cutoff = Date.now() - maxAgeMs;
|
|
9925
10002
|
for (const entry of entries) {
|
|
9926
|
-
const dir =
|
|
10003
|
+
const dir = join40(base, entry);
|
|
9927
10004
|
try {
|
|
9928
10005
|
const info = await stat6(dir);
|
|
9929
10006
|
if (!info.isDirectory() || info.mtimeMs > cutoff)
|
|
@@ -9956,7 +10033,7 @@ async function prepareCommittedTree(repoRoot, commitSha, options = {}) {
|
|
|
9956
10033
|
}
|
|
9957
10034
|
const base = options.worktreeBase ?? worktreeBaseDir();
|
|
9958
10035
|
const dirName = createHash5("sha256").update(`${repoRoot}\0${commitSha}`).digest("hex").slice(0, 16) + "-" + commitSha.slice(0, 12);
|
|
9959
|
-
const worktreePath =
|
|
10036
|
+
const worktreePath = join40(base, dirName);
|
|
9960
10037
|
try {
|
|
9961
10038
|
await mkdir15(base, { recursive: true });
|
|
9962
10039
|
await git(["-C", repoRoot, "worktree", "prune"]).catch(() => void 0);
|
|
@@ -10292,7 +10369,7 @@ var CRASH_LOOP_WINDOW_MS = 3e4;
|
|
|
10292
10369
|
var CRASH_LOOP_THRESHOLD = 3;
|
|
10293
10370
|
async function readRawToolConfig() {
|
|
10294
10371
|
try {
|
|
10295
|
-
const configPath =
|
|
10372
|
+
const configPath = join41(getConfigDir(), "config.json");
|
|
10296
10373
|
const data = await readFile13(configPath, "utf-8");
|
|
10297
10374
|
const raw = JSON.parse(data);
|
|
10298
10375
|
return {
|
|
@@ -10367,11 +10444,11 @@ function resolveAuditRoots() {
|
|
|
10367
10444
|
return override.split(":").map((s) => s.trim()).filter(Boolean);
|
|
10368
10445
|
}
|
|
10369
10446
|
const out = /* @__PURE__ */ new Set();
|
|
10370
|
-
let dir =
|
|
10447
|
+
let dir = dirname17(process.execPath);
|
|
10371
10448
|
for (let i = 0; i < 8; i += 1) {
|
|
10372
|
-
out.add(
|
|
10373
|
-
out.add(
|
|
10374
|
-
const parent =
|
|
10449
|
+
out.add(join41(dir, "node_modules"));
|
|
10450
|
+
out.add(join41(dir, "lib", "node_modules"));
|
|
10451
|
+
const parent = dirname17(dir);
|
|
10375
10452
|
if (parent === dir)
|
|
10376
10453
|
break;
|
|
10377
10454
|
dir = parent;
|
|
@@ -10635,7 +10712,7 @@ async function checkStaleContext(repos, state, groups) {
|
|
|
10635
10712
|
if (group?.offline.isOffline)
|
|
10636
10713
|
continue;
|
|
10637
10714
|
const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
|
|
10638
|
-
const contextPath =
|
|
10715
|
+
const contextPath = join41(repo.localPath, "repowise-context");
|
|
10639
10716
|
let isMissingOrEmpty = false;
|
|
10640
10717
|
try {
|
|
10641
10718
|
const s = statSync2(contextPath);
|
|
@@ -10700,7 +10777,7 @@ async function reconcileAgentInstructions(repos) {
|
|
|
10700
10777
|
const { graphOnly } = await readRawToolConfig();
|
|
10701
10778
|
const variant = graphOnly ? "graph" : "full";
|
|
10702
10779
|
for (const repo of repos) {
|
|
10703
|
-
const path =
|
|
10780
|
+
const path = join41(repo.localPath, "repowise-context", "project-overview.md");
|
|
10704
10781
|
let content;
|
|
10705
10782
|
try {
|
|
10706
10783
|
content = await readFile13(path, "utf-8");
|
|
@@ -10784,7 +10861,7 @@ async function startListener() {
|
|
|
10784
10861
|
}
|
|
10785
10862
|
const configDir = getConfigDir();
|
|
10786
10863
|
await mkdir16(configDir, { recursive: true });
|
|
10787
|
-
const lockPath =
|
|
10864
|
+
const lockPath = join41(configDir, "listener.lock");
|
|
10788
10865
|
await writeFile15(lockPath, "", { flag: "a" });
|
|
10789
10866
|
let lockIsHeld = false;
|
|
10790
10867
|
try {
|
|
@@ -10827,7 +10904,7 @@ async function startListener() {
|
|
|
10827
10904
|
return;
|
|
10828
10905
|
}
|
|
10829
10906
|
if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
|
|
10830
|
-
console.error(`No repos configured. Add repos to ${
|
|
10907
|
+
console.error(`No repos configured. Add repos to ${join41(configDir, "config.json")}`);
|
|
10831
10908
|
await releaseLockAndExit();
|
|
10832
10909
|
process.exitCode = 1;
|
|
10833
10910
|
return;
|
|
@@ -10894,8 +10971,8 @@ async function startListener() {
|
|
|
10894
10971
|
const packageName = true ? "repowisestage" : "repowise";
|
|
10895
10972
|
let currentVersion = "";
|
|
10896
10973
|
try {
|
|
10897
|
-
const selfDir =
|
|
10898
|
-
const pkgJsonPath =
|
|
10974
|
+
const selfDir = dirname17(fileURLToPath3(import.meta.url));
|
|
10975
|
+
const pkgJsonPath = join41(selfDir, "..", "..", "package.json");
|
|
10899
10976
|
const pkgJson = JSON.parse(await readFile13(pkgJsonPath, "utf-8"));
|
|
10900
10977
|
currentVersion = pkgJson.version;
|
|
10901
10978
|
} catch (err) {
|
|
@@ -11126,6 +11203,9 @@ async function startListener() {
|
|
|
11126
11203
|
void warmReposLsp(newRepos, mcpRuntime.lspWorkspaces, config2.lspOverrides).catch(() => {
|
|
11127
11204
|
});
|
|
11128
11205
|
}
|
|
11206
|
+
void reconcileMcpConfigs(newRepos, packageName).catch((err) => {
|
|
11207
|
+
console.warn("[mcp-config] front-load for newly-registered repo(s) failed:", err instanceof Error ? err.message : String(err));
|
|
11208
|
+
});
|
|
11129
11209
|
}
|
|
11130
11210
|
} catch {
|
|
11131
11211
|
}
|
|
@@ -11398,7 +11478,7 @@ async function startListener() {
|
|
|
11398
11478
|
} catch {
|
|
11399
11479
|
}
|
|
11400
11480
|
}
|
|
11401
|
-
const credentialsPath =
|
|
11481
|
+
const credentialsPath = join41(getConfigDir(), "credentials.json");
|
|
11402
11482
|
let credentialsChanged = false;
|
|
11403
11483
|
let watcher = null;
|
|
11404
11484
|
try {
|
|
@@ -11443,8 +11523,8 @@ if (isDirectRun) {
|
|
|
11443
11523
|
}
|
|
11444
11524
|
|
|
11445
11525
|
// src/lib/env.ts
|
|
11446
|
-
import { homedir as
|
|
11447
|
-
import { join as
|
|
11526
|
+
import { homedir as homedir7 } from "os";
|
|
11527
|
+
import { join as join42 } from "path";
|
|
11448
11528
|
var IS_STAGING2 = true ? true : false;
|
|
11449
11529
|
var PRODUCTION = {
|
|
11450
11530
|
apiUrl: "https://api.repowise.ai",
|
|
@@ -11464,7 +11544,7 @@ function getEnvConfig() {
|
|
|
11464
11544
|
return IS_STAGING2 ? STAGING : PRODUCTION;
|
|
11465
11545
|
}
|
|
11466
11546
|
function getConfigDir2() {
|
|
11467
|
-
return
|
|
11547
|
+
return join42(homedir7(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
|
|
11468
11548
|
}
|
|
11469
11549
|
function getPackageName() {
|
|
11470
11550
|
return true ? "repowisestage" : "repowise";
|
|
@@ -11475,11 +11555,11 @@ import chalk from "chalk";
|
|
|
11475
11555
|
|
|
11476
11556
|
// src/lib/config.ts
|
|
11477
11557
|
import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir17, rename as rename4, unlink as unlink10 } from "fs/promises";
|
|
11478
|
-
import { join as
|
|
11558
|
+
import { join as join43 } from "path";
|
|
11479
11559
|
import lockfile5 from "proper-lockfile";
|
|
11480
11560
|
async function getConfig() {
|
|
11481
11561
|
try {
|
|
11482
|
-
const data = await readFile14(
|
|
11562
|
+
const data = await readFile14(join43(getConfigDir2(), "config.json"), "utf-8");
|
|
11483
11563
|
return JSON.parse(data);
|
|
11484
11564
|
} catch {
|
|
11485
11565
|
return {};
|
|
@@ -11487,7 +11567,7 @@ async function getConfig() {
|
|
|
11487
11567
|
}
|
|
11488
11568
|
async function saveConfig(config2) {
|
|
11489
11569
|
const dir = getConfigDir2();
|
|
11490
|
-
const path =
|
|
11570
|
+
const path = join43(dir, "config.json");
|
|
11491
11571
|
await mkdir17(dir, { recursive: true });
|
|
11492
11572
|
const tmpPath = path + ".tmp";
|
|
11493
11573
|
try {
|
|
@@ -11503,7 +11583,7 @@ async function saveConfig(config2) {
|
|
|
11503
11583
|
}
|
|
11504
11584
|
async function mergeAndSaveConfig(updates) {
|
|
11505
11585
|
const dir = getConfigDir2();
|
|
11506
|
-
const path =
|
|
11586
|
+
const path = join43(dir, "config.json");
|
|
11507
11587
|
await mkdir17(dir, { recursive: true });
|
|
11508
11588
|
try {
|
|
11509
11589
|
await writeFile16(path, "", { flag: "a" });
|
|
@@ -11574,7 +11654,7 @@ async function showWelcome(currentVersion) {
|
|
|
11574
11654
|
|
|
11575
11655
|
// src/commands/create.ts
|
|
11576
11656
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11577
|
-
import { dirname as
|
|
11657
|
+
import { dirname as dirname19, join as join49 } from "path";
|
|
11578
11658
|
init_src();
|
|
11579
11659
|
import chalk8 from "chalk";
|
|
11580
11660
|
import ora from "ora";
|
|
@@ -11583,7 +11663,7 @@ import ora from "ora";
|
|
|
11583
11663
|
import { createHash as createHash6, randomBytes as randomBytes3 } from "crypto";
|
|
11584
11664
|
import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir18, chmod as chmod4, unlink as unlink11 } from "fs/promises";
|
|
11585
11665
|
import http from "http";
|
|
11586
|
-
import { join as
|
|
11666
|
+
import { join as join44 } from "path";
|
|
11587
11667
|
var CLI_CALLBACK_PORT = 19876;
|
|
11588
11668
|
var CALLBACK_TIMEOUT_MS = 12e4;
|
|
11589
11669
|
function getCognitoConfigForStorage() {
|
|
@@ -11749,7 +11829,7 @@ async function refreshTokens2(refreshToken) {
|
|
|
11749
11829
|
}
|
|
11750
11830
|
async function getStoredCredentials2() {
|
|
11751
11831
|
try {
|
|
11752
|
-
const credPath =
|
|
11832
|
+
const credPath = join44(getConfigDir2(), "credentials.json");
|
|
11753
11833
|
const data = await readFile15(credPath, "utf-8");
|
|
11754
11834
|
return JSON.parse(data);
|
|
11755
11835
|
} catch (err) {
|
|
@@ -11761,14 +11841,14 @@ async function getStoredCredentials2() {
|
|
|
11761
11841
|
}
|
|
11762
11842
|
async function storeCredentials2(credentials) {
|
|
11763
11843
|
const dir = getConfigDir2();
|
|
11764
|
-
const credPath =
|
|
11844
|
+
const credPath = join44(dir, "credentials.json");
|
|
11765
11845
|
await mkdir18(dir, { recursive: true, mode: 448 });
|
|
11766
11846
|
await writeFile17(credPath, JSON.stringify(credentials, null, 2));
|
|
11767
11847
|
await chmod4(credPath, 384);
|
|
11768
11848
|
}
|
|
11769
11849
|
async function clearCredentials() {
|
|
11770
11850
|
try {
|
|
11771
|
-
await unlink11(
|
|
11851
|
+
await unlink11(join44(getConfigDir2(), "credentials.json"));
|
|
11772
11852
|
} catch (err) {
|
|
11773
11853
|
if (err.code !== "ENOENT") throw err;
|
|
11774
11854
|
}
|
|
@@ -11976,9 +12056,9 @@ async function selectAiTools() {
|
|
|
11976
12056
|
|
|
11977
12057
|
// src/lib/gitignore.ts
|
|
11978
12058
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
|
|
11979
|
-
import { join as
|
|
12059
|
+
import { join as join45 } from "path";
|
|
11980
12060
|
function ensureGitignore(repoRoot, entry) {
|
|
11981
|
-
const gitignorePath =
|
|
12061
|
+
const gitignorePath = join45(repoRoot, ".gitignore");
|
|
11982
12062
|
if (existsSync2(gitignorePath)) {
|
|
11983
12063
|
const content = readFileSync2(gitignorePath, "utf-8");
|
|
11984
12064
|
const lines = content.split("\n").map((l) => l.trim());
|
|
@@ -11995,7 +12075,7 @@ function ensureGitignore(repoRoot, entry) {
|
|
|
11995
12075
|
// src/lib/graph-cache.ts
|
|
11996
12076
|
init_config_dir();
|
|
11997
12077
|
import { mkdirSync, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
|
|
11998
|
-
import { dirname as
|
|
12078
|
+
import { dirname as dirname18, join as join46 } from "path";
|
|
11999
12079
|
var SAFE_REPO_ID = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
12000
12080
|
function assertSafeRepoId2(repoId) {
|
|
12001
12081
|
if (!repoId || typeof repoId !== "string" || !SAFE_REPO_ID.test(repoId) || repoId === "." || repoId === ".." || repoId.startsWith(".")) {
|
|
@@ -12004,7 +12084,7 @@ function assertSafeRepoId2(repoId) {
|
|
|
12004
12084
|
}
|
|
12005
12085
|
function graphCachePath(repoId) {
|
|
12006
12086
|
assertSafeRepoId2(repoId);
|
|
12007
|
-
return
|
|
12087
|
+
return join46(getConfigDir(), "graphs", `${repoId}.json`);
|
|
12008
12088
|
}
|
|
12009
12089
|
function isUsableGraph(parsed) {
|
|
12010
12090
|
if (typeof parsed !== "object" || parsed === null) return false;
|
|
@@ -12022,9 +12102,27 @@ function readErrorCode(body) {
|
|
|
12022
12102
|
return void 0;
|
|
12023
12103
|
}
|
|
12024
12104
|
}
|
|
12105
|
+
async function readBodyBounded(res, ctrl, bodyTimeoutMs) {
|
|
12106
|
+
const bodyPromise = res.text();
|
|
12107
|
+
void bodyPromise.catch(() => {
|
|
12108
|
+
});
|
|
12109
|
+
let timer;
|
|
12110
|
+
const timeout = new Promise((_, reject) => {
|
|
12111
|
+
timer = setTimeout(() => {
|
|
12112
|
+
ctrl.abort();
|
|
12113
|
+
reject(new Error("GRAPH_BODY_TIMEOUT"));
|
|
12114
|
+
}, bodyTimeoutMs);
|
|
12115
|
+
});
|
|
12116
|
+
try {
|
|
12117
|
+
return await Promise.race([bodyPromise, timeout]);
|
|
12118
|
+
} finally {
|
|
12119
|
+
if (timer) clearTimeout(timer);
|
|
12120
|
+
}
|
|
12121
|
+
}
|
|
12025
12122
|
async function ensureGraphDownloaded(opts) {
|
|
12026
12123
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
12027
12124
|
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
12125
|
+
const bodyTimeoutMs = opts.bodyTimeoutMs ?? 12e4;
|
|
12028
12126
|
const maxRetries = opts.maxRetries ?? 3;
|
|
12029
12127
|
const sleep2 = opts.sleepFn ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
12030
12128
|
let targetPath;
|
|
@@ -12081,7 +12179,16 @@ async function ensureGraphDownloaded(opts) {
|
|
|
12081
12179
|
if (!res.ok) {
|
|
12082
12180
|
return { status: "error", message: `HTTP ${String(res.status)}` };
|
|
12083
12181
|
}
|
|
12084
|
-
|
|
12182
|
+
let body;
|
|
12183
|
+
try {
|
|
12184
|
+
body = await readBodyBounded(res, ctrl, bodyTimeoutMs);
|
|
12185
|
+
} catch (err) {
|
|
12186
|
+
if (attempt < maxRetries) {
|
|
12187
|
+
await sleep2(2e3 * attempt);
|
|
12188
|
+
continue;
|
|
12189
|
+
}
|
|
12190
|
+
return { status: "error", message: err instanceof Error ? err.message : String(err) };
|
|
12191
|
+
}
|
|
12085
12192
|
let parsed;
|
|
12086
12193
|
try {
|
|
12087
12194
|
parsed = JSON.parse(body);
|
|
@@ -12096,7 +12203,7 @@ async function ensureGraphDownloaded(opts) {
|
|
|
12096
12203
|
return { status: "not_found", message: "EMPTY_GRAPH" };
|
|
12097
12204
|
}
|
|
12098
12205
|
try {
|
|
12099
|
-
mkdirSync(
|
|
12206
|
+
mkdirSync(dirname18(targetPath), { recursive: true });
|
|
12100
12207
|
const tmp = `${targetPath}.${String(process.pid)}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
12101
12208
|
try {
|
|
12102
12209
|
writeFileSync2(tmp, body, { encoding: "utf-8", mode: 384 });
|
|
@@ -12247,7 +12354,7 @@ async function handleInterview(syncId, questionId, questionText, questionContext
|
|
|
12247
12354
|
const message = err instanceof Error ? err.message : String(err);
|
|
12248
12355
|
if (message.includes("not awaiting input") || message.includes("expired")) {
|
|
12249
12356
|
console.log(chalk3.dim(" Pipeline has already moved on \u2014 continuing."));
|
|
12250
|
-
return;
|
|
12357
|
+
return { finished: true };
|
|
12251
12358
|
}
|
|
12252
12359
|
try {
|
|
12253
12360
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
@@ -12257,7 +12364,7 @@ async function handleInterview(syncId, questionId, questionText, questionContext
|
|
|
12257
12364
|
});
|
|
12258
12365
|
} catch {
|
|
12259
12366
|
console.log(chalk3.yellow(" Could not submit answer \u2014 pipeline will continue."));
|
|
12260
|
-
return;
|
|
12367
|
+
return { finished: false };
|
|
12261
12368
|
}
|
|
12262
12369
|
}
|
|
12263
12370
|
if (action === "done") {
|
|
@@ -12268,6 +12375,7 @@ async function handleInterview(syncId, questionId, questionText, questionContext
|
|
|
12268
12375
|
console.log(chalk3.dim(" Answer recorded."));
|
|
12269
12376
|
}
|
|
12270
12377
|
console.log("");
|
|
12378
|
+
return { finished: action === "done" || questionCounter >= MAX_QUESTIONS };
|
|
12271
12379
|
}
|
|
12272
12380
|
|
|
12273
12381
|
// src/lib/progress-renderer.ts
|
|
@@ -12300,6 +12408,12 @@ var ProgressRenderer = class {
|
|
|
12300
12408
|
privacyShieldShown = false;
|
|
12301
12409
|
discoveryShown = false;
|
|
12302
12410
|
interviewCompleteShown = false;
|
|
12411
|
+
// FIX-10: the scan runs in PARALLEL with the interview, so scanProgress
|
|
12412
|
+
// arrives mid-interview. Hold scan rendering until the interview is
|
|
12413
|
+
// definitively over (setInterviewComplete) so the coffee/Code-Analysis/graph
|
|
12414
|
+
// block never interrupts the Q&A. Buffer the latest progress meanwhile.
|
|
12415
|
+
interviewComplete = false;
|
|
12416
|
+
pendingScanProgress = null;
|
|
12303
12417
|
scanHeaderShown = false;
|
|
12304
12418
|
scanSummaryShown = false;
|
|
12305
12419
|
graphSubtitleShown = false;
|
|
@@ -12601,6 +12715,21 @@ var ProgressRenderer = class {
|
|
|
12601
12715
|
}
|
|
12602
12716
|
return `${stepLabel}... ${chalk4.dim(`(${overallPct}%)`)}`;
|
|
12603
12717
|
}
|
|
12718
|
+
/**
|
|
12719
|
+
* FIX-10 — mark the interview definitively over. Unlocks scan-progress
|
|
12720
|
+
* rendering and flushes any progress buffered during the interview, so the
|
|
12721
|
+
* coffee → Code-Analysis → graph-ready block appears in order AFTER the last
|
|
12722
|
+
* question (renderScanProgress is idempotent via its *Shown latches).
|
|
12723
|
+
* Idempotent; safe to call from multiple completion paths.
|
|
12724
|
+
*/
|
|
12725
|
+
setInterviewComplete(spinner) {
|
|
12726
|
+
if (this.interviewComplete) return;
|
|
12727
|
+
this.interviewComplete = true;
|
|
12728
|
+
if (this.pendingScanProgress) {
|
|
12729
|
+
this.renderScanProgress(this.pendingScanProgress, spinner);
|
|
12730
|
+
this.pendingScanProgress = null;
|
|
12731
|
+
}
|
|
12732
|
+
}
|
|
12604
12733
|
update(syncResult, spinner) {
|
|
12605
12734
|
if (syncResult.privacyShieldEnabled !== void 0) {
|
|
12606
12735
|
this.renderPrivacyShield(syncResult.privacyShieldEnabled, spinner);
|
|
@@ -12609,7 +12738,11 @@ var ProgressRenderer = class {
|
|
|
12609
12738
|
this.renderDiscovery(syncResult.discoveryResult, spinner);
|
|
12610
12739
|
}
|
|
12611
12740
|
if (syncResult.scanProgress) {
|
|
12612
|
-
this.
|
|
12741
|
+
if (this.interviewComplete) {
|
|
12742
|
+
this.renderScanProgress(syncResult.scanProgress, spinner);
|
|
12743
|
+
} else {
|
|
12744
|
+
this.pendingScanProgress = syncResult.scanProgress;
|
|
12745
|
+
}
|
|
12613
12746
|
}
|
|
12614
12747
|
if (syncResult.generationProgress?.fileStatuses && syncResult.generationProgress.fileStatuses.length > 0) {
|
|
12615
12748
|
this.renderFileStatuses(syncResult.generationProgress.fileStatuses, spinner);
|
|
@@ -12669,7 +12802,7 @@ import chalk6 from "chalk";
|
|
|
12669
12802
|
|
|
12670
12803
|
// src/lib/dep-installer.ts
|
|
12671
12804
|
import { promises as fs21 } from "fs";
|
|
12672
|
-
import { join as
|
|
12805
|
+
import { join as join47 } from "path";
|
|
12673
12806
|
var SUPPORTED_DEP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
12674
12807
|
"typescript",
|
|
12675
12808
|
"javascript",
|
|
@@ -12686,7 +12819,7 @@ var exists = async (p) => {
|
|
|
12686
12819
|
}
|
|
12687
12820
|
};
|
|
12688
12821
|
async function fileExists16(repoRoot, name) {
|
|
12689
|
-
return exists(
|
|
12822
|
+
return exists(join47(repoRoot, name));
|
|
12690
12823
|
}
|
|
12691
12824
|
async function detectNodePackageManager(repoRoot) {
|
|
12692
12825
|
if (await fileExists16(repoRoot, "pnpm-lock.yaml")) {
|
|
@@ -12764,11 +12897,11 @@ async function detectMissingDeps(repoRoot, scopedLanguages) {
|
|
|
12764
12897
|
import { spawn as spawn11 } from "child_process";
|
|
12765
12898
|
import { createWriteStream as createWriteStream3 } from "fs";
|
|
12766
12899
|
import { promises as fs22 } from "fs";
|
|
12767
|
-
import { join as
|
|
12900
|
+
import { join as join48 } from "path";
|
|
12768
12901
|
var DEFAULT_INSTALL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
12769
12902
|
async function runMissingDepInstalls(opts) {
|
|
12770
12903
|
const safeRepoId = opts.repoId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
12771
|
-
const logPath2 =
|
|
12904
|
+
const logPath2 = join48(getConfigDir2(), `install-log.${safeRepoId}.txt`);
|
|
12772
12905
|
await fs22.mkdir(getConfigDir2(), { recursive: true });
|
|
12773
12906
|
const stream = opts.logStream ?? createWriteStream3(logPath2, { flags: "a" });
|
|
12774
12907
|
stream.on("error", () => {
|
|
@@ -12815,7 +12948,7 @@ async function runOne2(dep, repoRoot, stream, timeoutMs) {
|
|
|
12815
12948
|
}
|
|
12816
12949
|
async function runPipFlow(repoRoot, stream, timeoutMs) {
|
|
12817
12950
|
await runSimple(["python3", "-m", "venv", ".venv"], repoRoot, stream, timeoutMs);
|
|
12818
|
-
const venvPip = process.platform === "win32" ?
|
|
12951
|
+
const venvPip = process.platform === "win32" ? join48(".venv", "Scripts", "pip.exe") : join48(".venv", "bin", "pip");
|
|
12819
12952
|
await runSimple([venvPip, "install", "-r", "requirements.txt"], repoRoot, stream, timeoutMs);
|
|
12820
12953
|
}
|
|
12821
12954
|
function runSimple(cmd, repoRoot, stream, timeoutMs) {
|
|
@@ -13229,6 +13362,8 @@ async function create() {
|
|
|
13229
13362
|
const progressRenderer = new ProgressRenderer();
|
|
13230
13363
|
let depInstallShown = false;
|
|
13231
13364
|
let seenAwaitingInput = false;
|
|
13365
|
+
let interviewComplete = false;
|
|
13366
|
+
let interviewQuestionsAnswered = 0;
|
|
13232
13367
|
let lspWaitStartedAt = null;
|
|
13233
13368
|
let lspFellBackNoticeShown = false;
|
|
13234
13369
|
let depInstallPromise = null;
|
|
@@ -13269,6 +13404,8 @@ async function create() {
|
|
|
13269
13404
|
try {
|
|
13270
13405
|
while (true) {
|
|
13271
13406
|
if (++pollAttempts > MAX_POLL_ATTEMPTS) {
|
|
13407
|
+
progressRenderer.setInterviewComplete(spinner);
|
|
13408
|
+
progressRenderer.finalize();
|
|
13272
13409
|
spinner.fail(chalk8.red("Pipeline timed out. Check dashboard for status."));
|
|
13273
13410
|
process.exitCode = 1;
|
|
13274
13411
|
return;
|
|
@@ -13288,6 +13425,10 @@ async function create() {
|
|
|
13288
13425
|
if (sigintBusy) {
|
|
13289
13426
|
continue;
|
|
13290
13427
|
}
|
|
13428
|
+
if (!interviewComplete && graphOnly) {
|
|
13429
|
+
interviewComplete = true;
|
|
13430
|
+
progressRenderer.setInterviewComplete(spinner);
|
|
13431
|
+
}
|
|
13291
13432
|
progressRenderer.update(syncResult, spinner);
|
|
13292
13433
|
if (!graphOnly && syncResult.status === "in_progress") {
|
|
13293
13434
|
if (syncResult.lspWaitState === "awaiting" || syncResult.lspWaitState === "analyzing") {
|
|
@@ -13307,13 +13448,19 @@ async function create() {
|
|
|
13307
13448
|
}
|
|
13308
13449
|
if (syncResult.status === "awaiting_input" && syncResult.questionId && syncResult.questionText) {
|
|
13309
13450
|
spinner.stop();
|
|
13310
|
-
|
|
13451
|
+
const estimatedQ = syncResult.discoveryResult?.estimatedInterviewQuestions;
|
|
13452
|
+
const { finished } = await handleInterview(
|
|
13311
13453
|
syncId,
|
|
13312
13454
|
syncResult.questionId,
|
|
13313
13455
|
syncResult.questionText,
|
|
13314
13456
|
syncResult.questionContext ?? void 0,
|
|
13315
|
-
|
|
13457
|
+
estimatedQ
|
|
13316
13458
|
);
|
|
13459
|
+
interviewQuestionsAnswered++;
|
|
13460
|
+
if (!interviewComplete && (finished || estimatedQ !== void 0 && estimatedQ > 0 && interviewQuestionsAnswered >= estimatedQ)) {
|
|
13461
|
+
interviewComplete = true;
|
|
13462
|
+
progressRenderer.setInterviewComplete(spinner);
|
|
13463
|
+
}
|
|
13317
13464
|
spinner.start("Resuming pipeline...");
|
|
13318
13465
|
continue;
|
|
13319
13466
|
}
|
|
@@ -13333,6 +13480,7 @@ async function create() {
|
|
|
13333
13480
|
depInstallPromise = result.installPromise;
|
|
13334
13481
|
}
|
|
13335
13482
|
if (syncResult.status === "completed") {
|
|
13483
|
+
progressRenderer.setInterviewComplete(spinner);
|
|
13336
13484
|
progressRenderer.finalize();
|
|
13337
13485
|
const generatedFiles = syncResult.filesGenerated ?? [];
|
|
13338
13486
|
const fileCount = generatedFiles.length;
|
|
@@ -13357,6 +13505,7 @@ async function create() {
|
|
|
13357
13505
|
break;
|
|
13358
13506
|
}
|
|
13359
13507
|
if (syncResult.status === "failed") {
|
|
13508
|
+
progressRenderer.setInterviewComplete(spinner);
|
|
13360
13509
|
progressRenderer.finalize();
|
|
13361
13510
|
spinner.fail(chalk8.red(`Pipeline failed: ${syncResult.error ?? "Unknown error"}`));
|
|
13362
13511
|
process.exitCode = 1;
|
|
@@ -13372,7 +13521,7 @@ async function create() {
|
|
|
13372
13521
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
13373
13522
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
13374
13523
|
if (files.length > 0) {
|
|
13375
|
-
const contextDir =
|
|
13524
|
+
const contextDir = join49(repoRoot, DEFAULT_CONTEXT_FOLDER);
|
|
13376
13525
|
mkdirSync2(contextDir, { recursive: true });
|
|
13377
13526
|
let downloadedCount = 0;
|
|
13378
13527
|
let failedCount = 0;
|
|
@@ -13386,8 +13535,8 @@ async function create() {
|
|
|
13386
13535
|
const response = await fetch(presignedUrl);
|
|
13387
13536
|
if (response.ok) {
|
|
13388
13537
|
const content = await response.text();
|
|
13389
|
-
const filePath =
|
|
13390
|
-
mkdirSync2(
|
|
13538
|
+
const filePath = join49(contextDir, file.fileName);
|
|
13539
|
+
mkdirSync2(dirname19(filePath), { recursive: true });
|
|
13391
13540
|
writeFileSync3(filePath, content, "utf-8");
|
|
13392
13541
|
downloadedCount++;
|
|
13393
13542
|
} else {
|
|
@@ -13637,7 +13786,7 @@ Files are stored on our servers (not in git). Retry when online.`
|
|
|
13637
13786
|
|
|
13638
13787
|
// src/commands/member.ts
|
|
13639
13788
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
13640
|
-
import { dirname as
|
|
13789
|
+
import { dirname as dirname20, join as join50, resolve, sep } from "path";
|
|
13641
13790
|
import chalk9 from "chalk";
|
|
13642
13791
|
import ora2 from "ora";
|
|
13643
13792
|
var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
|
|
@@ -13791,7 +13940,7 @@ async function member() {
|
|
|
13791
13940
|
spinner.succeed(`Found ${chalk9.bold(files.length)} context files on server`);
|
|
13792
13941
|
const { tools } = await selectAiTools();
|
|
13793
13942
|
spinner.start("Downloading context files...");
|
|
13794
|
-
const contextDir =
|
|
13943
|
+
const contextDir = join50(repoRoot, DEFAULT_CONTEXT_FOLDER2);
|
|
13795
13944
|
mkdirSync3(contextDir, { recursive: true });
|
|
13796
13945
|
let downloadedCount = 0;
|
|
13797
13946
|
let failedCount = 0;
|
|
@@ -13812,7 +13961,7 @@ async function member() {
|
|
|
13812
13961
|
const response = await fetch(presignedUrl);
|
|
13813
13962
|
if (response.ok) {
|
|
13814
13963
|
const content = await response.text();
|
|
13815
|
-
mkdirSync3(
|
|
13964
|
+
mkdirSync3(dirname20(safePath), { recursive: true });
|
|
13816
13965
|
writeFileSync4(safePath, content, "utf-8");
|
|
13817
13966
|
downloadedCount++;
|
|
13818
13967
|
} else {
|
|
@@ -13990,10 +14139,10 @@ import ora3 from "ora";
|
|
|
13990
14139
|
|
|
13991
14140
|
// src/lib/tenant-graph-purge.ts
|
|
13992
14141
|
import { promises as fs23 } from "fs";
|
|
13993
|
-
import { homedir as
|
|
13994
|
-
import { join as
|
|
13995
|
-
async function purgeForeignGraphs(validRepoIds, home =
|
|
13996
|
-
const graphsDir =
|
|
14142
|
+
import { homedir as homedir8 } from "os";
|
|
14143
|
+
import { join as join51 } from "path";
|
|
14144
|
+
async function purgeForeignGraphs(validRepoIds, home = homedir8()) {
|
|
14145
|
+
const graphsDir = join51(home, ".repowise", "graphs");
|
|
13997
14146
|
const result = { kept: [], removed: [] };
|
|
13998
14147
|
let entries;
|
|
13999
14148
|
try {
|
|
@@ -14011,7 +14160,7 @@ async function purgeForeignGraphs(validRepoIds, home = homedir7()) {
|
|
|
14011
14160
|
result.kept.push(entry);
|
|
14012
14161
|
continue;
|
|
14013
14162
|
}
|
|
14014
|
-
const path =
|
|
14163
|
+
const path = join51(graphsDir, entry);
|
|
14015
14164
|
try {
|
|
14016
14165
|
const stat8 = await fs23.lstat(path);
|
|
14017
14166
|
if (stat8.isSymbolicLink()) {
|
|
@@ -14104,11 +14253,11 @@ async function logout() {
|
|
|
14104
14253
|
|
|
14105
14254
|
// src/commands/status.ts
|
|
14106
14255
|
import { readFile as readFile16 } from "fs/promises";
|
|
14107
|
-
import { basename as basename4, join as
|
|
14256
|
+
import { basename as basename4, join as join52 } from "path";
|
|
14108
14257
|
async function status() {
|
|
14109
14258
|
const configDir = getConfigDir2();
|
|
14110
|
-
const STATE_PATH =
|
|
14111
|
-
const CONFIG_PATH =
|
|
14259
|
+
const STATE_PATH = join52(configDir, "listener-state.json");
|
|
14260
|
+
const CONFIG_PATH = join52(configDir, "config.json");
|
|
14112
14261
|
let state = null;
|
|
14113
14262
|
try {
|
|
14114
14263
|
const data = await readFile16(STATE_PATH, "utf-8");
|
|
@@ -14156,7 +14305,7 @@ async function status() {
|
|
|
14156
14305
|
|
|
14157
14306
|
// src/commands/sync.ts
|
|
14158
14307
|
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
14159
|
-
import { dirname as
|
|
14308
|
+
import { dirname as dirname21, join as join53 } from "path";
|
|
14160
14309
|
import chalk12 from "chalk";
|
|
14161
14310
|
import ora4 from "ora";
|
|
14162
14311
|
var POLL_INTERVAL_MS2 = 3e3;
|
|
@@ -14305,7 +14454,7 @@ async function sync() {
|
|
|
14305
14454
|
const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
|
|
14306
14455
|
const files = listResult.data?.files ?? listResult.files ?? [];
|
|
14307
14456
|
if (files.length > 0) {
|
|
14308
|
-
const contextDir =
|
|
14457
|
+
const contextDir = join53(repoRoot, DEFAULT_CONTEXT_FOLDER3);
|
|
14309
14458
|
mkdirSync4(contextDir, { recursive: true });
|
|
14310
14459
|
let downloadedCount = 0;
|
|
14311
14460
|
let failedCount = 0;
|
|
@@ -14319,8 +14468,8 @@ async function sync() {
|
|
|
14319
14468
|
const response = await fetch(presignedUrl);
|
|
14320
14469
|
if (response.ok) {
|
|
14321
14470
|
const content = await response.text();
|
|
14322
|
-
const filePath =
|
|
14323
|
-
mkdirSync4(
|
|
14471
|
+
const filePath = join53(contextDir, file.fileName);
|
|
14472
|
+
mkdirSync4(dirname21(filePath), { recursive: true });
|
|
14324
14473
|
writeFileSync5(filePath, content, "utf-8");
|
|
14325
14474
|
downloadedCount++;
|
|
14326
14475
|
} else {
|
|
@@ -14575,7 +14724,7 @@ async function config() {
|
|
|
14575
14724
|
// src/commands/mcp-log.ts
|
|
14576
14725
|
import { createDecipheriv as createDecipheriv2 } from "crypto";
|
|
14577
14726
|
import { mkdir as mkdir19, readFile as readFile17, stat as stat7, writeFile as writeFile18 } from "fs/promises";
|
|
14578
|
-
import { dirname as
|
|
14727
|
+
import { dirname as dirname22, join as join54 } from "path";
|
|
14579
14728
|
var FLAG_FILE = "mcp-log.flag";
|
|
14580
14729
|
var LOG_FILE = "mcp-log.jsonl.enc";
|
|
14581
14730
|
var KEY_FILE = "mcp-log.key";
|
|
@@ -14583,14 +14732,14 @@ var ENDPOINT_FILE = "listener.endpoint";
|
|
|
14583
14732
|
var IV_BYTES2 = 12;
|
|
14584
14733
|
var TAG_BYTES2 = 16;
|
|
14585
14734
|
function flagPath() {
|
|
14586
|
-
return
|
|
14735
|
+
return join54(getConfigDir2(), FLAG_FILE);
|
|
14587
14736
|
}
|
|
14588
14737
|
function logPath() {
|
|
14589
|
-
return
|
|
14738
|
+
return join54(getConfigDir2(), LOG_FILE);
|
|
14590
14739
|
}
|
|
14591
14740
|
async function writeFlag(flag) {
|
|
14592
14741
|
const path = flagPath();
|
|
14593
|
-
await mkdir19(
|
|
14742
|
+
await mkdir19(dirname22(path), { recursive: true });
|
|
14594
14743
|
await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
|
|
14595
14744
|
}
|
|
14596
14745
|
async function mcpLogOn() {
|
|
@@ -14627,14 +14776,14 @@ async function trySendConsentToServer() {
|
|
|
14627
14776
|
let apiUrl = null;
|
|
14628
14777
|
let token = null;
|
|
14629
14778
|
try {
|
|
14630
|
-
const body = await readFile17(
|
|
14779
|
+
const body = await readFile17(join54(getConfigDir2(), "config.json"), "utf-8");
|
|
14631
14780
|
const parsed = JSON.parse(body);
|
|
14632
14781
|
apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
|
|
14633
14782
|
} catch {
|
|
14634
14783
|
return false;
|
|
14635
14784
|
}
|
|
14636
14785
|
try {
|
|
14637
|
-
const body = await readFile17(
|
|
14786
|
+
const body = await readFile17(join54(getConfigDir2(), "credentials.json"), "utf-8");
|
|
14638
14787
|
const parsed = JSON.parse(body);
|
|
14639
14788
|
token = parsed.idToken ?? null;
|
|
14640
14789
|
} catch {
|
|
@@ -14704,7 +14853,7 @@ async function mcpLogStatus() {
|
|
|
14704
14853
|
process.stderr.write("Log size: no file yet\n");
|
|
14705
14854
|
}
|
|
14706
14855
|
try {
|
|
14707
|
-
const endpointBody = await readFile17(
|
|
14856
|
+
const endpointBody = await readFile17(join54(getConfigDir2(), ENDPOINT_FILE), "utf-8");
|
|
14708
14857
|
const match = /endpoint=([^\n]+)/.exec(endpointBody);
|
|
14709
14858
|
process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
|
|
14710
14859
|
`);
|
|
@@ -14735,7 +14884,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14735
14884
|
const key = await readKey();
|
|
14736
14885
|
if (!key) {
|
|
14737
14886
|
process.stderr.write(
|
|
14738
|
-
`No encryption key at ${
|
|
14887
|
+
`No encryption key at ${join54(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
|
|
14739
14888
|
`
|
|
14740
14889
|
);
|
|
14741
14890
|
return;
|
|
@@ -14811,7 +14960,7 @@ async function mcpLogViewingFlags(flags = {}) {
|
|
|
14811
14960
|
}
|
|
14812
14961
|
async function readKey() {
|
|
14813
14962
|
try {
|
|
14814
|
-
const body = await readFile17(
|
|
14963
|
+
const body = await readFile17(join54(getConfigDir2(), KEY_FILE), "utf-8");
|
|
14815
14964
|
const parsed = Buffer.from(body.trim(), "base64");
|
|
14816
14965
|
if (parsed.length !== 32) return null;
|
|
14817
14966
|
return parsed;
|
|
@@ -14855,7 +15004,7 @@ import chalk14 from "chalk";
|
|
|
14855
15004
|
|
|
14856
15005
|
// src/lib/graph-loader.ts
|
|
14857
15006
|
import { promises as fs24 } from "fs";
|
|
14858
|
-
import { join as
|
|
15007
|
+
import { join as join55, resolve as resolve2 } from "path";
|
|
14859
15008
|
import { gunzipSync } from "zlib";
|
|
14860
15009
|
var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
|
|
14861
15010
|
var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
|
|
@@ -14872,8 +15021,8 @@ var GraphNotFoundError = class extends Error {
|
|
|
14872
15021
|
var cache = /* @__PURE__ */ new Map();
|
|
14873
15022
|
async function loadGraph(repoRoot = process.cwd()) {
|
|
14874
15023
|
const root = resolve2(repoRoot);
|
|
14875
|
-
const gzPath =
|
|
14876
|
-
const plainPath =
|
|
15024
|
+
const gzPath = join55(root, GZIPPED_GRAPH_PATH);
|
|
15025
|
+
const plainPath = join55(root, RELATIVE_GRAPH_PATH);
|
|
14877
15026
|
const cached = cache.get(root);
|
|
14878
15027
|
if (cached) {
|
|
14879
15028
|
return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
|
|
@@ -15288,13 +15437,13 @@ function registerQueryCommand(program2) {
|
|
|
15288
15437
|
|
|
15289
15438
|
// src/commands/uninstall.ts
|
|
15290
15439
|
import { promises as fs28 } from "fs";
|
|
15291
|
-
import { homedir as
|
|
15292
|
-
import { join as
|
|
15440
|
+
import { homedir as homedir10 } from "os";
|
|
15441
|
+
import { join as join59 } from "path";
|
|
15293
15442
|
import chalk15 from "chalk";
|
|
15294
15443
|
|
|
15295
15444
|
// src/lib/cleanup/marker-blocks.ts
|
|
15296
15445
|
import { promises as fs25 } from "fs";
|
|
15297
|
-
import { join as
|
|
15446
|
+
import { join as join56 } from "path";
|
|
15298
15447
|
var MARKER_START = "<!-- repowise-start -->";
|
|
15299
15448
|
var MARKER_END = "<!-- repowise-end -->";
|
|
15300
15449
|
var CONTEXT_FILES = [
|
|
@@ -15334,7 +15483,7 @@ async function stripMarkerBlock(filePath) {
|
|
|
15334
15483
|
async function stripAllMarkerBlocks(repoRoot) {
|
|
15335
15484
|
const out = [];
|
|
15336
15485
|
for (const relative of CONTEXT_FILES) {
|
|
15337
|
-
const full =
|
|
15486
|
+
const full = join56(repoRoot, relative);
|
|
15338
15487
|
const result = await stripMarkerBlock(full).catch((err) => ({
|
|
15339
15488
|
path: full,
|
|
15340
15489
|
status: "untouched",
|
|
@@ -15347,18 +15496,18 @@ async function stripAllMarkerBlocks(repoRoot) {
|
|
|
15347
15496
|
|
|
15348
15497
|
// src/lib/cleanup/mcp-configs.ts
|
|
15349
15498
|
import { promises as fs26 } from "fs";
|
|
15350
|
-
import { join as
|
|
15499
|
+
import { join as join57 } from "path";
|
|
15351
15500
|
function mcpConfigPaths(repoRoot, home) {
|
|
15352
15501
|
return [
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15502
|
+
join57(repoRoot, ".mcp.json"),
|
|
15503
|
+
join57(repoRoot, ".cursor", "mcp.json"),
|
|
15504
|
+
join57(repoRoot, ".vscode", "mcp.json"),
|
|
15505
|
+
join57(repoRoot, ".roo", "mcp.json"),
|
|
15506
|
+
join57(home, ".cline", "mcp.json"),
|
|
15507
|
+
join57(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
15508
|
+
join57(home, ".gemini", "settings.json"),
|
|
15509
|
+
join57(home, ".codex", "mcp.json"),
|
|
15510
|
+
join57(home, ".roo", "mcp.json")
|
|
15362
15511
|
];
|
|
15363
15512
|
}
|
|
15364
15513
|
async function removeRepowiseFromConfig(path, serverName) {
|
|
@@ -15398,11 +15547,11 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
|
|
|
15398
15547
|
|
|
15399
15548
|
// src/lib/cleanup/local-state.ts
|
|
15400
15549
|
import { promises as fs27 } from "fs";
|
|
15401
|
-
import { homedir as
|
|
15402
|
-
import { join as
|
|
15550
|
+
import { homedir as homedir9 } from "os";
|
|
15551
|
+
import { join as join58, resolve as resolve3 } from "path";
|
|
15403
15552
|
async function clearLocalState(homeOverride) {
|
|
15404
|
-
const home = homeOverride ??
|
|
15405
|
-
const target = resolve3(
|
|
15553
|
+
const home = homeOverride ?? homedir9();
|
|
15554
|
+
const target = resolve3(join58(home, ".repowise"));
|
|
15406
15555
|
if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
|
|
15407
15556
|
return { path: target, status: "error", error: "refused: not under home" };
|
|
15408
15557
|
}
|
|
@@ -15437,7 +15586,7 @@ async function stopAndUninstallService(uninstaller) {
|
|
|
15437
15586
|
// src/commands/uninstall.ts
|
|
15438
15587
|
async function uninstall2(opts = {}) {
|
|
15439
15588
|
const tier = opts.tier ?? "uninstall";
|
|
15440
|
-
const home = opts.home ??
|
|
15589
|
+
const home = opts.home ?? homedir10();
|
|
15441
15590
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
15442
15591
|
const loadRepoIds = opts.loadRepoIds ?? defaultLoadRepoIds;
|
|
15443
15592
|
const report = { tier, removed: [], preserved: [], skipped: [] };
|
|
@@ -15446,7 +15595,7 @@ async function uninstall2(opts = {}) {
|
|
|
15446
15595
|
else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
|
|
15447
15596
|
if (tier === "stop") return report;
|
|
15448
15597
|
try {
|
|
15449
|
-
await fs28.unlink(
|
|
15598
|
+
await fs28.unlink(join59(home, ".repowise", "credentials.json"));
|
|
15450
15599
|
report.removed.push("credentials");
|
|
15451
15600
|
} catch (err) {
|
|
15452
15601
|
if (err.code !== "ENOENT") {
|
|
@@ -15485,7 +15634,7 @@ async function uninstall2(opts = {}) {
|
|
|
15485
15634
|
}
|
|
15486
15635
|
async function defaultLoadRepoIds(home) {
|
|
15487
15636
|
try {
|
|
15488
|
-
const raw = await fs28.readFile(
|
|
15637
|
+
const raw = await fs28.readFile(join59(home, ".repowise", "config.json"), "utf-8");
|
|
15489
15638
|
const parsed = JSON.parse(raw);
|
|
15490
15639
|
return (parsed.repos ?? []).map((r) => r.repoId);
|
|
15491
15640
|
} catch {
|
|
@@ -15534,10 +15683,10 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
|
|
|
15534
15683
|
init_config_dir();
|
|
15535
15684
|
import { promises as fs29 } from "fs";
|
|
15536
15685
|
import { createInterface as createInterface2 } from "readline";
|
|
15537
|
-
import { join as
|
|
15686
|
+
import { join as join60 } from "path";
|
|
15538
15687
|
var DEFAULT_MAX = 200 * 1024;
|
|
15539
15688
|
async function mcpShim(opts) {
|
|
15540
|
-
const endpointPath = opts.endpointFile ??
|
|
15689
|
+
const endpointPath = opts.endpointFile ?? join60(getConfigDir(), "listener.endpoint");
|
|
15541
15690
|
const stdin = opts.stdin ?? process.stdin;
|
|
15542
15691
|
const stdout = opts.stdout ?? process.stdout;
|
|
15543
15692
|
const stderr = opts.stderr ?? process.stderr;
|
|
@@ -16285,8 +16434,8 @@ async function lspOn() {
|
|
|
16285
16434
|
|
|
16286
16435
|
// bin/repowise.ts
|
|
16287
16436
|
var __filename = fileURLToPath4(import.meta.url);
|
|
16288
|
-
var __dirname =
|
|
16289
|
-
var pkg = JSON.parse(readFileSync3(
|
|
16437
|
+
var __dirname = dirname23(__filename);
|
|
16438
|
+
var pkg = JSON.parse(readFileSync3(join61(__dirname, "..", "..", "package.json"), "utf-8"));
|
|
16290
16439
|
var program = new Command();
|
|
16291
16440
|
program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
|
|
16292
16441
|
await showWelcome(pkg.version);
|