repowisestage 0.0.40 → 0.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin/repowise.js +1178 -549
  2. package/package.json +1 -1
@@ -456,404 +456,6 @@ var init_service_installer = __esm({
456
456
  }
457
457
  });
458
458
 
459
- // ../../packages/shared/src/types/typed-resolution.ts
460
- function typedResolutionKey(filePath, propertyName, line, column) {
461
- return `${filePath}\0${propertyName}\0${line.toString()}\0${column.toString()}`;
462
- }
463
- var TYPED_RESOLUTION_SCHEMA_VERSION;
464
- var init_typed_resolution = __esm({
465
- "../../packages/shared/src/types/typed-resolution.ts"() {
466
- "use strict";
467
- TYPED_RESOLUTION_SCHEMA_VERSION = 1;
468
- }
469
- });
470
-
471
- // ../../packages/shared/src/types/billing.ts
472
- var init_billing = __esm({
473
- "../../packages/shared/src/types/billing.ts"() {
474
- "use strict";
475
- }
476
- });
477
-
478
- // ../../packages/shared/src/constants/platforms.ts
479
- var init_platforms = __esm({
480
- "../../packages/shared/src/constants/platforms.ts"() {
481
- "use strict";
482
- }
483
- });
484
-
485
- // ../../packages/shared/src/constants/tiers.ts
486
- var SUBSCRIPTION_TIERS, TIER_LIMITS;
487
- var init_tiers = __esm({
488
- "../../packages/shared/src/constants/tiers.ts"() {
489
- "use strict";
490
- SUBSCRIPTION_TIERS = {
491
- STARTER: "starter",
492
- PRO: "pro",
493
- TEAM: "team"
494
- };
495
- TIER_LIMITS = {
496
- [SUBSCRIPTION_TIERS.STARTER]: {
497
- maxRepos: 1,
498
- maxSeats: 1,
499
- maxSyncsPerMonth: 10,
500
- maxConcurrentSyncs: 1,
501
- bedrockEndpoint: "public"
502
- },
503
- [SUBSCRIPTION_TIERS.PRO]: {
504
- maxRepos: 2,
505
- maxSeats: 1,
506
- maxSyncsPerMonth: 30,
507
- maxConcurrentSyncs: 2,
508
- bedrockEndpoint: "public"
509
- },
510
- [SUBSCRIPTION_TIERS.TEAM]: {
511
- maxRepos: 3,
512
- maxSeats: 999999,
513
- maxSyncsPerMonth: 30,
514
- maxConcurrentSyncs: 10,
515
- bedrockEndpoint: "public"
516
- }
517
- };
518
- }
519
- });
520
-
521
- // ../../packages/shared/src/constants/roles.ts
522
- function hasPermission(role, permission) {
523
- return PERMISSIONS[role][permission];
524
- }
525
- function resolveRole(groups) {
526
- for (const role of ROLE_PRIORITY) {
527
- if (groups.includes(role)) return role;
528
- }
529
- return ROLES.MEMBER;
530
- }
531
- var ROLES, PERMISSIONS, ROLE_PRIORITY;
532
- var init_roles = __esm({
533
- "../../packages/shared/src/constants/roles.ts"() {
534
- "use strict";
535
- ROLES = {
536
- OWNER: "owner",
537
- ADMIN: "admin",
538
- REPO_MANAGER: "repo_manager",
539
- MEMBER: "member"
540
- };
541
- PERMISSIONS = {
542
- [ROLES.OWNER]: {
543
- connectRepos: true,
544
- viewSync: true,
545
- triggerRetry: true,
546
- configWatcher: true,
547
- inviteMembers: true,
548
- manageBilling: true,
549
- configAiTools: true,
550
- manageTeam: true
551
- },
552
- [ROLES.ADMIN]: {
553
- connectRepos: true,
554
- viewSync: true,
555
- triggerRetry: true,
556
- configWatcher: true,
557
- inviteMembers: true,
558
- manageBilling: false,
559
- configAiTools: true,
560
- manageTeam: true
561
- },
562
- [ROLES.REPO_MANAGER]: {
563
- connectRepos: true,
564
- viewSync: true,
565
- triggerRetry: true,
566
- configWatcher: true,
567
- inviteMembers: false,
568
- manageBilling: false,
569
- configAiTools: true,
570
- manageTeam: false
571
- },
572
- [ROLES.MEMBER]: {
573
- connectRepos: false,
574
- viewSync: true,
575
- triggerRetry: true,
576
- configWatcher: false,
577
- inviteMembers: false,
578
- manageBilling: false,
579
- configAiTools: true,
580
- manageTeam: false
581
- }
582
- };
583
- ROLE_PRIORITY = [
584
- ROLES.OWNER,
585
- ROLES.ADMIN,
586
- ROLES.REPO_MANAGER,
587
- ROLES.MEMBER
588
- ];
589
- }
590
- });
591
-
592
- // ../../packages/shared/src/index.ts
593
- var init_src = __esm({
594
- "../../packages/shared/src/index.ts"() {
595
- "use strict";
596
- init_typed_resolution();
597
- init_billing();
598
- init_platforms();
599
- init_tiers();
600
- init_roles();
601
- }
602
- });
603
-
604
- // ../listener/dist/typed-resolution/sidecar-cache.js
605
- var sidecar_cache_exports = {};
606
- __export(sidecar_cache_exports, {
607
- loadMergedSidecar: () => loadMergedSidecar,
608
- persistMergedSidecar: () => persistMergedSidecar,
609
- sidecarCachePaths: () => sidecarCachePaths
610
- });
611
- import { mkdir as mkdir8, readFile as readFile7, readdir as readdir3, stat as stat2, unlink as unlink7, writeFile as writeFile8 } from "fs/promises";
612
- import { dirname as dirname5, join as join14 } from "path";
613
- function repoIdSafe(repoId) {
614
- return /^[A-Za-z0-9_.-]{1,128}$/.test(repoId) && !repoId.startsWith(".");
615
- }
616
- function commitShaSafe(commitSha) {
617
- return /^[a-f0-9]{7,64}$/.test(commitSha);
618
- }
619
- function sidecarCachePaths(repoId, commitSha) {
620
- if (!repoIdSafe(repoId)) {
621
- throw new Error(`unsafe repoId: ${repoId}`);
622
- }
623
- if (!commitShaSafe(commitSha)) {
624
- throw new Error(`unsafe commitSha: ${commitSha}`);
625
- }
626
- const repoDir = join14(getConfigDir(), "typed-resolution", repoId);
627
- const fullPath = join14(repoDir, `${commitSha}.jsonl`);
628
- return { fullPath, repoDir };
629
- }
630
- async function persistMergedSidecar(repoId, commitSha, sidecar) {
631
- const { fullPath, repoDir } = sidecarCachePaths(repoId, commitSha);
632
- await mkdir8(repoDir, { recursive: true });
633
- const tmpPath = `${fullPath}.tmp`;
634
- await writeFile8(tmpPath, JSON.stringify(sidecar), "utf-8");
635
- const { rename: rename5 } = await import("fs/promises");
636
- await rename5(tmpPath, fullPath);
637
- try {
638
- await sweepSidecarDir(repoDir);
639
- } catch {
640
- }
641
- }
642
- async function sweepSidecarDir(repoDir) {
643
- const entries = await readdir3(repoDir);
644
- const jsonlFiles = entries.filter((e) => e.endsWith(".jsonl"));
645
- if (jsonlFiles.length <= SWEEP_KEEP_MIN)
646
- return;
647
- const withMtime = [];
648
- for (const name of jsonlFiles) {
649
- try {
650
- const s = await stat2(join14(repoDir, name));
651
- withMtime.push({ name, mtimeMs: s.mtimeMs });
652
- } catch {
653
- }
654
- }
655
- withMtime.sort((a, b) => b.mtimeMs - a.mtimeMs);
656
- const now = Date.now();
657
- const candidates = withMtime.slice(SWEEP_KEEP_MIN);
658
- for (const { name, mtimeMs } of candidates) {
659
- if (now - mtimeMs >= SWEEP_MAX_AGE_MS) {
660
- try {
661
- await unlink7(join14(repoDir, name));
662
- } catch {
663
- }
664
- }
665
- }
666
- }
667
- function isValidSidecarEntry(e) {
668
- if (!e || typeof e !== "object")
669
- return false;
670
- const r = e;
671
- if (typeof r["filePath"] !== "string")
672
- return false;
673
- if (typeof r["propertyName"] !== "string")
674
- return false;
675
- if (typeof r["line"] !== "number" || !Number.isInteger(r["line"]))
676
- return false;
677
- if (typeof r["column"] !== "number" || !Number.isInteger(r["column"]))
678
- return false;
679
- if (typeof r["confidence"] !== "number")
680
- return false;
681
- return true;
682
- }
683
- async function loadMergedSidecar(repoId, commitSha) {
684
- let body;
685
- try {
686
- const { fullPath } = sidecarCachePaths(repoId, commitSha);
687
- body = await readFile7(fullPath, "utf-8");
688
- } catch {
689
- return null;
690
- }
691
- try {
692
- const parsed = JSON.parse(body);
693
- if (parsed.schemaVersion !== TYPED_RESOLUTION_SCHEMA_VERSION)
694
- return null;
695
- if (!Array.isArray(parsed.resolutions))
696
- return null;
697
- const all = parsed.resolutions;
698
- const valid = all.filter(isValidSidecarEntry);
699
- if (valid.length === 0 && all.length > 0)
700
- return null;
701
- if (valid.length < all.length * 0.5)
702
- return null;
703
- return { ...parsed, resolutions: valid };
704
- } catch {
705
- return null;
706
- }
707
- }
708
- var SWEEP_MAX_AGE_MS, SWEEP_KEEP_MIN;
709
- var init_sidecar_cache = __esm({
710
- "../listener/dist/typed-resolution/sidecar-cache.js"() {
711
- "use strict";
712
- init_config_dir();
713
- init_src();
714
- SWEEP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
715
- SWEEP_KEEP_MIN = 5;
716
- }
717
- });
718
-
719
- // ../listener/dist/typed-resolution/sidecar-client.js
720
- var sidecar_client_exports = {};
721
- __export(sidecar_client_exports, {
722
- buildSidecar: () => buildSidecar,
723
- buildSidecarIndex: () => buildSidecarIndex,
724
- downloadMergedSidecar: () => downloadMergedSidecar,
725
- overlayMergedSidecar: () => overlayMergedSidecar,
726
- uploadSidecar: () => uploadSidecar
727
- });
728
- async function uploadSidecar(req, fetchImpl = fetch) {
729
- const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution`;
730
- const body = JSON.stringify({ ...req.sidecar, commitSha: req.commitSha });
731
- const byteLength = Buffer.byteLength(body, "utf8");
732
- if (byteLength > UPLOAD_BODY_BYTE_LIMIT) {
733
- const msg = `sidecar body too large to upload (${byteLength.toString()} bytes > ${UPLOAD_BODY_BYTE_LIMIT.toString()} byte cap); skipping`;
734
- console.warn(`[typed-resolution] ${msg}`);
735
- return {
736
- uploaded: false,
737
- resolutionCount: req.sidecar.resolutions.length,
738
- uploadKey: "",
739
- error: msg
740
- };
741
- }
742
- const res = await fetchImpl(url, {
743
- method: "POST",
744
- headers: {
745
- "content-type": "application/json",
746
- authorization: `Bearer ${req.authToken}`
747
- },
748
- body
749
- });
750
- if (!res.ok) {
751
- const text = await res.text().catch(() => "");
752
- throw new Error(`upload failed: HTTP ${res.status.toString()} ${text}`);
753
- }
754
- const payload = await res.json();
755
- if (!payload.data)
756
- throw new Error("upload response missing `data`");
757
- return payload.data;
758
- }
759
- async function downloadMergedSidecar(req, fetchImpl = fetch) {
760
- const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution/${encodeURIComponent(req.commitSha)}`;
761
- const res = await fetchImpl(url, {
762
- method: "GET",
763
- headers: { authorization: `Bearer ${req.authToken}` }
764
- });
765
- if (res.status === 404)
766
- return null;
767
- if (!res.ok) {
768
- throw new Error(`download failed: HTTP ${res.status.toString()}`);
769
- }
770
- const body = await res.json();
771
- if (body.schemaVersion !== TYPED_RESOLUTION_SCHEMA_VERSION)
772
- return null;
773
- if (!Array.isArray(body.resolutions))
774
- return null;
775
- return body;
776
- }
777
- function buildSidecarIndex(sidecar) {
778
- const map = /* @__PURE__ */ new Map();
779
- if (!sidecar)
780
- return map;
781
- for (const r of sidecar.resolutions) {
782
- map.set(typedResolutionKey(r.filePath, r.propertyName, r.line, r.column), r);
783
- }
784
- return map;
785
- }
786
- function overlayMergedSidecar(edges, sidecar) {
787
- let edgesUpgraded = 0;
788
- let edgesUnchanged = 0;
789
- const index = buildSidecarIndex(sidecar);
790
- for (const edge of edges) {
791
- if (!edge.filePath || !edge.propertyName || !edge.location || edge.resolution === "typed") {
792
- edgesUnchanged += 1;
793
- continue;
794
- }
795
- const key = typedResolutionKey(edge.filePath, edge.propertyName, edge.location.line, edge.location.column);
796
- const hit = index.get(key);
797
- if (!hit || hit.targetSymbolId === null) {
798
- edgesUnchanged += 1;
799
- continue;
800
- }
801
- edge.to = hit.targetSymbolId;
802
- edge.resolution = "typed";
803
- edge.confidence = hit.confidence;
804
- edgesUpgraded += 1;
805
- }
806
- return { edgesUpgraded, edgesUnchanged };
807
- }
808
- async function buildSidecar(req) {
809
- const groupKeyFn = req.groupKey ?? (() => "default");
810
- const groups = /* @__PURE__ */ new Map();
811
- req.receivers.forEach((receiver, index) => {
812
- const key = groupKeyFn(receiver) ?? "__default__";
813
- let bucket = groups.get(key);
814
- if (!bucket) {
815
- bucket = [];
816
- groups.set(key, bucket);
817
- }
818
- bucket.push({ index, receiver });
819
- });
820
- const resolutions = new Array(req.receivers.length);
821
- await Promise.all(Array.from(groups.values()).map(async (bucket) => {
822
- for (const { index, receiver } of bucket) {
823
- let targetSymbolId;
824
- try {
825
- targetSymbolId = await req.resolve(receiver);
826
- } catch (err) {
827
- console.warn(`[typed-resolution] resolve failed for ${receiver.filePath}:${receiver.line.toString()}:${receiver.column.toString()} property=${receiver.propertyName} errMsg=${err instanceof Error ? err.message : String(err)}`);
828
- targetSymbolId = null;
829
- }
830
- resolutions[index] = {
831
- filePath: receiver.filePath,
832
- propertyName: receiver.propertyName,
833
- line: receiver.line,
834
- column: receiver.column,
835
- targetSymbolId,
836
- confidence: 0.9
837
- };
838
- }
839
- }));
840
- return {
841
- schemaVersion: TYPED_RESOLUTION_SCHEMA_VERSION,
842
- producer: req.producer,
843
- emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
844
- languages: [...req.languages],
845
- resolutions
846
- };
847
- }
848
- var UPLOAD_BODY_BYTE_LIMIT;
849
- var init_sidecar_client = __esm({
850
- "../listener/dist/typed-resolution/sidecar-client.js"() {
851
- "use strict";
852
- init_src();
853
- UPLOAD_BODY_BYTE_LIMIT = 8 * 1024 * 1024;
854
- }
855
- });
856
-
857
459
  // ../listener/dist/lsp/registry.js
858
460
  function detectLanguage(path) {
859
461
  const dot = path.lastIndexOf(".");
@@ -895,7 +497,8 @@ var init_registry = __esm({
895
497
  args: ["--stdio"],
896
498
  extensions: [".ts", ".tsx", ".mts", ".cts"],
897
499
  lspLanguageId: "typescript",
898
- installHint: "npm i -g typescript typescript-language-server"
500
+ installHint: "npm i -g typescript typescript-language-server",
501
+ npmPackage: "typescript-language-server"
899
502
  }
900
503
  ],
901
504
  javascript: [
@@ -906,7 +509,8 @@ var init_registry = __esm({
906
509
  args: ["--stdio"],
907
510
  extensions: [".js", ".jsx", ".mjs", ".cjs"],
908
511
  lspLanguageId: "javascript",
909
- installHint: "npm i -g typescript typescript-language-server"
512
+ installHint: "npm i -g typescript typescript-language-server",
513
+ npmPackage: "typescript-language-server"
910
514
  }
911
515
  ],
912
516
  python: [
@@ -917,7 +521,8 @@ var init_registry = __esm({
917
521
  args: ["--stdio"],
918
522
  extensions: [".py", ".pyi"],
919
523
  lspLanguageId: "python",
920
- installHint: "npm i -g pyright"
524
+ installHint: "npm i -g pyright",
525
+ npmPackage: "pyright"
921
526
  },
922
527
  {
923
528
  id: "pylsp",
@@ -1009,7 +614,8 @@ var init_registry = __esm({
1009
614
  args: ["--stdio"],
1010
615
  extensions: [".php"],
1011
616
  lspLanguageId: "php",
1012
- installHint: "npm i -g intelephense"
617
+ installHint: "npm i -g intelephense",
618
+ npmPackage: "intelephense"
1013
619
  }
1014
620
  ],
1015
621
  ruby: [
@@ -1095,7 +701,8 @@ var init_registry = __esm({
1095
701
  args: ["--stdio"],
1096
702
  extensions: [".vue"],
1097
703
  lspLanguageId: "vue",
1098
- installHint: "npm i -g @vue/language-server"
704
+ installHint: "npm i -g @vue/language-server",
705
+ npmPackage: "@vue/language-server"
1099
706
  }
1100
707
  ],
1101
708
  svelte: [
@@ -1106,13 +713,412 @@ var init_registry = __esm({
1106
713
  args: ["--stdio"],
1107
714
  extensions: [".svelte"],
1108
715
  lspLanguageId: "svelte",
1109
- installHint: "npm i -g svelte-language-server"
716
+ installHint: "npm i -g svelte-language-server",
717
+ npmPackage: "svelte-language-server"
1110
718
  }
1111
719
  ]
1112
720
  };
1113
721
  }
1114
722
  });
1115
723
 
724
+ // ../../packages/shared/src/types/typed-resolution.ts
725
+ function typedResolutionKey(filePath, propertyName, line, column) {
726
+ return `${filePath}\0${propertyName}\0${line.toString()}\0${column.toString()}`;
727
+ }
728
+ var TYPED_RESOLUTION_SCHEMA_VERSION;
729
+ var init_typed_resolution = __esm({
730
+ "../../packages/shared/src/types/typed-resolution.ts"() {
731
+ "use strict";
732
+ TYPED_RESOLUTION_SCHEMA_VERSION = 1;
733
+ }
734
+ });
735
+
736
+ // ../../packages/shared/src/types/billing.ts
737
+ var init_billing = __esm({
738
+ "../../packages/shared/src/types/billing.ts"() {
739
+ "use strict";
740
+ }
741
+ });
742
+
743
+ // ../../packages/shared/src/constants/platforms.ts
744
+ var init_platforms = __esm({
745
+ "../../packages/shared/src/constants/platforms.ts"() {
746
+ "use strict";
747
+ }
748
+ });
749
+
750
+ // ../../packages/shared/src/constants/tiers.ts
751
+ var SUBSCRIPTION_TIERS, TIER_LIMITS;
752
+ var init_tiers = __esm({
753
+ "../../packages/shared/src/constants/tiers.ts"() {
754
+ "use strict";
755
+ SUBSCRIPTION_TIERS = {
756
+ STARTER: "starter",
757
+ PRO: "pro",
758
+ TEAM: "team"
759
+ };
760
+ TIER_LIMITS = {
761
+ [SUBSCRIPTION_TIERS.STARTER]: {
762
+ maxRepos: 1,
763
+ maxSeats: 1,
764
+ maxSyncsPerMonth: 10,
765
+ maxConcurrentSyncs: 1,
766
+ bedrockEndpoint: "public"
767
+ },
768
+ [SUBSCRIPTION_TIERS.PRO]: {
769
+ maxRepos: 2,
770
+ maxSeats: 1,
771
+ maxSyncsPerMonth: 30,
772
+ maxConcurrentSyncs: 2,
773
+ bedrockEndpoint: "public"
774
+ },
775
+ [SUBSCRIPTION_TIERS.TEAM]: {
776
+ maxRepos: 3,
777
+ maxSeats: 999999,
778
+ maxSyncsPerMonth: 30,
779
+ maxConcurrentSyncs: 10,
780
+ bedrockEndpoint: "public"
781
+ }
782
+ };
783
+ }
784
+ });
785
+
786
+ // ../../packages/shared/src/constants/roles.ts
787
+ function hasPermission(role, permission) {
788
+ return PERMISSIONS[role][permission];
789
+ }
790
+ function resolveRole(groups) {
791
+ for (const role of ROLE_PRIORITY) {
792
+ if (groups.includes(role)) return role;
793
+ }
794
+ return ROLES.MEMBER;
795
+ }
796
+ var ROLES, PERMISSIONS, ROLE_PRIORITY;
797
+ var init_roles = __esm({
798
+ "../../packages/shared/src/constants/roles.ts"() {
799
+ "use strict";
800
+ ROLES = {
801
+ OWNER: "owner",
802
+ ADMIN: "admin",
803
+ REPO_MANAGER: "repo_manager",
804
+ MEMBER: "member"
805
+ };
806
+ PERMISSIONS = {
807
+ [ROLES.OWNER]: {
808
+ connectRepos: true,
809
+ viewSync: true,
810
+ triggerRetry: true,
811
+ configWatcher: true,
812
+ inviteMembers: true,
813
+ manageBilling: true,
814
+ configAiTools: true,
815
+ manageTeam: true
816
+ },
817
+ [ROLES.ADMIN]: {
818
+ connectRepos: true,
819
+ viewSync: true,
820
+ triggerRetry: true,
821
+ configWatcher: true,
822
+ inviteMembers: true,
823
+ manageBilling: false,
824
+ configAiTools: true,
825
+ manageTeam: true
826
+ },
827
+ [ROLES.REPO_MANAGER]: {
828
+ connectRepos: true,
829
+ viewSync: true,
830
+ triggerRetry: true,
831
+ configWatcher: true,
832
+ inviteMembers: false,
833
+ manageBilling: false,
834
+ configAiTools: true,
835
+ manageTeam: false
836
+ },
837
+ [ROLES.MEMBER]: {
838
+ connectRepos: false,
839
+ viewSync: true,
840
+ triggerRetry: true,
841
+ configWatcher: false,
842
+ inviteMembers: false,
843
+ manageBilling: false,
844
+ configAiTools: true,
845
+ manageTeam: false
846
+ }
847
+ };
848
+ ROLE_PRIORITY = [
849
+ ROLES.OWNER,
850
+ ROLES.ADMIN,
851
+ ROLES.REPO_MANAGER,
852
+ ROLES.MEMBER
853
+ ];
854
+ }
855
+ });
856
+
857
+ // ../../packages/shared/src/index.ts
858
+ var init_src = __esm({
859
+ "../../packages/shared/src/index.ts"() {
860
+ "use strict";
861
+ init_typed_resolution();
862
+ init_billing();
863
+ init_platforms();
864
+ init_tiers();
865
+ init_roles();
866
+ }
867
+ });
868
+
869
+ // ../listener/dist/typed-resolution/sidecar-cache.js
870
+ var sidecar_cache_exports = {};
871
+ __export(sidecar_cache_exports, {
872
+ loadMergedSidecar: () => loadMergedSidecar,
873
+ persistMergedSidecar: () => persistMergedSidecar,
874
+ sidecarCachePaths: () => sidecarCachePaths
875
+ });
876
+ import { mkdir as mkdir8, readFile as readFile7, readdir as readdir3, stat as stat2, unlink as unlink7, writeFile as writeFile8 } from "fs/promises";
877
+ import { dirname as dirname6, join as join15 } from "path";
878
+ function repoIdSafe(repoId) {
879
+ return /^[A-Za-z0-9_.-]{1,128}$/.test(repoId) && !repoId.startsWith(".");
880
+ }
881
+ function commitShaSafe(commitSha) {
882
+ return /^[a-f0-9]{7,64}$/.test(commitSha);
883
+ }
884
+ function sidecarCachePaths(repoId, commitSha) {
885
+ if (!repoIdSafe(repoId)) {
886
+ throw new Error(`unsafe repoId: ${repoId}`);
887
+ }
888
+ if (!commitShaSafe(commitSha)) {
889
+ throw new Error(`unsafe commitSha: ${commitSha}`);
890
+ }
891
+ const repoDir = join15(getConfigDir(), "typed-resolution", repoId);
892
+ const fullPath = join15(repoDir, `${commitSha}.jsonl`);
893
+ return { fullPath, repoDir };
894
+ }
895
+ async function persistMergedSidecar(repoId, commitSha, sidecar) {
896
+ const { fullPath, repoDir } = sidecarCachePaths(repoId, commitSha);
897
+ await mkdir8(repoDir, { recursive: true });
898
+ const tmpPath = `${fullPath}.tmp`;
899
+ await writeFile8(tmpPath, JSON.stringify(sidecar), "utf-8");
900
+ const { rename: rename5 } = await import("fs/promises");
901
+ await rename5(tmpPath, fullPath);
902
+ try {
903
+ await sweepSidecarDir(repoDir);
904
+ } catch {
905
+ }
906
+ }
907
+ async function sweepSidecarDir(repoDir) {
908
+ const entries = await readdir3(repoDir);
909
+ const jsonlFiles = entries.filter((e) => e.endsWith(".jsonl"));
910
+ if (jsonlFiles.length <= SWEEP_KEEP_MIN)
911
+ return;
912
+ const withMtime = [];
913
+ for (const name of jsonlFiles) {
914
+ try {
915
+ const s = await stat2(join15(repoDir, name));
916
+ withMtime.push({ name, mtimeMs: s.mtimeMs });
917
+ } catch {
918
+ }
919
+ }
920
+ withMtime.sort((a, b) => b.mtimeMs - a.mtimeMs);
921
+ const now = Date.now();
922
+ const candidates = withMtime.slice(SWEEP_KEEP_MIN);
923
+ for (const { name, mtimeMs } of candidates) {
924
+ if (now - mtimeMs >= SWEEP_MAX_AGE_MS) {
925
+ try {
926
+ await unlink7(join15(repoDir, name));
927
+ } catch {
928
+ }
929
+ }
930
+ }
931
+ }
932
+ function isValidSidecarEntry(e) {
933
+ if (!e || typeof e !== "object")
934
+ return false;
935
+ const r = e;
936
+ if (typeof r["filePath"] !== "string")
937
+ return false;
938
+ if (typeof r["propertyName"] !== "string")
939
+ return false;
940
+ if (typeof r["line"] !== "number" || !Number.isInteger(r["line"]))
941
+ return false;
942
+ if (typeof r["column"] !== "number" || !Number.isInteger(r["column"]))
943
+ return false;
944
+ if (typeof r["confidence"] !== "number")
945
+ return false;
946
+ return true;
947
+ }
948
+ async function loadMergedSidecar(repoId, commitSha) {
949
+ let body;
950
+ try {
951
+ const { fullPath } = sidecarCachePaths(repoId, commitSha);
952
+ body = await readFile7(fullPath, "utf-8");
953
+ } catch {
954
+ return null;
955
+ }
956
+ try {
957
+ const parsed = JSON.parse(body);
958
+ if (parsed.schemaVersion !== TYPED_RESOLUTION_SCHEMA_VERSION)
959
+ return null;
960
+ if (!Array.isArray(parsed.resolutions))
961
+ return null;
962
+ const all = parsed.resolutions;
963
+ const valid = all.filter(isValidSidecarEntry);
964
+ if (valid.length === 0 && all.length > 0)
965
+ return null;
966
+ if (valid.length < all.length * 0.5)
967
+ return null;
968
+ return { ...parsed, resolutions: valid };
969
+ } catch {
970
+ return null;
971
+ }
972
+ }
973
+ var SWEEP_MAX_AGE_MS, SWEEP_KEEP_MIN;
974
+ var init_sidecar_cache = __esm({
975
+ "../listener/dist/typed-resolution/sidecar-cache.js"() {
976
+ "use strict";
977
+ init_config_dir();
978
+ init_src();
979
+ SWEEP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
980
+ SWEEP_KEEP_MIN = 5;
981
+ }
982
+ });
983
+
984
+ // ../listener/dist/typed-resolution/sidecar-client.js
985
+ var sidecar_client_exports = {};
986
+ __export(sidecar_client_exports, {
987
+ buildSidecar: () => buildSidecar,
988
+ buildSidecarIndex: () => buildSidecarIndex,
989
+ downloadMergedSidecar: () => downloadMergedSidecar,
990
+ overlayMergedSidecar: () => overlayMergedSidecar,
991
+ uploadSidecar: () => uploadSidecar
992
+ });
993
+ async function uploadSidecar(req, fetchImpl = fetch) {
994
+ const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution`;
995
+ const body = JSON.stringify({ ...req.sidecar, commitSha: req.commitSha });
996
+ const byteLength = Buffer.byteLength(body, "utf8");
997
+ if (byteLength > UPLOAD_BODY_BYTE_LIMIT) {
998
+ const msg = `sidecar body too large to upload (${byteLength.toString()} bytes > ${UPLOAD_BODY_BYTE_LIMIT.toString()} byte cap); skipping`;
999
+ console.warn(`[typed-resolution] ${msg}`);
1000
+ return {
1001
+ uploaded: false,
1002
+ resolutionCount: req.sidecar.resolutions.length,
1003
+ uploadKey: "",
1004
+ error: msg
1005
+ };
1006
+ }
1007
+ const res = await fetchImpl(url, {
1008
+ method: "POST",
1009
+ headers: {
1010
+ "content-type": "application/json",
1011
+ authorization: `Bearer ${req.authToken}`
1012
+ },
1013
+ body
1014
+ });
1015
+ if (!res.ok) {
1016
+ const text = await res.text().catch(() => "");
1017
+ throw new Error(`upload failed: HTTP ${res.status.toString()} ${text}`);
1018
+ }
1019
+ const payload = await res.json();
1020
+ if (!payload.data)
1021
+ throw new Error("upload response missing `data`");
1022
+ return payload.data;
1023
+ }
1024
+ async function downloadMergedSidecar(req, fetchImpl = fetch) {
1025
+ const url = `${req.apiUrl.replace(/\/$/, "")}/v1/repos/${encodeURIComponent(req.repoId)}/typed-resolution/${encodeURIComponent(req.commitSha)}`;
1026
+ const res = await fetchImpl(url, {
1027
+ method: "GET",
1028
+ headers: { authorization: `Bearer ${req.authToken}` }
1029
+ });
1030
+ if (res.status === 404)
1031
+ return null;
1032
+ if (!res.ok) {
1033
+ throw new Error(`download failed: HTTP ${res.status.toString()}`);
1034
+ }
1035
+ const body = await res.json();
1036
+ if (body.schemaVersion !== TYPED_RESOLUTION_SCHEMA_VERSION)
1037
+ return null;
1038
+ if (!Array.isArray(body.resolutions))
1039
+ return null;
1040
+ return body;
1041
+ }
1042
+ function buildSidecarIndex(sidecar) {
1043
+ const map = /* @__PURE__ */ new Map();
1044
+ if (!sidecar)
1045
+ return map;
1046
+ for (const r of sidecar.resolutions) {
1047
+ map.set(typedResolutionKey(r.filePath, r.propertyName, r.line, r.column), r);
1048
+ }
1049
+ return map;
1050
+ }
1051
+ function overlayMergedSidecar(edges, sidecar) {
1052
+ let edgesUpgraded = 0;
1053
+ let edgesUnchanged = 0;
1054
+ const index = buildSidecarIndex(sidecar);
1055
+ for (const edge of edges) {
1056
+ if (!edge.filePath || !edge.propertyName || !edge.location || edge.resolution === "typed") {
1057
+ edgesUnchanged += 1;
1058
+ continue;
1059
+ }
1060
+ const key = typedResolutionKey(edge.filePath, edge.propertyName, edge.location.line, edge.location.column);
1061
+ const hit = index.get(key);
1062
+ if (!hit || hit.targetSymbolId === null) {
1063
+ edgesUnchanged += 1;
1064
+ continue;
1065
+ }
1066
+ edge.to = hit.targetSymbolId;
1067
+ edge.resolution = "typed";
1068
+ edge.confidence = hit.confidence;
1069
+ edgesUpgraded += 1;
1070
+ }
1071
+ return { edgesUpgraded, edgesUnchanged };
1072
+ }
1073
+ async function buildSidecar(req) {
1074
+ const groupKeyFn = req.groupKey ?? (() => "default");
1075
+ const groups = /* @__PURE__ */ new Map();
1076
+ req.receivers.forEach((receiver, index) => {
1077
+ const key = groupKeyFn(receiver) ?? "__default__";
1078
+ let bucket = groups.get(key);
1079
+ if (!bucket) {
1080
+ bucket = [];
1081
+ groups.set(key, bucket);
1082
+ }
1083
+ bucket.push({ index, receiver });
1084
+ });
1085
+ const resolutions = new Array(req.receivers.length);
1086
+ await Promise.all(Array.from(groups.values()).map(async (bucket) => {
1087
+ for (const { index, receiver } of bucket) {
1088
+ let targetSymbolId;
1089
+ try {
1090
+ targetSymbolId = await req.resolve(receiver);
1091
+ } catch (err) {
1092
+ console.warn(`[typed-resolution] resolve failed for ${receiver.filePath}:${receiver.line.toString()}:${receiver.column.toString()} property=${receiver.propertyName} errMsg=${err instanceof Error ? err.message : String(err)}`);
1093
+ targetSymbolId = null;
1094
+ }
1095
+ resolutions[index] = {
1096
+ filePath: receiver.filePath,
1097
+ propertyName: receiver.propertyName,
1098
+ line: receiver.line,
1099
+ column: receiver.column,
1100
+ targetSymbolId,
1101
+ confidence: 0.9
1102
+ };
1103
+ }
1104
+ }));
1105
+ return {
1106
+ schemaVersion: TYPED_RESOLUTION_SCHEMA_VERSION,
1107
+ producer: req.producer,
1108
+ emittedAt: (/* @__PURE__ */ new Date()).toISOString(),
1109
+ languages: [...req.languages],
1110
+ resolutions
1111
+ };
1112
+ }
1113
+ var UPLOAD_BODY_BYTE_LIMIT;
1114
+ var init_sidecar_client = __esm({
1115
+ "../listener/dist/typed-resolution/sidecar-client.js"() {
1116
+ "use strict";
1117
+ init_src();
1118
+ UPLOAD_BODY_BYTE_LIMIT = 8 * 1024 * 1024;
1119
+ }
1120
+ });
1121
+
1116
1122
  // ../listener/dist/lsp/lsp-tools.js
1117
1123
  var lsp_tools_exports = {};
1118
1124
  __export(lsp_tools_exports, {
@@ -1466,13 +1472,13 @@ var init_lsp_tools = __esm({
1466
1472
  // bin/repowise.ts
1467
1473
  import { readFileSync as readFileSync3 } from "fs";
1468
1474
  import { fileURLToPath as fileURLToPath4 } from "url";
1469
- import { dirname as dirname16, join as join36 } from "path";
1475
+ import { dirname as dirname18, join as join45 } from "path";
1470
1476
  import { Command } from "commander";
1471
1477
 
1472
1478
  // ../listener/dist/main.js
1473
1479
  init_config_dir();
1474
- import { readFile as readFile12, writeFile as writeFile14, mkdir as mkdir14 } from "fs/promises";
1475
- import { join as join18, dirname as dirname11 } from "path";
1480
+ import { readFile as readFile12, writeFile as writeFile14, mkdir as mkdir14, stat as fsStat } from "fs/promises";
1481
+ import { join as join27, dirname as dirname13 } from "path";
1476
1482
  import { fileURLToPath as fileURLToPath3 } from "url";
1477
1483
  import lockfile3 from "proper-lockfile";
1478
1484
 
@@ -2761,7 +2767,7 @@ async function stopListener() {
2761
2767
 
2762
2768
  // ../listener/dist/mcp/bootstrap.js
2763
2769
  init_config_dir();
2764
- import { join as join17 } from "path";
2770
+ import { join as join18 } from "path";
2765
2771
 
2766
2772
  // ../listener/dist/lsp/workspace-session.js
2767
2773
  import { pathToFileURL } from "url";
@@ -3023,18 +3029,205 @@ var LspClient = class extends EventEmitter {
3023
3029
  this.respondError(reqId, -32601, `method not found: ${method}`);
3024
3030
  return;
3025
3031
  }
3026
- this.emit("request", method, msg["params"], reqId);
3032
+ this.emit("request", method, msg["params"], reqId);
3033
+ }
3034
+ }
3035
+ failAllPending(err) {
3036
+ for (const pending of this.pending.values()) {
3037
+ if (pending.timer)
3038
+ clearTimeout(pending.timer);
3039
+ pending.reject(err);
3040
+ }
3041
+ this.pending.clear();
3042
+ }
3043
+ };
3044
+
3045
+ // ../listener/dist/lsp/installer.js
3046
+ init_config_dir();
3047
+ init_registry();
3048
+ import { promises as fs } from "fs";
3049
+ import { join as join14, dirname as dirname5 } from "path";
3050
+ import { spawn as spawn3 } from "child_process";
3051
+ function getLspInstallDir() {
3052
+ return join14(getConfigDir(), "lsp-servers");
3053
+ }
3054
+ function getLspBinDir() {
3055
+ return join14(getLspInstallDir(), "node_modules", ".bin");
3056
+ }
3057
+ async function ensureNpmLspInstalled(config2) {
3058
+ if (!config2.npmPackage)
3059
+ return { installed: false, skipped: "no-npm-package" };
3060
+ const installDir = getLspInstallDir();
3061
+ const binPath = join14(installDir, "node_modules", ".bin", config2.command);
3062
+ if (await pathExists(binPath)) {
3063
+ return { installed: false, skipped: "already-present" };
3064
+ }
3065
+ try {
3066
+ await fs.mkdir(installDir, { recursive: true });
3067
+ const pkgJsonPath = join14(installDir, "package.json");
3068
+ if (!await pathExists(pkgJsonPath)) {
3069
+ await fs.writeFile(pkgJsonPath, JSON.stringify({ name: "repowise-lsp-servers", private: true, version: "0.0.0" }, null, 2), "utf-8");
3070
+ }
3071
+ await runNpmInstall(installDir, config2.npmPackage);
3072
+ if (!await pathExists(binPath)) {
3073
+ return {
3074
+ installed: false,
3075
+ error: `npm install completed but ${config2.command} still not at ${binPath}`
3076
+ };
3077
+ }
3078
+ return { installed: true };
3079
+ } catch (err) {
3080
+ return {
3081
+ installed: false,
3082
+ error: err instanceof Error ? err.message : String(err)
3083
+ };
3084
+ }
3085
+ }
3086
+ async function resolveNpmCommand() {
3087
+ const nodeDir = dirname5(process.execPath);
3088
+ for (const candidate of [join14(nodeDir, "npm"), join14(nodeDir, "npm.cmd")]) {
3089
+ try {
3090
+ await fs.access(candidate);
3091
+ return candidate;
3092
+ } catch {
3093
+ }
3094
+ }
3095
+ for (const candidate of ["/opt/homebrew/bin/npm", "/usr/local/bin/npm", "/usr/bin/npm"]) {
3096
+ try {
3097
+ await fs.access(candidate);
3098
+ return candidate;
3099
+ } catch {
3100
+ }
3101
+ }
3102
+ return "npm";
3103
+ }
3104
+ async function runNpmInstall(cwd, pkg2) {
3105
+ const npmCmd = await resolveNpmCommand();
3106
+ return new Promise((resolve4, reject) => {
3107
+ const child = spawn3(npmCmd, ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
3108
+ cwd,
3109
+ stdio: ["ignore", "pipe", "pipe"],
3110
+ env: { ...process.env }
3111
+ });
3112
+ let stderr = "";
3113
+ child.stderr.on("data", (chunk) => {
3114
+ stderr += chunk.toString();
3115
+ });
3116
+ child.on("error", (err) => reject(err));
3117
+ child.on("close", (code) => {
3118
+ if (code === 0) {
3119
+ resolve4();
3120
+ } else {
3121
+ reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
3122
+ }
3123
+ });
3124
+ });
3125
+ }
3126
+ function sanitizeNpmStderr(raw) {
3127
+ const truncated = raw.split("\n").slice(0, 3).join(" ").trim();
3128
+ return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
3129
+ }
3130
+ async function pathExists(p) {
3131
+ try {
3132
+ await fs.access(p);
3133
+ return true;
3134
+ } catch {
3135
+ return false;
3136
+ }
3137
+ }
3138
+ async function detectRepoLanguages(repoRoot) {
3139
+ const found = /* @__PURE__ */ new Set();
3140
+ let inspected = 0;
3141
+ const MAX_INSPECT = 200;
3142
+ async function inspect(dir) {
3143
+ if (inspected >= MAX_INSPECT)
3144
+ return;
3145
+ let entries;
3146
+ try {
3147
+ entries = await fs.readdir(dir);
3148
+ } catch {
3149
+ return;
3150
+ }
3151
+ for (const name of entries) {
3152
+ if (inspected >= MAX_INSPECT)
3153
+ return;
3154
+ if (name.startsWith("."))
3155
+ continue;
3156
+ if (name === "node_modules" || name === "dist" || name === "build")
3157
+ continue;
3158
+ const lang = detectLanguage(name);
3159
+ if (lang) {
3160
+ found.add(lang);
3161
+ inspected += 1;
3162
+ }
3027
3163
  }
3028
3164
  }
3029
- failAllPending(err) {
3030
- for (const pending of this.pending.values()) {
3031
- if (pending.timer)
3032
- clearTimeout(pending.timer);
3033
- pending.reject(err);
3165
+ await inspect(repoRoot);
3166
+ let topEntries = [];
3167
+ try {
3168
+ topEntries = await fs.readdir(repoRoot);
3169
+ } catch {
3170
+ return found;
3171
+ }
3172
+ for (const name of topEntries) {
3173
+ if (name.startsWith("."))
3174
+ continue;
3175
+ if (name === "node_modules" || name === "dist" || name === "build")
3176
+ continue;
3177
+ const sub = join14(repoRoot, name);
3178
+ try {
3179
+ const stat7 = await fs.stat(sub);
3180
+ if (stat7.isDirectory())
3181
+ await inspect(sub);
3182
+ } catch {
3034
3183
  }
3035
- this.pending.clear();
3036
3184
  }
3037
- };
3185
+ return found;
3186
+ }
3187
+ async function prepareLspServersForRepos(repos) {
3188
+ const detected = /* @__PURE__ */ new Set();
3189
+ for (const r of repos) {
3190
+ if (!r.localPath)
3191
+ continue;
3192
+ try {
3193
+ const stat7 = await fs.stat(r.localPath);
3194
+ if (!stat7.isDirectory())
3195
+ continue;
3196
+ } catch {
3197
+ continue;
3198
+ }
3199
+ try {
3200
+ const langs = await detectRepoLanguages(r.localPath);
3201
+ for (const l of langs)
3202
+ detected.add(l);
3203
+ } catch {
3204
+ }
3205
+ }
3206
+ const results = [];
3207
+ for (const language of detected) {
3208
+ const configs = LSP_REGISTRY[language];
3209
+ const npmConfig = configs.find((c) => c.npmPackage);
3210
+ if (!npmConfig) {
3211
+ results.push({
3212
+ language,
3213
+ installed: false,
3214
+ alreadyPresent: false,
3215
+ skippedNoNpmPackage: true,
3216
+ hint: configs[0]?.installHint
3217
+ });
3218
+ continue;
3219
+ }
3220
+ const outcome = await ensureNpmLspInstalled(npmConfig);
3221
+ results.push({
3222
+ language,
3223
+ installed: outcome.installed,
3224
+ alreadyPresent: outcome.skipped === "already-present",
3225
+ skippedNoNpmPackage: false,
3226
+ error: outcome.error
3227
+ });
3228
+ }
3229
+ return results;
3230
+ }
3038
3231
 
3039
3232
  // ../listener/dist/lsp/workspace-session.js
3040
3233
  function keyOf(args) {
@@ -3050,10 +3243,14 @@ var WorkspaceManager = class {
3050
3243
  this.idleTimeoutMs = opts.idleTimeoutMs ?? 10 * 60 * 1e3;
3051
3244
  this.maxSessions = opts.maxSessions ?? 32;
3052
3245
  this.clientFactory = opts.clientFactory ?? ((config2, cwd) => {
3246
+ const env = { ...process.env };
3247
+ const lspBin = getLspBinDir();
3248
+ env.PATH = env.PATH ? `${env.PATH}:${lspBin}` : lspBin;
3053
3249
  const client = new LspClient({
3054
3250
  command: config2.command,
3055
3251
  args: config2.args,
3056
- cwd
3252
+ cwd,
3253
+ env
3057
3254
  });
3058
3255
  client.on("stderr", (line) => {
3059
3256
  process.stderr.write(`[lsp:${config2.id}] ${line}`);
@@ -3381,7 +3578,7 @@ var PathEscapeError = class extends Error {
3381
3578
  // ../listener/dist/mcp/graph-cache.js
3382
3579
  init_config_dir();
3383
3580
  import { readFile as readFile8, stat as stat3 } from "fs/promises";
3384
- import { join as join15 } from "path";
3581
+ import { join as join16 } from "path";
3385
3582
  var EVICT_DEBOUNCE_MS = 6e4;
3386
3583
  function assertSafeRepoId(repoId) {
3387
3584
  if (!repoId || typeof repoId !== "string") {
@@ -3396,7 +3593,7 @@ function assertSafeRepoId(repoId) {
3396
3593
  }
3397
3594
  function createGraphCache(options = {}) {
3398
3595
  const evictMs = options.evictDebounceMs ?? EVICT_DEBOUNCE_MS;
3399
- const resolvePath = options.resolveGraphPath ?? ((repoId) => join15(defaultRepoWiseHome(), "graphs", `${repoId}.json`));
3596
+ const resolvePath = options.resolveGraphPath ?? ((repoId) => join16(defaultRepoWiseHome(), "graphs", `${repoId}.json`));
3400
3597
  const entries = /* @__PURE__ */ new Map();
3401
3598
  const inFlight = /* @__PURE__ */ new Map();
3402
3599
  async function loadFromDisk(repoId) {
@@ -3490,7 +3687,7 @@ function defaultRepoWiseHome() {
3490
3687
 
3491
3688
  // ../listener/dist/mcp/graph-downloader.js
3492
3689
  import { mkdir as mkdir9, rename as rename3, writeFile as writeFile9 } from "fs/promises";
3493
- import { dirname as dirname6 } from "path";
3690
+ import { dirname as dirname7 } from "path";
3494
3691
  function createGraphDownloader(options) {
3495
3692
  const fetchFn = options.fetchImpl ?? fetch;
3496
3693
  let lastSha = null;
@@ -3541,7 +3738,7 @@ function createGraphDownloader(options) {
3541
3738
  message: `graph parse: ${err instanceof Error ? err.message : String(err)}`
3542
3739
  };
3543
3740
  }
3544
- await mkdir9(dirname6(options.targetPath), { recursive: true });
3741
+ await mkdir9(dirname7(options.targetPath), { recursive: true });
3545
3742
  const tmpPath = `${options.targetPath}.${Date.now()}.tmp`;
3546
3743
  await writeFile9(tmpPath, body, { encoding: "utf-8", mode: 384 });
3547
3744
  await rename3(tmpPath, options.targetPath);
@@ -3567,7 +3764,7 @@ function createGraphDownloader(options) {
3567
3764
  // ../listener/dist/mcp/log-encryption.js
3568
3765
  import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
3569
3766
  import { mkdir as mkdir10, readFile as readFile9, stat as stat4, writeFile as writeFile10 } from "fs/promises";
3570
- import { dirname as dirname7 } from "path";
3767
+ import { dirname as dirname8 } from "path";
3571
3768
  var KEY_BYTES = 32;
3572
3769
  var IV_BYTES = 12;
3573
3770
  var TAG_BYTES = 16;
@@ -3614,7 +3811,7 @@ function createFileKeyStore(keyPath) {
3614
3811
  return parsed;
3615
3812
  }
3616
3813
  const fresh = randomBytes(KEY_BYTES);
3617
- await mkdir10(dirname7(keyPath), { recursive: true });
3814
+ await mkdir10(dirname8(keyPath), { recursive: true });
3618
3815
  const tmp = `${keyPath}.tmp`;
3619
3816
  await writeFile10(tmp, fresh.toString("base64") + "\n", {
3620
3817
  encoding: "utf-8",
@@ -3656,7 +3853,7 @@ function decryptLine(encoded, key) {
3656
3853
 
3657
3854
  // ../listener/dist/mcp/mcp-logger.js
3658
3855
  import { appendFile, mkdir as mkdir11, stat as stat5, unlink as unlink8, writeFile as writeFile11, readFile as readFile10 } from "fs/promises";
3659
- import { dirname as dirname8 } from "path";
3856
+ import { dirname as dirname9 } from "path";
3660
3857
  var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
3661
3858
  function createMcpLogger(options) {
3662
3859
  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
@@ -3679,7 +3876,7 @@ function createMcpLogger(options) {
3679
3876
  await migrateLegacyPlaintext();
3680
3877
  const key = await options.keyStore.getKey();
3681
3878
  const encoded = encryptLine(JSON.stringify(entry), key) + "\n";
3682
- await mkdir11(dirname8(options.filePath), { recursive: true });
3879
+ await mkdir11(dirname9(options.filePath), { recursive: true });
3683
3880
  await appendFile(options.filePath, encoded, { encoding: "utf-8", mode: 384 });
3684
3881
  try {
3685
3882
  const s = await stat5(options.filePath);
@@ -3713,7 +3910,7 @@ async function rotate(path, size) {
3713
3910
  // ../listener/dist/mcp/mcp-log-uploader.js
3714
3911
  import { randomUUID } from "crypto";
3715
3912
  import { readFile as readFile11, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
3716
- import { dirname as dirname9 } from "path";
3913
+ import { dirname as dirname10 } from "path";
3717
3914
  var DEFAULT_MAX_ENTRIES = 5e3;
3718
3915
  var DEFAULT_MAX_BYTES2 = 1 * 1024 * 1024;
3719
3916
  function createMcpLogUploader(options) {
@@ -3863,7 +4060,7 @@ async function readPendingBatch(watermarkPath) {
3863
4060
  }
3864
4061
  }
3865
4062
  async function writePendingBatch(watermarkPath, batchId) {
3866
- await mkdir12(dirname9(watermarkPath), { recursive: true });
4063
+ await mkdir12(dirname10(watermarkPath), { recursive: true });
3867
4064
  await writeFile12(pendingPath(watermarkPath), batchId, { encoding: "utf-8", mode: 384 });
3868
4065
  }
3869
4066
  async function clearPendingBatch(watermarkPath) {
@@ -3885,7 +4082,7 @@ async function readWatermark(path) {
3885
4082
  }
3886
4083
  }
3887
4084
  async function writeWatermark(path, offset) {
3888
- await mkdir12(dirname9(path), { recursive: true });
4085
+ await mkdir12(dirname10(path), { recursive: true });
3889
4086
  const tmp = `${path}.tmp`;
3890
4087
  await writeFile12(tmp, offset.toString() + "\n", { encoding: "utf-8", mode: 384 });
3891
4088
  const { rename: rename5 } = await import("fs/promises");
@@ -3905,7 +4102,7 @@ async function isLocallyConsented(flagPath2) {
3905
4102
  init_config_dir();
3906
4103
  import { createServer } from "http";
3907
4104
  import { mkdir as mkdir13, writeFile as writeFile13 } from "fs/promises";
3908
- import { dirname as dirname10, join as join16 } from "path";
4105
+ import { dirname as dirname11, join as join17 } from "path";
3909
4106
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
3910
4107
 
3911
4108
  // ../listener/dist/mcp/sanitize.js
@@ -5244,7 +5441,7 @@ async function readJson(req) {
5244
5441
  }
5245
5442
  }
5246
5443
  async function writeEndpointFile(path, endpoint, secret) {
5247
- await mkdir13(dirname10(path), { recursive: true });
5444
+ await mkdir13(dirname11(path), { recursive: true });
5248
5445
  await writeFile13(path, formatEndpointFile({ endpoint, secret }), {
5249
5446
  encoding: "utf-8",
5250
5447
  mode: 384
@@ -5258,7 +5455,7 @@ function extractBearer(header) {
5258
5455
  return m ? m[1] : null;
5259
5456
  }
5260
5457
  function defaultEndpointFile() {
5261
- return join16(getConfigDir(), "listener.endpoint");
5458
+ return join17(getConfigDir(), "listener.endpoint");
5262
5459
  }
5263
5460
 
5264
5461
  // ../listener/dist/mcp/bootstrap.js
@@ -5266,7 +5463,7 @@ async function startMcp(options) {
5266
5463
  const disabled = process.env.REPOWISE_MCP_DISABLED === "true";
5267
5464
  const graphsDir = options.graphsDir ?? defaultGraphsDir();
5268
5465
  const graphCache = createGraphCache({
5269
- resolveGraphPath: (repoId) => join17(graphsDir, `${repoId}.json`)
5466
+ resolveGraphPath: (repoId) => join18(graphsDir, `${repoId}.json`)
5270
5467
  });
5271
5468
  if (disabled) {
5272
5469
  return {
@@ -5289,11 +5486,11 @@ async function startMcp(options) {
5289
5486
  }
5290
5487
  const firstRepoLocal = options.repos.find((r) => r.localPath)?.localPath;
5291
5488
  const mcpHome = defaultMcpHome();
5292
- const logFilePath = join17(mcpHome, "mcp-log.jsonl.enc");
5293
- const keyStore = createFileKeyStore(join17(mcpHome, "mcp-log.key"));
5489
+ const logFilePath = join18(mcpHome, "mcp-log.jsonl.enc");
5490
+ const keyStore = createFileKeyStore(join18(mcpHome, "mcp-log.key"));
5294
5491
  const mcpLogger = createMcpLogger({ filePath: logFilePath, keyStore });
5295
- const flagFilePath = join17(mcpHome, "mcp-log.flag");
5296
- const watermarkFilePath = join17(mcpHome, "mcp-log.watermark");
5492
+ const flagFilePath = join18(mcpHome, "mcp-log.flag");
5493
+ const watermarkFilePath = join18(mcpHome, "mcp-log.watermark");
5297
5494
  let uploader = null;
5298
5495
  let lastConsentState = false;
5299
5496
  function ensureUploader() {
@@ -5337,7 +5534,7 @@ async function startMcp(options) {
5337
5534
  apiBaseUrl: repo.apiUrl,
5338
5535
  getAuthToken: options.getAuthToken,
5339
5536
  repoId: repo.repoId,
5340
- targetPath: join17(graphsDir, `${repo.repoId}.json`),
5537
+ targetPath: join18(graphsDir, `${repo.repoId}.json`),
5341
5538
  graphCache,
5342
5539
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
5343
5540
  }));
@@ -5413,7 +5610,7 @@ async function startMcp(options) {
5413
5610
  apiBaseUrl: repo.apiUrl,
5414
5611
  getAuthToken: options.getAuthToken,
5415
5612
  repoId: repo.repoId,
5416
- targetPath: join17(graphsDir, `${repo.repoId}.json`),
5613
+ targetPath: join18(graphsDir, `${repo.repoId}.json`),
5417
5614
  graphCache,
5418
5615
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
5419
5616
  }));
@@ -5434,12 +5631,389 @@ async function startMcp(options) {
5434
5631
  };
5435
5632
  }
5436
5633
  function defaultGraphsDir() {
5437
- return join17(getConfigDir(), "graphs");
5634
+ return join18(getConfigDir(), "graphs");
5438
5635
  }
5439
5636
  function defaultMcpHome() {
5440
5637
  return getConfigDir();
5441
5638
  }
5442
5639
 
5640
+ // ../listener/dist/mcp/auto-config/index.js
5641
+ import { homedir as homedir4 } from "os";
5642
+
5643
+ // ../listener/dist/mcp/auto-config/writers/claude-code.js
5644
+ import { promises as fs3 } from "fs";
5645
+ import { join as join19 } from "path";
5646
+
5647
+ // ../listener/dist/mcp/auto-config/markers.js
5648
+ import { promises as fs2 } from "fs";
5649
+ import { dirname as dirname12 } from "path";
5650
+ async function writeMergedConfig(params) {
5651
+ const current = await readConfig(params.path);
5652
+ const servers = { ...current.mcpServers ?? {} };
5653
+ servers[params.serverName] = params.spec;
5654
+ const next = { ...current, mcpServers: servers };
5655
+ const canonical = canonicalize(next);
5656
+ const existing = safeExistingContent(params.path, current);
5657
+ if (existing === canonical)
5658
+ return "unchanged";
5659
+ await fs2.mkdir(dirname12(params.path), { recursive: true });
5660
+ await fs2.writeFile(params.path, canonical, "utf-8");
5661
+ return "written";
5662
+ }
5663
+ async function removeFromConfig(path, serverName) {
5664
+ const current = await readConfig(path);
5665
+ if (!current.mcpServers || !(serverName in current.mcpServers))
5666
+ return;
5667
+ const servers = { ...current.mcpServers };
5668
+ delete servers[serverName];
5669
+ const next = { ...current, mcpServers: servers };
5670
+ if (Object.keys(servers).length === 0) {
5671
+ delete next.mcpServers;
5672
+ }
5673
+ await fs2.writeFile(path, canonicalize(next), "utf-8");
5674
+ }
5675
+ async function readConfig(path) {
5676
+ try {
5677
+ const raw = await fs2.readFile(path, "utf-8");
5678
+ return JSON.parse(raw);
5679
+ } catch (err) {
5680
+ if (err.code === "ENOENT")
5681
+ return {};
5682
+ throw err;
5683
+ }
5684
+ }
5685
+ function canonicalize(config2) {
5686
+ const serversSorted = {};
5687
+ if (config2.mcpServers) {
5688
+ const keys = Object.keys(config2.mcpServers).sort();
5689
+ for (const k of keys)
5690
+ serversSorted[k] = normalizeSpec(config2.mcpServers[k]);
5691
+ }
5692
+ const top = {};
5693
+ const otherKeys = Object.keys(config2).filter((k) => k !== "mcpServers").sort();
5694
+ for (const k of otherKeys)
5695
+ top[k] = config2[k];
5696
+ if (Object.keys(serversSorted).length > 0)
5697
+ top.mcpServers = serversSorted;
5698
+ return JSON.stringify(top, null, 2) + "\n";
5699
+ }
5700
+ function normalizeSpec(spec) {
5701
+ const out = { command: spec.command };
5702
+ if (spec.args && spec.args.length > 0)
5703
+ out.args = [...spec.args];
5704
+ if (spec.env && Object.keys(spec.env).length > 0) {
5705
+ const sorted = {};
5706
+ for (const k of Object.keys(spec.env).sort())
5707
+ sorted[k] = spec.env[k];
5708
+ out.env = sorted;
5709
+ }
5710
+ return out;
5711
+ }
5712
+ function safeExistingContent(path, current) {
5713
+ try {
5714
+ return canonicalize(current);
5715
+ } catch {
5716
+ return null;
5717
+ }
5718
+ void path;
5719
+ }
5720
+
5721
+ // ../listener/dist/mcp/auto-config/writers/claude-code.js
5722
+ var claudeCodeWriter = {
5723
+ tool: "claude-code",
5724
+ async detect(repoRoot, home) {
5725
+ return await fileExists2(join19(repoRoot, "CLAUDE.md")) || await hasClaudeBinary(home);
5726
+ },
5727
+ async write(ctx) {
5728
+ const path = join19(ctx.repoRoot, ".mcp.json");
5729
+ const status2 = await writeMergedConfig({
5730
+ path,
5731
+ serverName: `repowise-${ctx.repoId}`,
5732
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5733
+ });
5734
+ return { status: status2, path };
5735
+ },
5736
+ async remove(ctx) {
5737
+ await removeFromConfig(join19(ctx.repoRoot, ".mcp.json"), `repowise-${ctx.repoId}`);
5738
+ }
5739
+ };
5740
+ async function fileExists2(path) {
5741
+ try {
5742
+ await fs3.access(path);
5743
+ return true;
5744
+ } catch {
5745
+ return false;
5746
+ }
5747
+ }
5748
+ async function hasClaudeBinary(home) {
5749
+ return fileExists2(join19(home, ".claude", "claude.json"));
5750
+ }
5751
+
5752
+ // ../listener/dist/mcp/auto-config/writers/cline.js
5753
+ import { promises as fs4 } from "fs";
5754
+ import { join as join20 } from "path";
5755
+ var clineWriter = {
5756
+ tool: "cline",
5757
+ async detect(repoRoot, home) {
5758
+ return await fileExists3(join20(repoRoot, ".clinerules")) || await fileExists3(join20(home, ".cline"));
5759
+ },
5760
+ async write(ctx) {
5761
+ const path = join20(ctx.home, ".cline", "mcp.json");
5762
+ const status2 = await writeMergedConfig({
5763
+ path,
5764
+ serverName: `repowise-${ctx.repoId}`,
5765
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5766
+ });
5767
+ return { status: status2, path };
5768
+ },
5769
+ async remove(ctx) {
5770
+ await removeFromConfig(join20(ctx.home, ".cline", "mcp.json"), `repowise-${ctx.repoId}`);
5771
+ }
5772
+ };
5773
+ async function fileExists3(path) {
5774
+ try {
5775
+ await fs4.access(path);
5776
+ return true;
5777
+ } catch {
5778
+ return false;
5779
+ }
5780
+ }
5781
+
5782
+ // ../listener/dist/mcp/auto-config/writers/codex.js
5783
+ import { promises as fs5 } from "fs";
5784
+ import { join as join21 } from "path";
5785
+ var codexWriter = {
5786
+ tool: "codex",
5787
+ async detect(_repoRoot, home) {
5788
+ return fileExists4(join21(home, ".codex"));
5789
+ },
5790
+ async write(ctx) {
5791
+ const path = join21(ctx.home, ".codex", "mcp.json");
5792
+ const status2 = await writeMergedConfig({
5793
+ path,
5794
+ serverName: `repowise-${ctx.repoId}`,
5795
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5796
+ });
5797
+ return { status: status2, path };
5798
+ },
5799
+ async remove(ctx) {
5800
+ await removeFromConfig(join21(ctx.home, ".codex", "mcp.json"), `repowise-${ctx.repoId}`);
5801
+ }
5802
+ };
5803
+ async function fileExists4(path) {
5804
+ try {
5805
+ await fs5.access(path);
5806
+ return true;
5807
+ } catch {
5808
+ return false;
5809
+ }
5810
+ }
5811
+
5812
+ // ../listener/dist/mcp/auto-config/writers/copilot.js
5813
+ import { promises as fs6 } from "fs";
5814
+ import { join as join22 } from "path";
5815
+ var copilotWriter = {
5816
+ tool: "copilot",
5817
+ async detect(repoRoot) {
5818
+ return fileExists5(join22(repoRoot, ".vscode"));
5819
+ },
5820
+ async write(ctx) {
5821
+ const path = join22(ctx.repoRoot, ".vscode", "mcp.json");
5822
+ const status2 = await writeMergedConfig({
5823
+ path,
5824
+ serverName: `repowise-${ctx.repoId}`,
5825
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5826
+ });
5827
+ return { status: status2, path };
5828
+ },
5829
+ async remove(ctx) {
5830
+ await removeFromConfig(join22(ctx.repoRoot, ".vscode", "mcp.json"), `repowise-${ctx.repoId}`);
5831
+ }
5832
+ };
5833
+ async function fileExists5(path) {
5834
+ try {
5835
+ await fs6.access(path);
5836
+ return true;
5837
+ } catch {
5838
+ return false;
5839
+ }
5840
+ }
5841
+
5842
+ // ../listener/dist/mcp/auto-config/writers/cursor.js
5843
+ import { promises as fs7 } from "fs";
5844
+ import { join as join23 } from "path";
5845
+ var cursorWriter = {
5846
+ tool: "cursor",
5847
+ async detect(repoRoot) {
5848
+ return await fileExists6(join23(repoRoot, ".cursor")) || await fileExists6(join23(repoRoot, ".cursorrules"));
5849
+ },
5850
+ async write(ctx) {
5851
+ const path = join23(ctx.repoRoot, ".cursor", "mcp.json");
5852
+ const status2 = await writeMergedConfig({
5853
+ path,
5854
+ serverName: `repowise-${ctx.repoId}`,
5855
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5856
+ });
5857
+ return { status: status2, path };
5858
+ },
5859
+ async remove(ctx) {
5860
+ await removeFromConfig(join23(ctx.repoRoot, ".cursor", "mcp.json"), `repowise-${ctx.repoId}`);
5861
+ }
5862
+ };
5863
+ async function fileExists6(path) {
5864
+ try {
5865
+ await fs7.access(path);
5866
+ return true;
5867
+ } catch {
5868
+ return false;
5869
+ }
5870
+ }
5871
+
5872
+ // ../listener/dist/mcp/auto-config/writers/gemini-cli.js
5873
+ import { promises as fs8 } from "fs";
5874
+ import { join as join24 } from "path";
5875
+ var geminiCliWriter = {
5876
+ tool: "gemini-cli",
5877
+ async detect(_repoRoot, home) {
5878
+ return fileExists7(join24(home, ".gemini"));
5879
+ },
5880
+ async write(ctx) {
5881
+ const path = join24(ctx.home, ".gemini", "settings.json");
5882
+ const status2 = await writeMergedConfig({
5883
+ path,
5884
+ serverName: `repowise-${ctx.repoId}`,
5885
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5886
+ });
5887
+ return { status: status2, path };
5888
+ },
5889
+ async remove(ctx) {
5890
+ await removeFromConfig(join24(ctx.home, ".gemini", "settings.json"), `repowise-${ctx.repoId}`);
5891
+ }
5892
+ };
5893
+ async function fileExists7(path) {
5894
+ try {
5895
+ await fs8.access(path);
5896
+ return true;
5897
+ } catch {
5898
+ return false;
5899
+ }
5900
+ }
5901
+
5902
+ // ../listener/dist/mcp/auto-config/writers/roo.js
5903
+ import { promises as fs9 } from "fs";
5904
+ import { join as join25 } from "path";
5905
+ var rooWriter = {
5906
+ tool: "roo",
5907
+ async detect(repoRoot, home) {
5908
+ return await fileExists8(join25(repoRoot, ".roo")) || await fileExists8(join25(home, ".roo"));
5909
+ },
5910
+ async write(ctx) {
5911
+ const repoConfig = join25(ctx.repoRoot, ".roo", "mcp.json");
5912
+ const useRepoScope = await fileExists8(join25(ctx.repoRoot, ".roo"));
5913
+ const path = useRepoScope ? repoConfig : join25(ctx.home, ".roo", "mcp.json");
5914
+ const status2 = await writeMergedConfig({
5915
+ path,
5916
+ serverName: `repowise-${ctx.repoId}`,
5917
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5918
+ });
5919
+ return { status: status2, path };
5920
+ },
5921
+ async remove(ctx) {
5922
+ await removeFromConfig(join25(ctx.repoRoot, ".roo", "mcp.json"), `repowise-${ctx.repoId}`);
5923
+ await removeFromConfig(join25(ctx.home, ".roo", "mcp.json"), `repowise-${ctx.repoId}`);
5924
+ }
5925
+ };
5926
+ async function fileExists8(path) {
5927
+ try {
5928
+ await fs9.access(path);
5929
+ return true;
5930
+ } catch {
5931
+ return false;
5932
+ }
5933
+ }
5934
+
5935
+ // ../listener/dist/mcp/auto-config/writers/windsurf.js
5936
+ import { promises as fs10 } from "fs";
5937
+ import { join as join26 } from "path";
5938
+ var windsurfWriter = {
5939
+ tool: "windsurf",
5940
+ async detect(_repoRoot, home) {
5941
+ return fileExists9(join26(home, ".codeium", "windsurf"));
5942
+ },
5943
+ async write(ctx) {
5944
+ const path = join26(ctx.home, ".codeium", "windsurf", "mcp_config.json");
5945
+ const status2 = await writeMergedConfig({
5946
+ path,
5947
+ serverName: `repowise-${ctx.repoId}`,
5948
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5949
+ });
5950
+ return { status: status2, path };
5951
+ },
5952
+ async remove(ctx) {
5953
+ await removeFromConfig(join26(ctx.home, ".codeium", "windsurf", "mcp_config.json"), `repowise-${ctx.repoId}`);
5954
+ }
5955
+ };
5956
+ async function fileExists9(path) {
5957
+ try {
5958
+ await fs10.access(path);
5959
+ return true;
5960
+ } catch {
5961
+ return false;
5962
+ }
5963
+ }
5964
+
5965
+ // ../listener/dist/mcp/auto-config/writers/index.js
5966
+ var WRITERS = [
5967
+ claudeCodeWriter,
5968
+ clineWriter,
5969
+ codexWriter,
5970
+ copilotWriter,
5971
+ cursorWriter,
5972
+ geminiCliWriter,
5973
+ rooWriter,
5974
+ windsurfWriter
5975
+ ];
5976
+
5977
+ // ../listener/dist/mcp/auto-config/index.js
5978
+ async function runAutoConfig(opts) {
5979
+ const home = opts.home ?? homedir4();
5980
+ const writers = opts.writers ?? WRITERS;
5981
+ const results = [];
5982
+ for (const writer of writers) {
5983
+ let detected;
5984
+ try {
5985
+ detected = await writer.detect(opts.repoRoot, home);
5986
+ } catch (err) {
5987
+ results.push({
5988
+ tool: writer.tool,
5989
+ detected: false,
5990
+ error: err instanceof Error ? err.message : String(err)
5991
+ });
5992
+ continue;
5993
+ }
5994
+ if (!detected) {
5995
+ results.push({ tool: writer.tool, detected: false });
5996
+ continue;
5997
+ }
5998
+ try {
5999
+ const outcome = await writer.write({
6000
+ repoRoot: opts.repoRoot,
6001
+ repoId: opts.repoId,
6002
+ shimCmd: opts.shimCmd,
6003
+ home
6004
+ });
6005
+ results.push({ tool: writer.tool, detected: true, outcome });
6006
+ } catch (err) {
6007
+ results.push({
6008
+ tool: writer.tool,
6009
+ detected: true,
6010
+ error: err instanceof Error ? err.message : String(err)
6011
+ });
6012
+ }
6013
+ }
6014
+ return results;
6015
+ }
6016
+
5443
6017
  // ../listener/dist/typed-resolution/resolver-loop.js
5444
6018
  init_src();
5445
6019
  init_registry();
@@ -5644,7 +6218,7 @@ var CRASH_LOOP_WINDOW_MS = 3e4;
5644
6218
  var CRASH_LOOP_THRESHOLD = 3;
5645
6219
  async function readRawToolConfig() {
5646
6220
  try {
5647
- const configPath = join18(getConfigDir(), "config.json");
6221
+ const configPath = join27(getConfigDir(), "config.json");
5648
6222
  const data = await readFile12(configPath, "utf-8");
5649
6223
  const raw = JSON.parse(data);
5650
6224
  return {
@@ -5705,11 +6279,11 @@ function resolveAuditRoots() {
5705
6279
  return override.split(":").map((s) => s.trim()).filter(Boolean);
5706
6280
  }
5707
6281
  const out = /* @__PURE__ */ new Set();
5708
- let dir = dirname11(process.execPath);
6282
+ let dir = dirname13(process.execPath);
5709
6283
  for (let i = 0; i < 8; i += 1) {
5710
- out.add(join18(dir, "node_modules"));
5711
- out.add(join18(dir, "lib", "node_modules"));
5712
- const parent = dirname11(dir);
6284
+ out.add(join27(dir, "node_modules"));
6285
+ out.add(join27(dir, "lib", "node_modules"));
6286
+ const parent = dirname13(dir);
5713
6287
  if (parent === dir)
5714
6288
  break;
5715
6289
  dir = parent;
@@ -5928,7 +6502,7 @@ async function checkStaleContext(repos, state, groups) {
5928
6502
  if (group?.offline.isOffline)
5929
6503
  continue;
5930
6504
  const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
5931
- const contextPath = join18(repo.localPath, "repowise-context");
6505
+ const contextPath = join27(repo.localPath, "repowise-context");
5932
6506
  let isMissingOrEmpty = false;
5933
6507
  try {
5934
6508
  const s = statSync2(contextPath);
@@ -5957,9 +6531,36 @@ async function checkStaleContext(repos, state, groups) {
5957
6531
  }
5958
6532
  return dirty;
5959
6533
  }
6534
+ async function reconcileMcpConfigs(repos, packageName) {
6535
+ const shimCmd = packageName;
6536
+ for (const repo of repos) {
6537
+ if (!repo.localPath)
6538
+ continue;
6539
+ try {
6540
+ const s = await fsStat(repo.localPath);
6541
+ if (!s.isDirectory())
6542
+ continue;
6543
+ } catch {
6544
+ continue;
6545
+ }
6546
+ try {
6547
+ const results = await runAutoConfig({
6548
+ repoRoot: repo.localPath,
6549
+ repoId: repo.repoId,
6550
+ shimCmd
6551
+ });
6552
+ const written = results.filter((r) => r.detected && r.outcome?.status === "written");
6553
+ if (written.length > 0) {
6554
+ console.log(`[mcp-config] Wrote ${written.length.toString()} config(s) for ${repo.repoId}: ${written.map((r) => `${r.tool}=${r.outcome.path}`).join(", ")}`);
6555
+ }
6556
+ } catch (err) {
6557
+ console.warn(`[mcp-config] Reconcile failed for ${repo.repoId}:`, err instanceof Error ? err.message : String(err));
6558
+ }
6559
+ }
6560
+ }
5960
6561
  async function reconcileAgentInstructions(repos) {
5961
6562
  for (const repo of repos) {
5962
- const path = join18(repo.localPath, "repowise-context", "project-overview.md");
6563
+ const path = join27(repo.localPath, "repowise-context", "project-overview.md");
5963
6564
  let content;
5964
6565
  try {
5965
6566
  content = await readFile12(path, "utf-8");
@@ -6021,7 +6622,7 @@ async function startListener() {
6021
6622
  }
6022
6623
  const configDir = getConfigDir();
6023
6624
  await mkdir14(configDir, { recursive: true });
6024
- const lockPath = join18(configDir, "listener.lock");
6625
+ const lockPath = join27(configDir, "listener.lock");
6025
6626
  await writeFile14(lockPath, "", { flag: "a" });
6026
6627
  let lockIsHeld = false;
6027
6628
  try {
@@ -6064,7 +6665,7 @@ async function startListener() {
6064
6665
  return;
6065
6666
  }
6066
6667
  if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
6067
- console.error(`No repos configured. Add repos to ${join18(configDir, "config.json")}`);
6668
+ console.error(`No repos configured. Add repos to ${join27(configDir, "config.json")}`);
6068
6669
  await releaseLockAndExit();
6069
6670
  process.exitCode = 1;
6070
6671
  return;
@@ -6131,8 +6732,8 @@ async function startListener() {
6131
6732
  const packageName = true ? "repowisestage" : "repowise";
6132
6733
  let currentVersion = "";
6133
6734
  try {
6134
- const selfDir = dirname11(fileURLToPath3(import.meta.url));
6135
- const pkgJsonPath = join18(selfDir, "..", "..", "package.json");
6735
+ const selfDir = dirname13(fileURLToPath3(import.meta.url));
6736
+ const pkgJsonPath = join27(selfDir, "..", "..", "package.json");
6136
6737
  const pkgJson = JSON.parse(await readFile12(pkgJsonPath, "utf-8"));
6137
6738
  currentVersion = pkgJson.version;
6138
6739
  } catch (err) {
@@ -6185,6 +6786,29 @@ async function startListener() {
6185
6786
  } catch (err) {
6186
6787
  console.warn("[reconcile] Initial agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
6187
6788
  }
6789
+ void (async () => {
6790
+ try {
6791
+ await reconcileMcpConfigs(config2.repos, packageName);
6792
+ } catch (err) {
6793
+ console.warn("[mcp-config] Initial MCP config reconciliation failed:", err instanceof Error ? err.message : String(err));
6794
+ }
6795
+ })();
6796
+ void (async () => {
6797
+ try {
6798
+ const lspResults = await prepareLspServersForRepos(config2.repos);
6799
+ for (const r of lspResults) {
6800
+ if (r.installed) {
6801
+ console.log(`[lsp-install] Installed ${r.language} LSP server`);
6802
+ } else if (r.skippedNoNpmPackage && r.hint) {
6803
+ console.log(`[lsp-install] ${r.language} LSP not auto-installable. To enable: ${r.hint}`);
6804
+ } else if (r.error) {
6805
+ console.warn(`[lsp-install] ${r.language} install failed: ${r.error}`);
6806
+ }
6807
+ }
6808
+ } catch (err) {
6809
+ console.warn("[lsp-install] Pre-install scan failed:", err instanceof Error ? err.message : String(err));
6810
+ }
6811
+ })();
6188
6812
  const typedResolutionHooks = mcpRuntime?.lspWorkspaces ? buildTypedResolutionHooks({
6189
6813
  workspaces: mcpRuntime.lspWorkspaces,
6190
6814
  graphCache: mcpRuntime.graphCache,
@@ -6385,6 +7009,11 @@ async function startListener() {
6385
7009
  } catch (err) {
6386
7010
  console.warn("[reconcile] Agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
6387
7011
  }
7012
+ try {
7013
+ await reconcileMcpConfigs(config2.repos, packageName);
7014
+ } catch (err) {
7015
+ console.warn("[mcp-config] Reconciliation failed:", err instanceof Error ? err.message : String(err));
7016
+ }
6388
7017
  }
6389
7018
  if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
6390
7019
  if (latestCliVersion !== state.lastUpdateTargetVersion) {
@@ -6448,12 +7077,12 @@ async function startListener() {
6448
7077
  } catch {
6449
7078
  }
6450
7079
  }
6451
- const credentialsPath = join18(getConfigDir(), "credentials.json");
7080
+ const credentialsPath = join27(getConfigDir(), "credentials.json");
6452
7081
  let credentialsChanged = false;
6453
7082
  let watcher = null;
6454
7083
  try {
6455
- const fs8 = await import("fs");
6456
- watcher = fs8.watch(credentialsPath, () => {
7084
+ const fs18 = await import("fs");
7085
+ watcher = fs18.watch(credentialsPath, () => {
6457
7086
  credentialsChanged = true;
6458
7087
  });
6459
7088
  } catch {
@@ -6493,8 +7122,8 @@ if (isDirectRun) {
6493
7122
  }
6494
7123
 
6495
7124
  // src/lib/env.ts
6496
- import { homedir as homedir4 } from "os";
6497
- import { join as join19 } from "path";
7125
+ import { homedir as homedir5 } from "os";
7126
+ import { join as join28 } from "path";
6498
7127
  var IS_STAGING2 = true ? true : false;
6499
7128
  var PRODUCTION = {
6500
7129
  apiUrl: "https://api.repowise.ai",
@@ -6514,7 +7143,7 @@ function getEnvConfig() {
6514
7143
  return IS_STAGING2 ? STAGING : PRODUCTION;
6515
7144
  }
6516
7145
  function getConfigDir2() {
6517
- return join19(homedir4(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
7146
+ return join28(homedir5(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
6518
7147
  }
6519
7148
  function getPackageName() {
6520
7149
  return true ? "repowisestage" : "repowise";
@@ -6525,11 +7154,11 @@ import chalk from "chalk";
6525
7154
 
6526
7155
  // src/lib/config.ts
6527
7156
  import { readFile as readFile13, writeFile as writeFile15, mkdir as mkdir15, rename as rename4, unlink as unlink9 } from "fs/promises";
6528
- import { join as join20 } from "path";
7157
+ import { join as join29 } from "path";
6529
7158
  import lockfile4 from "proper-lockfile";
6530
7159
  async function getConfig() {
6531
7160
  try {
6532
- const data = await readFile13(join20(getConfigDir2(), "config.json"), "utf-8");
7161
+ const data = await readFile13(join29(getConfigDir2(), "config.json"), "utf-8");
6533
7162
  return JSON.parse(data);
6534
7163
  } catch {
6535
7164
  return {};
@@ -6537,7 +7166,7 @@ async function getConfig() {
6537
7166
  }
6538
7167
  async function saveConfig(config2) {
6539
7168
  const dir = getConfigDir2();
6540
- const path = join20(dir, "config.json");
7169
+ const path = join29(dir, "config.json");
6541
7170
  await mkdir15(dir, { recursive: true });
6542
7171
  const tmpPath = path + ".tmp";
6543
7172
  try {
@@ -6553,7 +7182,7 @@ async function saveConfig(config2) {
6553
7182
  }
6554
7183
  async function mergeAndSaveConfig(updates) {
6555
7184
  const dir = getConfigDir2();
6556
- const path = join20(dir, "config.json");
7185
+ const path = join29(dir, "config.json");
6557
7186
  await mkdir15(dir, { recursive: true });
6558
7187
  try {
6559
7188
  await writeFile15(path, "", { flag: "a" });
@@ -6624,7 +7253,7 @@ async function showWelcome(currentVersion) {
6624
7253
 
6625
7254
  // src/commands/create.ts
6626
7255
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
6627
- import { dirname as dirname12, join as join24 } from "path";
7256
+ import { dirname as dirname14, join as join33 } from "path";
6628
7257
  init_src();
6629
7258
  import chalk5 from "chalk";
6630
7259
  import ora from "ora";
@@ -6633,7 +7262,7 @@ import ora from "ora";
6633
7262
  import { createHash as createHash3, randomBytes as randomBytes3 } from "crypto";
6634
7263
  import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir16, chmod as chmod4, unlink as unlink10 } from "fs/promises";
6635
7264
  import http from "http";
6636
- import { join as join21 } from "path";
7265
+ import { join as join30 } from "path";
6637
7266
  var CLI_CALLBACK_PORT = 19876;
6638
7267
  var CALLBACK_TIMEOUT_MS = 12e4;
6639
7268
  function getCognitoConfigForStorage() {
@@ -6799,7 +7428,7 @@ async function refreshTokens2(refreshToken) {
6799
7428
  }
6800
7429
  async function getStoredCredentials2() {
6801
7430
  try {
6802
- const credPath = join21(getConfigDir2(), "credentials.json");
7431
+ const credPath = join30(getConfigDir2(), "credentials.json");
6803
7432
  const data = await readFile14(credPath, "utf-8");
6804
7433
  return JSON.parse(data);
6805
7434
  } catch (err) {
@@ -6811,14 +7440,14 @@ async function getStoredCredentials2() {
6811
7440
  }
6812
7441
  async function storeCredentials2(credentials) {
6813
7442
  const dir = getConfigDir2();
6814
- const credPath = join21(dir, "credentials.json");
7443
+ const credPath = join30(dir, "credentials.json");
6815
7444
  await mkdir16(dir, { recursive: true, mode: 448 });
6816
7445
  await writeFile16(credPath, JSON.stringify(credentials, null, 2));
6817
7446
  await chmod4(credPath, 384);
6818
7447
  }
6819
7448
  async function clearCredentials() {
6820
7449
  try {
6821
- await unlink10(join21(getConfigDir2(), "credentials.json"));
7450
+ await unlink10(join30(getConfigDir2(), "credentials.json"));
6822
7451
  } catch (err) {
6823
7452
  if (err.code !== "ENOENT") throw err;
6824
7453
  }
@@ -7025,10 +7654,10 @@ async function selectAiTools() {
7025
7654
 
7026
7655
  // src/lib/ai-tools.ts
7027
7656
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17 } from "fs/promises";
7028
- import { join as join22 } from "path";
7657
+ import { join as join31 } from "path";
7029
7658
  var REPOWISE_HOOK_MARKER = "repowise-context";
7030
7659
  async function writeClaudeSubagentHook(repoRoot, contextFolder) {
7031
- const settingsPath = join22(repoRoot, ".claude", "settings.json");
7660
+ const settingsPath = join31(repoRoot, ".claude", "settings.json");
7032
7661
  let settings = {};
7033
7662
  try {
7034
7663
  const raw = await readFile15(settingsPath, "utf-8");
@@ -7063,15 +7692,15 @@ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
7063
7692
  }
7064
7693
  hooks["SubagentStart"] = subagentStart;
7065
7694
  settings["hooks"] = hooks;
7066
- await mkdir17(join22(repoRoot, ".claude"), { recursive: true });
7695
+ await mkdir17(join31(repoRoot, ".claude"), { recursive: true });
7067
7696
  await writeFile17(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
7068
7697
  }
7069
7698
 
7070
7699
  // src/lib/gitignore.ts
7071
7700
  import { readFileSync as readFileSync2, writeFileSync, existsSync } from "fs";
7072
- import { join as join23 } from "path";
7701
+ import { join as join32 } from "path";
7073
7702
  function ensureGitignore(repoRoot, entry) {
7074
- const gitignorePath = join23(repoRoot, ".gitignore");
7703
+ const gitignorePath = join32(repoRoot, ".gitignore");
7075
7704
  if (existsSync(gitignorePath)) {
7076
7705
  const content = readFileSync2(gitignorePath, "utf-8");
7077
7706
  const lines = content.split("\n").map((l) => l.trim());
@@ -7861,7 +8490,7 @@ async function create() {
7861
8490
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
7862
8491
  const files = listResult.data?.files ?? listResult.files ?? [];
7863
8492
  if (files.length > 0) {
7864
- const contextDir = join24(repoRoot, DEFAULT_CONTEXT_FOLDER);
8493
+ const contextDir = join33(repoRoot, DEFAULT_CONTEXT_FOLDER);
7865
8494
  mkdirSync(contextDir, { recursive: true });
7866
8495
  let downloadedCount = 0;
7867
8496
  let failedCount = 0;
@@ -7875,8 +8504,8 @@ async function create() {
7875
8504
  const response = await fetch(presignedUrl);
7876
8505
  if (response.ok) {
7877
8506
  const content = await response.text();
7878
- const filePath = join24(contextDir, file.fileName);
7879
- mkdirSync(dirname12(filePath), { recursive: true });
8507
+ const filePath = join33(contextDir, file.fileName);
8508
+ mkdirSync(dirname14(filePath), { recursive: true });
7880
8509
  writeFileSync2(filePath, content, "utf-8");
7881
8510
  downloadedCount++;
7882
8511
  } else {
@@ -8017,7 +8646,7 @@ Files are stored on our servers (not in git). Retry when online.`
8017
8646
 
8018
8647
  // src/commands/member.ts
8019
8648
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
8020
- import { dirname as dirname13, join as join25, resolve, sep } from "path";
8649
+ import { dirname as dirname15, join as join34, resolve, sep } from "path";
8021
8650
  import chalk6 from "chalk";
8022
8651
  import ora2 from "ora";
8023
8652
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
@@ -8141,7 +8770,7 @@ async function member() {
8141
8770
  spinner.succeed(`Found ${chalk6.bold(files.length)} context files on server`);
8142
8771
  const { tools } = await selectAiTools();
8143
8772
  spinner.start("Downloading context files...");
8144
- const contextDir = join25(repoRoot, DEFAULT_CONTEXT_FOLDER2);
8773
+ const contextDir = join34(repoRoot, DEFAULT_CONTEXT_FOLDER2);
8145
8774
  mkdirSync2(contextDir, { recursive: true });
8146
8775
  let downloadedCount = 0;
8147
8776
  let failedCount = 0;
@@ -8162,7 +8791,7 @@ async function member() {
8162
8791
  const response = await fetch(presignedUrl);
8163
8792
  if (response.ok) {
8164
8793
  const content = await response.text();
8165
- mkdirSync2(dirname13(safePath), { recursive: true });
8794
+ mkdirSync2(dirname15(safePath), { recursive: true });
8166
8795
  writeFileSync3(safePath, content, "utf-8");
8167
8796
  downloadedCount++;
8168
8797
  } else {
@@ -8286,15 +8915,15 @@ import chalk7 from "chalk";
8286
8915
  import ora3 from "ora";
8287
8916
 
8288
8917
  // src/lib/tenant-graph-purge.ts
8289
- import { promises as fs } from "fs";
8290
- import { homedir as homedir5 } from "os";
8291
- import { join as join26 } from "path";
8292
- async function purgeForeignGraphs(validRepoIds, home = homedir5()) {
8293
- const graphsDir = join26(home, ".repowise", "graphs");
8918
+ import { promises as fs11 } from "fs";
8919
+ import { homedir as homedir6 } from "os";
8920
+ import { join as join35 } from "path";
8921
+ async function purgeForeignGraphs(validRepoIds, home = homedir6()) {
8922
+ const graphsDir = join35(home, ".repowise", "graphs");
8294
8923
  const result = { kept: [], removed: [] };
8295
8924
  let entries;
8296
8925
  try {
8297
- entries = await fs.readdir(graphsDir);
8926
+ entries = await fs11.readdir(graphsDir);
8298
8927
  } catch (err) {
8299
8928
  if (err.code === "ENOENT") return result;
8300
8929
  throw err;
@@ -8308,15 +8937,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir5()) {
8308
8937
  result.kept.push(entry);
8309
8938
  continue;
8310
8939
  }
8311
- const path = join26(graphsDir, entry);
8940
+ const path = join35(graphsDir, entry);
8312
8941
  try {
8313
- const stat7 = await fs.lstat(path);
8942
+ const stat7 = await fs11.lstat(path);
8314
8943
  if (stat7.isSymbolicLink()) {
8315
- await fs.unlink(path);
8944
+ await fs11.unlink(path);
8316
8945
  result.removed.push(entry);
8317
8946
  continue;
8318
8947
  }
8319
- await fs.rm(path, { recursive: true, force: true });
8948
+ await fs11.rm(path, { recursive: true, force: true });
8320
8949
  result.removed.push(entry);
8321
8950
  } catch {
8322
8951
  }
@@ -8401,11 +9030,11 @@ async function logout() {
8401
9030
 
8402
9031
  // src/commands/status.ts
8403
9032
  import { readFile as readFile16 } from "fs/promises";
8404
- import { basename as basename2, join as join27 } from "path";
9033
+ import { basename as basename2, join as join36 } from "path";
8405
9034
  async function status() {
8406
9035
  const configDir = getConfigDir2();
8407
- const STATE_PATH = join27(configDir, "listener-state.json");
8408
- const CONFIG_PATH = join27(configDir, "config.json");
9036
+ const STATE_PATH = join36(configDir, "listener-state.json");
9037
+ const CONFIG_PATH = join36(configDir, "config.json");
8409
9038
  let state = null;
8410
9039
  try {
8411
9040
  const data = await readFile16(STATE_PATH, "utf-8");
@@ -8453,7 +9082,7 @@ async function status() {
8453
9082
 
8454
9083
  // src/commands/sync.ts
8455
9084
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
8456
- import { dirname as dirname14, join as join28 } from "path";
9085
+ import { dirname as dirname16, join as join37 } from "path";
8457
9086
  import chalk9 from "chalk";
8458
9087
  import ora4 from "ora";
8459
9088
  var POLL_INTERVAL_MS2 = 3e3;
@@ -8602,7 +9231,7 @@ async function sync() {
8602
9231
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
8603
9232
  const files = listResult.data?.files ?? listResult.files ?? [];
8604
9233
  if (files.length > 0) {
8605
- const contextDir = join28(repoRoot, DEFAULT_CONTEXT_FOLDER3);
9234
+ const contextDir = join37(repoRoot, DEFAULT_CONTEXT_FOLDER3);
8606
9235
  mkdirSync3(contextDir, { recursive: true });
8607
9236
  let downloadedCount = 0;
8608
9237
  let failedCount = 0;
@@ -8616,8 +9245,8 @@ async function sync() {
8616
9245
  const response = await fetch(presignedUrl);
8617
9246
  if (response.ok) {
8618
9247
  const content = await response.text();
8619
- const filePath = join28(contextDir, file.fileName);
8620
- mkdirSync3(dirname14(filePath), { recursive: true });
9248
+ const filePath = join37(contextDir, file.fileName);
9249
+ mkdirSync3(dirname16(filePath), { recursive: true });
8621
9250
  writeFileSync4(filePath, content, "utf-8");
8622
9251
  downloadedCount++;
8623
9252
  } else {
@@ -8869,7 +9498,7 @@ async function config() {
8869
9498
  // src/commands/mcp-log.ts
8870
9499
  import { createDecipheriv as createDecipheriv2 } from "crypto";
8871
9500
  import { mkdir as mkdir18, readFile as readFile17, stat as stat6, writeFile as writeFile18 } from "fs/promises";
8872
- import { dirname as dirname15, join as join29 } from "path";
9501
+ import { dirname as dirname17, join as join38 } from "path";
8873
9502
  var FLAG_FILE = "mcp-log.flag";
8874
9503
  var LOG_FILE = "mcp-log.jsonl.enc";
8875
9504
  var KEY_FILE = "mcp-log.key";
@@ -8877,10 +9506,10 @@ var ENDPOINT_FILE = "listener.endpoint";
8877
9506
  var IV_BYTES2 = 12;
8878
9507
  var TAG_BYTES2 = 16;
8879
9508
  function flagPath() {
8880
- return join29(getConfigDir2(), FLAG_FILE);
9509
+ return join38(getConfigDir2(), FLAG_FILE);
8881
9510
  }
8882
9511
  function logPath() {
8883
- return join29(getConfigDir2(), LOG_FILE);
9512
+ return join38(getConfigDir2(), LOG_FILE);
8884
9513
  }
8885
9514
  async function readFlag() {
8886
9515
  try {
@@ -8896,7 +9525,7 @@ async function readFlag() {
8896
9525
  }
8897
9526
  async function writeFlag(flag) {
8898
9527
  const path = flagPath();
8899
- await mkdir18(dirname15(path), { recursive: true });
9528
+ await mkdir18(dirname17(path), { recursive: true });
8900
9529
  await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
8901
9530
  }
8902
9531
  async function showConsentPrompt() {
@@ -8967,14 +9596,14 @@ async function trySendConsentToServer() {
8967
9596
  let apiUrl = null;
8968
9597
  let token = null;
8969
9598
  try {
8970
- const body = await readFile17(join29(getConfigDir2(), "config.json"), "utf-8");
9599
+ const body = await readFile17(join38(getConfigDir2(), "config.json"), "utf-8");
8971
9600
  const parsed = JSON.parse(body);
8972
9601
  apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
8973
9602
  } catch {
8974
9603
  return false;
8975
9604
  }
8976
9605
  try {
8977
- const body = await readFile17(join29(getConfigDir2(), "credentials.json"), "utf-8");
9606
+ const body = await readFile17(join38(getConfigDir2(), "credentials.json"), "utf-8");
8978
9607
  const parsed = JSON.parse(body);
8979
9608
  token = parsed.idToken ?? null;
8980
9609
  } catch {
@@ -9027,7 +9656,7 @@ async function mcpLogStatus() {
9027
9656
  process.stderr.write("Log size: no file yet\n");
9028
9657
  }
9029
9658
  try {
9030
- const endpointBody = await readFile17(join29(getConfigDir2(), ENDPOINT_FILE), "utf-8");
9659
+ const endpointBody = await readFile17(join38(getConfigDir2(), ENDPOINT_FILE), "utf-8");
9031
9660
  const match = /endpoint=([^\n]+)/.exec(endpointBody);
9032
9661
  process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
9033
9662
  `);
@@ -9054,7 +9683,7 @@ Run \`repowise mcp-log on\` to grant consent and view them.
9054
9683
  const key = await readKey();
9055
9684
  if (!key) {
9056
9685
  process.stderr.write(
9057
- `No encryption key at ${join29(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
9686
+ `No encryption key at ${join38(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
9058
9687
  `
9059
9688
  );
9060
9689
  return;
@@ -9130,7 +9759,7 @@ Run \`repowise mcp-log on\` to grant consent and view them.
9130
9759
  }
9131
9760
  async function readKey() {
9132
9761
  try {
9133
- const body = await readFile17(join29(getConfigDir2(), KEY_FILE), "utf-8");
9762
+ const body = await readFile17(join38(getConfigDir2(), KEY_FILE), "utf-8");
9134
9763
  const parsed = Buffer.from(body.trim(), "base64");
9135
9764
  if (parsed.length !== 32) return null;
9136
9765
  return parsed;
@@ -9173,8 +9802,8 @@ async function mcpLog(subcommand, flags = {}) {
9173
9802
  import chalk11 from "chalk";
9174
9803
 
9175
9804
  // src/lib/graph-loader.ts
9176
- import { promises as fs2 } from "fs";
9177
- import { join as join30, resolve as resolve2 } from "path";
9805
+ import { promises as fs12 } from "fs";
9806
+ import { join as join39, resolve as resolve2 } from "path";
9178
9807
  import { gunzipSync } from "zlib";
9179
9808
  var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
9180
9809
  var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
@@ -9191,8 +9820,8 @@ var GraphNotFoundError = class extends Error {
9191
9820
  var cache = /* @__PURE__ */ new Map();
9192
9821
  async function loadGraph(repoRoot = process.cwd()) {
9193
9822
  const root = resolve2(repoRoot);
9194
- const gzPath = join30(root, GZIPPED_GRAPH_PATH);
9195
- const plainPath = join30(root, RELATIVE_GRAPH_PATH);
9823
+ const gzPath = join39(root, GZIPPED_GRAPH_PATH);
9824
+ const plainPath = join39(root, RELATIVE_GRAPH_PATH);
9196
9825
  const cached = cache.get(root);
9197
9826
  if (cached) {
9198
9827
  return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
@@ -9200,14 +9829,14 @@ async function loadGraph(repoRoot = process.cwd()) {
9200
9829
  let graphPath = null;
9201
9830
  let raw = null;
9202
9831
  try {
9203
- raw = await fs2.readFile(gzPath);
9832
+ raw = await fs12.readFile(gzPath);
9204
9833
  graphPath = gzPath;
9205
9834
  } catch (err) {
9206
9835
  if (err.code !== "ENOENT") throw err;
9207
9836
  }
9208
9837
  if (!raw) {
9209
9838
  try {
9210
- raw = await fs2.readFile(plainPath);
9839
+ raw = await fs12.readFile(plainPath);
9211
9840
  graphPath = plainPath;
9212
9841
  } catch (err) {
9213
9842
  if (err.code === "ENOENT") {
@@ -9606,14 +10235,14 @@ function registerQueryCommand(program2) {
9606
10235
  }
9607
10236
 
9608
10237
  // src/commands/uninstall.ts
9609
- import { promises as fs6 } from "fs";
9610
- import { homedir as homedir7 } from "os";
9611
- import { join as join34 } from "path";
10238
+ import { promises as fs16 } from "fs";
10239
+ import { homedir as homedir8 } from "os";
10240
+ import { join as join43 } from "path";
9612
10241
  import chalk12 from "chalk";
9613
10242
 
9614
10243
  // src/lib/cleanup/marker-blocks.ts
9615
- import { promises as fs3 } from "fs";
9616
- import { join as join31 } from "path";
10244
+ import { promises as fs13 } from "fs";
10245
+ import { join as join40 } from "path";
9617
10246
  var MARKER_START = "<!-- repowise-start -->";
9618
10247
  var MARKER_END = "<!-- repowise-end -->";
9619
10248
  var CONTEXT_FILES = [
@@ -9629,7 +10258,7 @@ var CONTEXT_FILES = [
9629
10258
  async function stripMarkerBlock(filePath) {
9630
10259
  let raw;
9631
10260
  try {
9632
- raw = await fs3.readFile(filePath, "utf-8");
10261
+ raw = await fs13.readFile(filePath, "utf-8");
9633
10262
  } catch (err) {
9634
10263
  if (err.code === "ENOENT")
9635
10264
  return { path: filePath, status: "missing" };
@@ -9644,16 +10273,16 @@ async function stripMarkerBlock(filePath) {
9644
10273
  const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
9645
10274
  const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
9646
10275
  if (stripped.length === 0) {
9647
- await fs3.unlink(filePath);
10276
+ await fs13.unlink(filePath);
9648
10277
  return { path: filePath, status: "deleted" };
9649
10278
  }
9650
- await fs3.writeFile(filePath, stripped + "\n", "utf-8");
10279
+ await fs13.writeFile(filePath, stripped + "\n", "utf-8");
9651
10280
  return { path: filePath, status: "stripped" };
9652
10281
  }
9653
10282
  async function stripAllMarkerBlocks(repoRoot) {
9654
10283
  const out = [];
9655
10284
  for (const relative of CONTEXT_FILES) {
9656
- const full = join31(repoRoot, relative);
10285
+ const full = join40(repoRoot, relative);
9657
10286
  const result = await stripMarkerBlock(full).catch((err) => ({
9658
10287
  path: full,
9659
10288
  status: "untouched",
@@ -9665,25 +10294,25 @@ async function stripAllMarkerBlocks(repoRoot) {
9665
10294
  }
9666
10295
 
9667
10296
  // src/lib/cleanup/mcp-configs.ts
9668
- import { promises as fs4 } from "fs";
9669
- import { join as join32 } from "path";
10297
+ import { promises as fs14 } from "fs";
10298
+ import { join as join41 } from "path";
9670
10299
  function mcpConfigPaths(repoRoot, home) {
9671
10300
  return [
9672
- join32(repoRoot, ".mcp.json"),
9673
- join32(repoRoot, ".cursor", "mcp.json"),
9674
- join32(repoRoot, ".vscode", "mcp.json"),
9675
- join32(repoRoot, ".roo", "mcp.json"),
9676
- join32(home, ".cline", "mcp.json"),
9677
- join32(home, ".codeium", "windsurf", "mcp_config.json"),
9678
- join32(home, ".gemini", "settings.json"),
9679
- join32(home, ".codex", "mcp.json"),
9680
- join32(home, ".roo", "mcp.json")
10301
+ join41(repoRoot, ".mcp.json"),
10302
+ join41(repoRoot, ".cursor", "mcp.json"),
10303
+ join41(repoRoot, ".vscode", "mcp.json"),
10304
+ join41(repoRoot, ".roo", "mcp.json"),
10305
+ join41(home, ".cline", "mcp.json"),
10306
+ join41(home, ".codeium", "windsurf", "mcp_config.json"),
10307
+ join41(home, ".gemini", "settings.json"),
10308
+ join41(home, ".codex", "mcp.json"),
10309
+ join41(home, ".roo", "mcp.json")
9681
10310
  ];
9682
10311
  }
9683
10312
  async function removeRepowiseFromConfig(path, serverName) {
9684
10313
  let raw;
9685
10314
  try {
9686
- raw = await fs4.readFile(path, "utf-8");
10315
+ raw = await fs14.readFile(path, "utf-8");
9687
10316
  } catch (err) {
9688
10317
  if (err.code === "ENOENT") return { path, status: "not-found" };
9689
10318
  return { path, status: "error", error: err.message };
@@ -9703,7 +10332,7 @@ async function removeRepowiseFromConfig(path, serverName) {
9703
10332
  } else {
9704
10333
  next.mcpServers = servers;
9705
10334
  }
9706
- await fs4.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
10335
+ await fs14.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
9707
10336
  return { path, status: "removed" };
9708
10337
  }
9709
10338
  async function removeAllMcpEntries(repoRoot, home, repoId) {
@@ -9716,17 +10345,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
9716
10345
  }
9717
10346
 
9718
10347
  // src/lib/cleanup/local-state.ts
9719
- import { promises as fs5 } from "fs";
9720
- import { homedir as homedir6 } from "os";
9721
- import { join as join33, resolve as resolve3 } from "path";
10348
+ import { promises as fs15 } from "fs";
10349
+ import { homedir as homedir7 } from "os";
10350
+ import { join as join42, resolve as resolve3 } from "path";
9722
10351
  async function clearLocalState(homeOverride) {
9723
- const home = homeOverride ?? homedir6();
9724
- const target = resolve3(join33(home, ".repowise"));
10352
+ const home = homeOverride ?? homedir7();
10353
+ const target = resolve3(join42(home, ".repowise"));
9725
10354
  if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
9726
10355
  return { path: target, status: "error", error: "refused: not under home" };
9727
10356
  }
9728
10357
  try {
9729
- await fs5.rm(target, { recursive: true, force: false });
10358
+ await fs15.rm(target, { recursive: true, force: false });
9730
10359
  return { path: target, status: "removed" };
9731
10360
  } catch (err) {
9732
10361
  if (err.code === "ENOENT")
@@ -9756,7 +10385,7 @@ async function stopAndUninstallService(uninstaller) {
9756
10385
  // src/commands/uninstall.ts
9757
10386
  async function uninstall2(opts = {}) {
9758
10387
  const tier = opts.tier ?? "uninstall";
9759
- const home = opts.home ?? homedir7();
10388
+ const home = opts.home ?? homedir8();
9760
10389
  const repoRoot = opts.repoRoot ?? process.cwd();
9761
10390
  const loadRepoIds = opts.loadRepoIds ?? defaultLoadRepoIds;
9762
10391
  const report = { tier, removed: [], preserved: [], skipped: [] };
@@ -9765,7 +10394,7 @@ async function uninstall2(opts = {}) {
9765
10394
  else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
9766
10395
  if (tier === "stop") return report;
9767
10396
  try {
9768
- await fs6.unlink(join34(home, ".repowise", "credentials.json"));
10397
+ await fs16.unlink(join43(home, ".repowise", "credentials.json"));
9769
10398
  report.removed.push("credentials");
9770
10399
  } catch (err) {
9771
10400
  if (err.code !== "ENOENT") {
@@ -9792,7 +10421,7 @@ async function uninstall2(opts = {}) {
9792
10421
  const allPaths = mcpConfigPaths(repoRoot, home);
9793
10422
  for (const p of allPaths) {
9794
10423
  try {
9795
- await fs6.access(p);
10424
+ await fs16.access(p);
9796
10425
  } catch {
9797
10426
  }
9798
10427
  }
@@ -9804,7 +10433,7 @@ async function uninstall2(opts = {}) {
9804
10433
  }
9805
10434
  async function defaultLoadRepoIds(home) {
9806
10435
  try {
9807
- const raw = await fs6.readFile(join34(home, ".repowise", "config.json"), "utf-8");
10436
+ const raw = await fs16.readFile(join43(home, ".repowise", "config.json"), "utf-8");
9808
10437
  const parsed = JSON.parse(raw);
9809
10438
  return (parsed.repos ?? []).map((r) => r.repoId);
9810
10439
  } catch {
@@ -9850,13 +10479,13 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
9850
10479
  }
9851
10480
 
9852
10481
  // src/commands/mcp-shim.ts
9853
- import { promises as fs7 } from "fs";
10482
+ import { promises as fs17 } from "fs";
9854
10483
  import { createInterface as createInterface2 } from "readline";
9855
- import { homedir as homedir8 } from "os";
9856
- import { join as join35 } from "path";
10484
+ import { homedir as homedir9 } from "os";
10485
+ import { join as join44 } from "path";
9857
10486
  var DEFAULT_MAX = 200 * 1024;
9858
10487
  async function mcpShim(opts) {
9859
- const endpointPath = opts.endpointFile ?? join35(homedir8(), ".repowise", "listener.endpoint");
10488
+ const endpointPath = opts.endpointFile ?? join44(homedir9(), ".repowise", "listener.endpoint");
9860
10489
  const stdin = opts.stdin ?? process.stdin;
9861
10490
  const stdout = opts.stdout ?? process.stdout;
9862
10491
  const stderr = opts.stderr ?? process.stderr;
@@ -9927,7 +10556,7 @@ async function mcpShim(opts) {
9927
10556
  }
9928
10557
  async function readEndpoint(path) {
9929
10558
  try {
9930
- const raw = (await fs7.readFile(path, "utf-8")).trim();
10559
+ const raw = (await fs17.readFile(path, "utf-8")).trim();
9931
10560
  if (!raw) return null;
9932
10561
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
9933
10562
  return { endpoint: raw.split("\n")[0].trim(), secret: null };
@@ -10141,14 +10770,14 @@ function writeError(stream, id, code, message) {
10141
10770
 
10142
10771
  // src/commands/lsp.ts
10143
10772
  init_registry();
10144
- import { spawn as spawn3 } from "child_process";
10773
+ import { spawn as spawn4 } from "child_process";
10145
10774
  import chalk13 from "chalk";
10146
10775
  async function isOnPath(command) {
10147
10776
  if (/[^\w./+-]/.test(command)) return false;
10148
10777
  const isWin = process.platform === "win32";
10149
10778
  const probeCmd = isWin ? "where" : "which";
10150
10779
  return new Promise((resolve4) => {
10151
- const child = spawn3(probeCmd, [command], { stdio: "ignore" });
10780
+ const child = spawn4(probeCmd, [command], { stdio: "ignore" });
10152
10781
  child.on("close", (code) => {
10153
10782
  resolve4(code === 0);
10154
10783
  });
@@ -10209,8 +10838,8 @@ async function lspDoctor() {
10209
10838
 
10210
10839
  // bin/repowise.ts
10211
10840
  var __filename = fileURLToPath4(import.meta.url);
10212
- var __dirname = dirname16(__filename);
10213
- var pkg = JSON.parse(readFileSync3(join36(__dirname, "..", "..", "package.json"), "utf-8"));
10841
+ var __dirname = dirname18(__filename);
10842
+ var pkg = JSON.parse(readFileSync3(join45(__dirname, "..", "..", "package.json"), "utf-8"));
10214
10843
  var program = new Command();
10215
10844
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
10216
10845
  await showWelcome(pkg.version);